django3 初級配置學習收集信息

       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;
    }
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章