Django,發音爲[`dʒæŋɡəʊ],是用python語言寫的開源web開發框架,並遵循MVC設計。勞倫斯出版集團爲了開發以新聞內容爲主的網站,而開發出來了這個框架,於2005年7月在BSD許可證下發布。這個名稱來源於比利時的爵士音樂家DjangoReinhardt,他是一個吉普賽人,主要以演奏吉它爲主,還演奏過小提琴等。由於Django在近年來的迅速發展,應用越來越廣泛,被著名IT開發雜誌SDTimes評選爲2013SDTimes100,位列"API、庫和框架"分類第6位,被認爲是該領域的佼佼者。
Django的主要目的是簡便、快速的開發數據庫驅動的網站。它強調代碼複用,多個組件可以很方便的以"插件"形式服務於整個框架,Django有許多功能強大的第三方插件,你甚至可以很方便的開發出自己的工具包。這使得Django具有很強的可擴展性。它還強調快速開發和DRY(DoNotRepeatYourself)原則。
安裝 Python3.6
yum install python36
安裝虛擬環境
pip3 install virtualenv pip3 install virtualenvwrapper
修改/root/.bashrc 設置虛擬環境,添加如下內容,注意目錄可以自定義設置,可執行文件根據自己安裝目錄填寫,默認如下:
export WORKON_HOME=$HOME/.virtualenvs export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3.6 source /usr/local/bin/virtualenvwrapper.sh
使用如下命令使配置文件生效。
source /root/.bashrc
使用如下命令創建虛擬環境,其中mycode是虛擬環境的名子
mkvirtualenv -p python3.6 mycode
提示如下:
[root@localhost]# mkvirtualenv -p python3.6 mycode created virtual environment in 399ms CPython3Posix(dest=/root/.virtualenvs/mycode, clear=False, global=False) with seeder FromAppData pip=latest setuptools=latest wheel=latest app_data_dir=/root/.local/share/virtualenv/seed-v1 via=copy virtualenvwrapper.user_scripts creating /root/.virtualenvs/mycode/bin/predeactivate virtualenvwrapper.user_scripts creating /root/.virtualenvs/mycode/bin/postdeactivate virtualenvwrapper.user_scripts creating /root/.virtualenvs/mycode/bin/preactivate virtualenvwrapper.user_scripts creating /root/.virtualenvs/mycode/bin/postactivate virtualenvwrapper.user_scripts creating /root/.virtualenvs/mycode/bin/get_env_details
如果創建的有問題,可以使用如下命令刪除創建的虛擬環境
rmvirtualenv mycode
使用如下進入虛擬環境
workon mycode
使用如下命令退出虛擬環境
deactivate
進入虛擬環境後 命令提示符如下:
(mycode) [root@localhost ~]#
然後再虛擬環境中查看已安裝的包,提示如下
(mycode) [root@localhost ~]# pip list Package Version ---------- ------- pip 20.0.2 setuptools 45.2.0 wheel 0.34.2
在虛擬環境下安裝django,這裏使用3.0.3版本
pip install Django==3.0.3
用如下命令查看Django是否安裝成功
pip freeze
使用如下命令安裝pymysql
pip install pymysql
安裝成功後用如下命令創建項目,其中new是項目名稱。
django-admin startproject new
項目創建在當前目錄,如果有改變目錄,可以進入該目錄後再執行創建命令,本次創建在home目錄。
進入創建後的目錄 /home/new
其中子目錄new與項目同名的目錄,此處爲也是new 如下文件:
manage.py是項目管理文件,通過它管理項目。
_init_.py是一個空文件,作用是這個目錄mycode可以被當作包使用。
settings.py是項目的整體配置文件。
urls.py是項目的url配置文件。
wsgi.py是項目與WSGI兼容的Web服務器入口。
退到manage.py文件所在的目錄創建應用,使用如下命令創建應用
python manage.py startapp app01
如果報錯SQLite版本過低請升級,安裝過程如下:
wget https://www.sqlite.org/2020/sqlite-autoconf-3310100.tar.gz
# 編譯
tar xvzf sqlite-autoconf-3310100.tar.gz cd sqlite-autoconf-3310100/ ./configure --prefix=/usr/local make && make install
# 替換系統低版本 sqlite3
mv /usr/bin/sqlite3 /usr/bin/sqlite3_old ln -s /usr/local/bin/sqlite3 /usr/bin/sqlite3 echo "/usr/local/lib" > /etc/ld.so.conf.d/sqlite3.conf ldconfig sqlite3 -version
項目創建完成後進入app01目錄,文件如下:
_init.py_是一個空文件,表示當前目錄可以當作一個python包使用。
tests.py文件用於開發測試用例。
models.py文件跟數據庫操作相關。
views.py文件跟接收瀏覽器請求,進行處理和返回頁面相關。
admin.py文件跟網站的後臺管理相關。
migrationsy用來裝遷移文件
應用創建完成後,設置路由、配置settings.py文件。
在settings.py文件配置數據庫,如下:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'mycode', 'USER': 'root', 'PASSWORD': '123456', 'HOST': 'localhost', 'PORT': '3306' } }
在項目new文件下的__init__.py文件裏面增加如下兩句
import pymysql pymysql.install_as_MySQLdb()
進入數據庫創建mycode數據庫
create database mycode charset=utf8;
生成遷移文件
python manage.py makemigrations
遷移文件
python manage.py migrate
如果提示
(mysql.W002) MySQL Strict Mode is not set for database connection 'default'
在settings.py文件數據庫配置部分,加入OPTIONS這部分內容
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'mycode', 'USER': 'root', 'PASSWORD': '123456', 'HOST': 'localhost', 'PORT': '3306' 'OPTIONS': { 'init_command': "SET sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO'", 'charset': 'utf8mb4', } } }
在settings.py文件配置語言和時區
LANGUAGE_CODE = 'zh-hans' TIME_ZONE = 'Asia/Shanghai' USE_I18N = True USE_L10N = True USE_TZ = True
在settings.py文件設置調試運行所有訪問.
ALLOWED_HOSTS = [‘*’]
在settings.py文件配置註冊應用
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app01', ]
設置管理後臺,使用如下命令創建管理員
python manage.py createsuperuser
然後輸入用戶名、郵箱、密碼即可。
之後使用如下命令運行服務器
python manage.py runserver
然後訪問:
http://127.0.0.1:8000/admin/
用剛纔創建的用戶名登錄,django完成安裝
創建模型:
BooleanField:布爾字段,值爲True或False。
NullBooleanField:支持Null、True、False三種值。
CharField(max_length=字符長度):字符串。類似mysql的varchar字段
參數max_length表示最大字符個數。
參數null = False 表示不能爲空
參數unique = True 表示值是唯一的。
參數blank = False 設置爲True時,字段可以爲空。設置爲False時,字段是必須填寫的。字符型字段CharField和TextField是用空字符串來存儲空值的。
extField:大文本字段,一般超過4000個字符時使用。
IntegerField:整數。
DecimalField(max_digits=None, decimal_places=None):十進制浮點數。
參數max_digits表示總位數。
參數decimal_places表示小數位數。
FloatField:浮點數。
DateField[auto_now=False, auto_now_add=False]):日期。
參數auto_now表示每次保存對象時,自動設置該字段爲當前時間,用於"最後一次修改"的時間戳,它總是使用當前日期,默認爲false。
參數auto_now_add表示當對象第一次被創建時自動設置當前時間,用於創建的時間戳,它總是使用當前日期,默認爲false。
參數auto_now_add和auto_now是相互排斥的,組合將會發生錯誤。
TimeField:時間,參數同DateField。
DateTimeField:日期時間,參數同DateField。
FileField:上傳文件字段。
ManyToManyField 多對多關聯
ForeignKey 一對多關聯
模型
在APP目錄的models.py文件裏面創建模型
創建之前線安裝一個django的複選框插件,如下命令
pip install django-multiselectfield
然後再models.py文件裏面引入。
from multiselectfield import MultiSelectField
如下例子:
from django.db import models from multiselectfield import MultiSelectField # Create your models here. #基礎信息類 class BaseInfo(models.Model): created_time = models.DateTimeField(verbose_name='創建時間',auto_now_add=True) updated_time = models.DateTimeField(verbose_name='更新時間',auto_now=True) is_delete = models.BooleanField(verbose_name='顯示控制',default=False) class Meta: abstract = True ''' 參數含義 class Meta 作爲抽象類繼承使用 verbose_name 字段名稱, auto_now_add 自動增加日期和時間 auto_now無論是你添加還是修改對象,時間爲你添加或者修改的時間。 auto_now_add爲添加時的時間,更新對象時不會有變動。 ''' #行程信息 class TripInfo(BaseInfo): name = models.CharField(verbose_name='行程描述',max_length=50,null=False) class Meta: verbose_name = '行程信息' verbose_name_plural = verbose_name def __str__(self): return self.name # 症狀信息 class SymptomInfo(BaseInfo): name = models.CharField(verbose_name='症狀描述',max_length=20,null=False,unique=True) class Meta: verbose_name = '症狀信息' verbose_name_plural = verbose_name def __str__(self): return self.name #人員信息類 class PersonInfo(BaseInfo): name = models.CharField(verbose_name='人員姓名',max_length=10,null=False) cid = models.CharField(verbose_name='身份證ID',max_length=18,null=False) age = models.IntegerField(verbose_name='年齡',null=False) sex_type = ((1,'男'),(0,'女'),(2,'保密')) sex = models.IntegerField(verbose_name='性別',choices=sex_type,null=False) address = models.CharField(verbose_name='現住址',max_length=50,null=False) temperature = models.FloatField(verbose_name=' 體溫',max_length=5,null=False) #symptom = models.ForeignKey(to=TripInfo,on_delete=models.CASCADE,verbose_name='症狀信息') symptom = models.ManyToManyField(to=SymptomInfo,verbose_name='症狀信息') #trip = models.ForeignKey(to=SymptomInfo, on_delete=models.CASCADE,verbose_name='行程信息') trip = models.ManyToManyField(to=TripInfo, verbose_name='行程信息') ''' class Meta 這裏表示在後臺管理裏面的標題顯示中文 ''' class Meta: verbose_name = '人員信息' verbose_name_plural = verbose_name def __str__(self): return self.name
創建完成之後生成遷移文件和遷移文件
python manage.py makemigrations python manage.py migrate
在後臺註冊管理用,再app01目錄下的admin.py文件註冊,如下
先導入模塊
from app01.models import PersonInfo,TripInfo,SymptomInfo admin.site.register(PersonInfo) admin.site.register(TripInfo) admin.site.register(SymptomInfo)
視圖
views.py文件寫入視圖函數 並導入模塊
from .models import SymptomInfo,TripInfo,PersonInfo
如下例子:
from django.shortcuts import render # Create your views here. from app01.models import SymptomInfo,TripInfo,PersonInfo from django.db.models import Avg from django.http import HttpResponse #人員查詢 def index(request): #查詢所有未刪除人員信息並以創建時間降序排列 person = PersonInfo.objects.filter(is_delete=False).order_by('-created_time').all() #查詢所有人員的平均溫度 avg_temp = PersonInfo.objects.aggregate(Avg('temperature')) #查詢所有人員的平均年齡 avg_age = PersonInfo.objects.aggregate(Avg('age')) return render(request, 'app01/index.html', locals()) #詳細頁面查詢 def show(request,id): #注意參數過多可以直接使用 def show(request,*args,**kwargs) details = PersonInfo.objects.filter(id=id).all() #可以加.[:10],只查詢前10個人員信息 if details: return render(request, 'app01/show.html', locals()) else: return HttpResponse('沒有查到數據') #查詢此症狀對應的所有人 def zhengzhuang(request,id): zzs = PersonInfo.objects.filter(symptom=id).order_by('-created_time').all() if zzs: return render(request, 'app01/zhengzhuang.html', locals()) else: return HttpResponse('沒有查到數據') #查詢此行程的所有人員 def xingcheng(request,id): xcs = PersonInfo.objects.filter(trip=id).order_by('-created_time').all() if xcs: return render(request, 'app01/xingcheng.html', locals()) else: return HttpResponse('沒有查詢到數據') # def creates(request): # tests = PersonInfo.objects.create(name = '老魏') #創建人員信息 # delete = PersonInfo.objects.filter(id=3).delete() #刪除人員信息
模板
注意模板文件在項目目錄templates文加下創建,
例如第一個應用 ,名稱是app01,目錄就是 templates/app01
然後如上視圖中的模板文件 xingcheng.html, zhengzhuang.html,index.html 都放在如上 templates/app01/目錄下。
模板如下例子,以index.html爲例子
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Home</title> <style> table {text-align: center;border:1px solid royalblue;} td {border:solid royalblue;} p { font-size: 20px;color: red;} </style> </head> <body> <h1>Django測試頁面</h1> <table> <tr> <td>姓名</td> <td>身份證ID</td> <td>現在住址</td> <td>年齡</td> <td>性別</td> <td>體溫</td> <td>症狀信息</td> <td>行程信息</td> <td>建立時間</td> <td>詳情</td> </tr> {% for p in person %} {#此處的person是在視圖文件views.py裏面的對象,name,cid都是這個對象的屬性。#} {% if not p.is_delete %} <tr> <td>{{ p.name }}</td> <td>{{ p.cid }}</td> <td>{{ p.address }}</td> <td>{{ p.age }}</td> <td>{{ p.get_sex_display }}</td> <td>{{ p.temperature }}</td> <td> {% for i in p.symptom.all %} {% if not forloop.last %} <a href="{% url 'app01:zhengzhuang' i.id %}">{{ i.name }}</a> {#注意這裏的{% url 'app01:zhengzhuang' i.id %}是反向解析的寫法,也可以寫成 href="/app01/zhengzhuang/{{i.id}}" #} {% else %} <a href="{% url 'app01:zhengzhuang' i.id %}">{{ i.name }}</a> {% endif %} {% endfor %} </td> <td> {% for i in p.trip.all %} {% if not forloop.last %} <a href="{% url 'app01:xingcheng' i.id %}">{{ i.name }}</a>, {% else %} <a href="{% url 'app01:xingcheng' i.id %}">{{ i.name }}</a> {% endif %} {% endfor %} </td> <td>{{ p.created_time }}</td> {#URL採用別名進行反向解析#} <td><a href="{% url 'app01:show' p.id %}">{{ p.id }}</a></td> </tr> {% endif %} {% endfor %} </table> <p>共有{{ person.count }}個人員信息.</p> <p>人員平均溫度:{{ avg_temp.temperature__avg | floatformat:2}}°</p> <p>人員平均年齡:{{ avg_age.age__avg | floatformat:2}}歲</p> </body> </html>
urls.py裏面導入視圖
from app01 import views
寫入路由
urlpatterns = [ path('admin/', admin.site.urls), path('', views.index) #新增路由,此處可以增加別名,寫成path('', views.index,name='index'),然後就可以模板的連接中寫反向解析 ]
上傳圖片
#安裝必要的包
pip install Pillow
配置 settings.py 放入如下內容
MEDIA_ROOT = os.path.join(BASE_DIR, 'media').replace("\\", "/")
MEDIA_URL = '/media/'
配置 settings.py文件 模板加入media
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')]
,
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'django.template.context_processors.media' #加入此行
],
},
},
]
在項目根目錄文件urls.py加入如下內容
from django.conf import settings #導入包
from django.conf.urls.static import static #導入包
urlpatterns = [
path('admin/', admin.site.urls),
path('app01/', include(('app01.urls', 'app01'), namespace='app01')),
path('app02/', include(('app02.urls', 'app02'), namespace='app02')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) #這裏是新加
上傳圖片的簡單模型如下,
from django.db import models from app02.storage import ImageStorage # Create your models here. #基礎類 class BaseInfo(models.Model): created_time = models.DateTimeField(verbose_name='創建時間',auto_now_add=True) updated_time = models.DateTimeField(verbose_name='更新時間',auto_now=True) is_delete = models.BooleanField(verbose_name='顯示控制',default=False) class Meta: abstract = True #用戶類 class UserUpload(BaseInfo): name =models.CharField(verbose_name='姓名',max_length=10,null=False) set_type = ((1,'男'),(0,'女'),(2,'保密')) set = models.IntegerField(verbose_name='性別',choices=set_type,null=False) image = models.ImageField(verbose_name='頭像',upload_to='app02/%Y/%m/%d',storage=ImageStorage()) #注意 ImageStorage是一個圖片更名的函數,因爲上面我們有定義media 因此upload_to='app02/%Y/%m/%d'的意思是上傳到哪裏,這裏是指上傳到media/app02/年份/月份/天,這個目錄 class Meta: verbose_name = '人員信息' verbose_name_plural = verbose_name def __str__(self): return self.name
圖片更名函數,可以放在應用的根目錄,和視圖模型文件同一個目錄,文件名例如 storage.py
內容如下:
rom django.core.files.storage import FileSystemStorage from django.http import HttpResponse class ImageStorage(FileSystemStorage): from django.conf import settings def __init__(self, location=settings.MEDIA_ROOT, base_url=settings.MEDIA_URL): # 初始化 super(ImageStorage, self).__init__(location, base_url) # 重寫 _save方法 def _save(self, name, content): # name爲上傳文件名稱 import os, time, random # 文件擴展名 ext = os.path.splitext(name)[1] # 文件目錄 d = os.path.dirname(name) # 定義文件名,年月日時分秒隨機數 fn = time.strftime('%Y%m%d%H%M%S') fn = fn + '_%d' % random.randint(0, 100) # 重寫合成文件名 name = os.path.join(d, fn + ext) # 調用父類方法 return super(ImageStorage, self)._save(name, content)
上傳圖片的簡單視圖如下:
from django.shortcuts import render from app02.models import UserUpload from django.http import HttpResponse from django.conf import settings from datetime import datetime import os,uuid from app02.models import UserUpload from django.shortcuts import redirect # Create your views here. def index(request): pics = UserUpload.objects.all() return render(request,'app02/index.html',locals()) # return HttpResponse('OK') def upload(request): if request.method == 'GET': return render(request,'app02/upload.html') else: name = request.POST.get('username') sex = request.POST.get('sex') pics = request.FILES.get('mypic') media_root = settings.MEDIA_ROOT pics_type = settings.UPLOAD_TYPE dates = datetime.now() path = 'app02/{}/{}/{}/' .format(dates.strftime('%Y'),dates.strftime('%m'),dates.strftime('%d')) if pics.name.split('.')[-1] in pics_type: full_path = media_root + '/' + path if not os.path.exists(full_path): os.makedirs(full_path) #更換圖片名稱 pics.name = str(uuid.uuid1()) + '.' + str(pics.name.split('.')[-1]) #注意這裏使用了UUID更改了上傳圖片名稱. #保存圖片 with open(full_path + pics.name,'wb') as pic: for c in pics.chunks(): #圖片切片 pic.write(c) # 寫入數據庫 UserUpload.objects.create(name=name,set=sex,image=path + pics.name) # 返回首頁 return redirect('app02:index') else: return HttpResponse('非法圖片') #注意這裏,如果圖片格式不對,則會返回這個提示,圖片格式在settings.py定義 UPLOAD_TYPE = ['JPG','jpg','jpeg','JPEG','PNG','png','gif','GIF']
上傳圖片的簡單模板如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>上傳圖片</title> </head> <body> <form action="" method="post" enctype="multipart/form-data"> {% csrf_token %} 姓名:<input type="text" name="username" maxlength="10"><br> 性別: 男 <input type="radio" name="sex" value="1"> 女 <input type="radio" name="sex" value="0"> 保密 <input type="radio" name="sex" value="2"><br> 頭像: <input type="file" name="mypic" ><br> <input type="submit" value="提交信息"> </form> </body> </html>
靜態配置:
settings.py文件的STATIC_URL = '/static/' 末尾配置如下內容
STATICFILES_DIRS = [ os.path.join(BASE_DIR),'static']
其中 STATIC_URL = '/static/' 用於僞裝圖片地址, static可隨意修改
然後在項目根目錄新建 static文件夾,這個文件夾下放置一些靜態文件,例如css、js、images
然後項目中的css、js、圖片文件可從此目錄引入
例如:
<script src="/static/js/aaa.js"></script>
<link rel="stylesheet" href="/static/css/head.css" type="text/css">
在模板文件裏面引入靜態反向解析
{% load static from staticfiles %} 或者 {% load staticfiles %}
引入後圖片地址可進行如下引用
<img src="{% static 'images/pic.jpng'%}" alt="">
其中CSS JS文件也可以這樣導入
<script src="{% static 'js/aaa.js' %}"></script>
<link rel='stylesheet' href="{% static 'css/head.css' %}">
注意: 如果項目文件settings.py文件裏面的DEBUG 設置爲 False 則靜態資源會失效,這個在項目部署後可以用NGINX解決。
模板語言
for循環
{% for i in abc %}
表達式
{% empyt %} 如果是空值輸出XX,用於循環內部
{% endfor %}
if語句
{% if a == b %}
表達式
{else}
表達式
{% endif %}
變量
{{變量名}}
常見方法
forloop 包括 first last counter0 counter1 等
常用過濾器
{{ abc | default:'哈哈'}} #如果有ABC有值,則返回ABC的值,如果沒有,則返回哈哈
{{ abc.time | date:'Y-m-d'}} 格式化日期和時間
{{ abc | length}} 計算字符串長度
{{ abc | truncatechars:2}} 截取字符
{{ abc | divisibleby:2}} 能被2整除 用於判斷
自定義過濾器
註釋{# #} 單行註釋
{% comment%} 多行註釋
{% endcomment%}
模板繼承:
相同內容用於繼承,一般用於網站的頭部和底部
父模板HTML
例如
titie標籤
<title>{% block title %}默認標題{% endblock%}</title>
中間內容
{% block content%}
內容部分
{% endblock%%}
css或者java
{% block style %}
<style></style>
{% endblock %}
子模板繼承父模板HTML
{% extends 'app01/base.html' %}
{% block title %}子標題{% endblock %}
{% block style %}<style></style>{% endblock %}
{% block comment %}
子內容
{% endblock %}
子類調用父類內容
{{block.super}}
轉義
瀏覽器默認轉義
如果要非轉義則使用過濾器
{{ content | safe }}
或者非轉義標籤
{% autoescape off %}
{{ content}}
{% endautoescape %}
反向解析
url反向
在urls.py 加上別名
其中根urls.py的如下
path('app02/', include(('app02.urls', 'app02'), namespace='app02')),
其中 namespace='app02' 這個就是根別名
APP的urls.py如下
path('show/', views.show,name='show')
其中 name='show' 是應用別名
之後重定向或者超鏈接可以如下寫
href = "{% url 'app02:show'%}"
反向的好處是應用目錄變更,解析仍然有效。
關鍵字帶參數
href = "{% url 'app02:show' id=1234 %}"
位置參數:
re_path(r'^app01/(\d+)/',views.index,name=index)
href = "{% url 'app02:show' 1234 %}"
分頁功能
安裝插件
pip install django-pure-pagination
settings.py文件裏面註冊應用
INSTALLED_APPS = (
'pure-pagination',
)
settings.py文件配置
PAGINATION_SETTINGS = {
'PAGE_RANGE_DISPLAYED': 1, #間距
'MARGIN_PAGES_DISPLAYED': 2, #間距
'SHOW_FIRST_PAGE_WHEN_INVALID': True, #無效頁碼返回第一頁
}
編寫視圖
from pure-pagination import PageNotAnIntege,Paginator
def index(request):
try:
page = request.GET.get('page', 1)
except PageNotAnInteger:
page = 1
arts = Article.objects.all()
p = Paginator(objects_list = arts, per_page=1, request=request)
articles = p.page(page)
return render(request, 'index.html', locals())
分頁模板
<ul>
{% for art in articles.object_list %}
<li>{{ art.title }}</li>
{% endfor %}
</ul>
{% include '_pagination.html' %}
分頁模板源文件
{% load i18n %}
<div class="pagination">
{% if articles.has_previous %}
<a href="?{{ articles.previous_page_number.querystring }}"
class="prev">上一頁</a>
{% else %}
<span class="disabled prev">上一頁 </span>
{% endif %}
{% for page in articles.pages %}
{% if page %}
{% ifequal page articles.number %}
<span class="current page">{{ page }}</span>
{% else %}
<a href="?{{ page.querystring }}" class="page">{{ page }}</a>
{% endifequal %}
{% else %}
...
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<a href="?{{ articles.next_page_number.querystring }}" class="next">下一頁</a>
{% else %}
<span class="disabled next">下一頁</span>
{% endif %}
</div>
文本框插件
DjangoUeditor
郵件發送
settings.py文件加入如下配置
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.163.com'
EMAIL_PORT = 25
# 發送郵件的郵箱
EMAIL_HOST_USER = '[email protected]'
# 在郵箱中設置的客戶端授權密碼
EMAIL_HOST_PASSWORD = 'abc1234567'
# 設置是否啓用安全鏈接
EMAIL_USER_TLS = True
視圖導入郵件相關模塊
from django.conf import settings
from django.core.mail import send_mail, send_mass_mail, EmailMultiAlternatives
from django.http import HttpResponse
def send(request):
res = send_mail('元旦放假已通知',
'元旦放假一天',
'[email protected]',
['[email protected]'],
fail_silently=False)
# 值1:郵件標題
# 值2:郵件內容
# 值3:發件人
# 值4:收件人
# 值5:如果失敗,是否拋出錯誤
if res == 1:
return HttpResponse('郵件發送成功')
else:
return HttpResponse('郵件發送失敗')
def send(request):
message1 = ('元旦放假已通知',
'元旦放假一天',
'[email protected]',
['[email protected]', '[email protected]'])
message2 = ('元旦放假已通知?',
'元旦放假一天',
'[email protected]',
['[email protected]', '[email protected]'])
res = send_mass_mail((message1, message2))
if res == 2:
return HttpResponse('多封郵件發送成功')
else:
return HttpResponse('多封郵件發送失敗')
form表單
應用目錄新建一個forms.py文件,
from django import forms from django.core.exceptions import ValidationError import re
一個簡單的form 表單模型、視圖、模板如下:
from django import forms from django.core.exceptions import ValidationError from captcha.fields import CaptchaField from app03.models import UserRegister from django.contrib.auth import authenticate import re #手機號碼驗證函數 def check_phone(phone): phone_nums = re.match(r'^1[3-9]\d{9}$',phone) if not phone_nums: raise ValidationError('手機號碼格式不正確,請重新輸入') #驗證用戶名 def check_username(username): username = re.match(r'^[a-zA-Z]+\d*$',username,re.I) if not username: raise ValidationError('用戶名不能以數字開頭,請重新輸入') #驗證郵箱 def check_email(email): mails = re.match('^[0-9a-zA-Z]+@[0-9a-zA-Z]+\.[a-zA-Z]{2,4}',email,re.I) if not mails: raise ValidationError('郵箱地址格式不正確,請重新輸入') #驗證密碼複雜度: def check_password(password): pwd1 = re.search('[a-zA-Z]+',password) pwd2 = re.search('[0-9]+',password) if not pwd1 or not pwd2: raise ValidationError('密碼必須是數字和字母的結合') #註冊表單類 class RegisterForm(forms.Form): username = forms.CharField(label='用戶名',required=True,min_length=6,max_length=16, error_messages={'required':'用戶名必須填寫','min_length':'用戶名最短6位','max_length':'用戶名最長16位'}, validators=[check_username,],widget=forms.TextInput({'placeholder':'請輸入用戶名'})) phone = forms.CharField(label='手機號碼',required=True,error_messages={'required':'手機號碼必須填寫'}, validators=[check_phone,],widget=forms.TextInput({'placeholder':'請輸入手機號碼'})) email = forms.EmailField(label='郵箱',required=True,error_messages={'required':'郵箱必須填寫'}, widget=forms.TextInput({'placeholder':'請輸入郵箱地址'})) last_name = forms.CharField(label='真實姓名',required=True,max_length=8, error_messages={'required':'真實姓名必須填寫','max_length':'真實姓名不超過8個字符'}, widget=forms.TextInput({'placeholder':'請輸入真實姓名'})) password = forms.CharField(label='密碼',min_length=8,max_length=16,required=True,validators=[check_password,], error_messages={'required':'密碼必須填寫','min_length':'密碼最短6位','max_length':'密碼最長16位'}, widget=forms.PasswordInput(attrs={'placeholder':'請輸入密碼'}),) re_password = forms.CharField(label='密碼',min_length=8,max_length=16,required=True,validators=[check_password,], error_messages={'required':'密碼必須填寫','min_length':'密碼最短6位','max_length':'密碼最長16位'}, widget=forms.PasswordInput(attrs={'placeholder':'請再次確認密碼'}),) code = CaptchaField(label='驗證碼',required=True,error_messages={'required':'請填寫驗證碼','invalid':'驗證碼錯誤'},) #驗證用戶名是否重複 def clean_username(self): username = self.cleaned_data.get('username') is_user = UserRegister.objects.filter(username=username).count() if is_user: raise ValidationError('用戶名已存在,請重新選擇一個') return username #驗證手機號碼是否重複 def clean_phone(self): phone = self.cleaned_data.get('phone') is_phone = UserRegister.objects.filter(phone=phone).count() if is_phone: raise ValidationError('手機號已存在,請重新填寫') return phone #驗證兩次輸入的密碼是否一致 def clean(self): clean_data = self.cleaned_data pwd1 = clean_data.get('password') pwd2 = clean_data.get('re_password') if pwd1 != pwd2: raise ValidationError('兩次輸入的密碼不一致') return clean_data
表單視圖如下:
class RegisterView(View): def get(self, request, *args,**kwargs): reg = RegisterForm() return render(request, 'app03/register.html', locals()) def post(self,request,*args,**kwargs): reg = RegisterForm(request.POST) if reg.is_valid(): ##將數據寫入數據庫 phone = reg.cleaned_data.get('phone') last_name = reg.cleaned_data.get('last_name') username = reg.cleaned_data.get('username') emails = reg.cleaned_data.get('email') password = reg.cleaned_data.get('password') UserRegister.objects.create_user( username=username, phone=phone, email=emails, password=password, last_name = last_name, ) messages.success(request,'註冊成功') return redirect(reverse('app03:index')) else: return render(request, 'app03/register.html', locals())
表單模板如下:
<form method="post" action="{% url 'app03:register' %}"> {% csrf_token %} <div class="register_con password_con"> <div class="text_box"> <div> <div class="inputs"><i><img src="{% static '/app03/images/icon01.png' %}"></i>{{ reg.username }} <span>* {% for err in reg.errors.username %} {{ err}}</span> {% endfor %} </div> <div class="inputs"><i><img src="{% static '/app03/images/icon04.png' %}"></i>{{ reg.email }} <span>*</span> {% for err in reg.errors.email %} <span>{{ err}}</span> {% endfor %} </div> <div class="inputs"><i><img src="{% static '/app03/images/icon04.png' %}"></i>{{ reg.last_name }} <span>*</span> {% for err in reg.errors.last_name %} <span>{{ err}}</span> {% endfor %} </div> <div class="inputs"><i><img src="{% static '/app03/images/icon04.png' %}"></i>{{ reg.phone }} <span>*</span> {% for err in reg.errors.phone %} <span>{{ err}}</span> {% endfor %} </div> <div class="inputs"><i><img src="{% static '/app03/images/icon02.png' %}"></i>{{ reg.password }} <span>*</span> {% for err in reg.errors.pasword %} <span>{{ err}}</span> {% endfor %} </div> <div class="inputs"><i><img src="{% static '/app03/images/icon02.png' %}"></i>{{ reg.re_password }} <span>*</span> {% for err in reg.errors.re_password %} <span>{{ err}}</span> {% endfor %} {% for errs in reg.non_field_errors %} <span>{{ errs }}</span> {% endfor %} </div> <div class="yzm inputs" ><i><img src="{% static '/app03/images/icon03.png' %}"></i>{{ reg.code }} <span>*</span> {% for err in reg.errors.code %} <span>{{ err}}</span> {% endfor %} </div> <button>註冊賬號</button> </div> </div> </div> </form>
驗證碼:
pip install django-simple-captcha
註冊應用
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app01' 'app02', 'captcha', ]
部署
uwsgi + nginx
安裝nginx和uwsgi
pip install uwsgi yum install nginx,python3-devel
修改settings.py文件的DEBUG爲False
注意項目目錄是news, news目錄下是app
uwsgi.ini 文件配置如下
[uwsgi] socket = /home/news/news.sock chdir = /home/news wsgi-file = news/uwsgi.ini touch-reload = /home/news/reload module = news.wsgi master = true buffer-size = 65536 processes = 8 threads = 4 vacuum = true chown-socket = nginx pidfile = uwsgi.pid daemonize = uwsgi.log
啓動 uwsgi --ini uwsgi.ini
nginx配置文件如下:
server { listen 9988; server_name 0.0.0.0; charset utf-8; client_max_body_size 75M; location /media { #上傳目錄 alias /home/news/media; } location /static { #配置靜態目錄連接 alias /home/news/static; #實際靜態目錄地址 } location / { uwsgi_pass unix://home/news/news.sock; include /etc/nginx/uwsgi_params; } }