一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

【Django】 初步學(xué)習(xí)

 goodwangLib 2020-03-01

這個(gè)系列(或者成不了一個(gè)系列。。)預(yù)計(jì)會(huì)全程參考Vamei様?shù)腄jango系列,膜一發(fā)。說句題外話,其實(shí)更加崇拜像Vamei那樣的能夠玩轉(zhuǎn)生活、各個(gè)領(lǐng)域都能取得不小成就的人。

【Django】

■  概述

  Django久聞大名,是Python中最為有名的Web框架之一了。相比于其他框架,D的特點(diǎn)就是提供了各種各樣的組件,重量級(jí),可以解決很多很多問題。讓W(xué)eb編程一簡再簡。之前一直都學(xué)習(xí)使用Flask,不否認(rèn)Flask有其有點(diǎn),但是一個(gè)很大的不方便的地方在于,F(xiàn)lask的擴(kuò)展沒有統(tǒng)一的標(biāo)準(zhǔn)而且開放,所有人都可以寫自己的Flask擴(kuò)展。雖然說是具有開源精神,但是一些比較常見的功能出現(xiàn)多種實(shí)現(xiàn)還是會(huì)讓人有些困擾。下面簡單說說Django的使用

  安裝Django依然使用pip:pip install Django,總的包大小大概6.8M。

  下載完成后可以在Python shell中運(yùn)行以下命令:

>>>import django
>>>print django.VERSION
(1, 11, 6, u'final', 0)

  說明安裝成功。

  ●  構(gòu)建一個(gè)Django項(xiàng)目目錄框架的快捷方法

  讓我第一次感受到Django的重型和周到是相比較于Flask構(gòu)建項(xiàng)目時(shí)要自己一個(gè)個(gè)文件建立,Django可以一鍵幫助生成一個(gè)較為完整的項(xiàng)目框架等待你填充內(nèi)容。在pip安裝完成之后,如果是windows環(huán)境則在$PYTHON_HOME的scripts,如果是Linux環(huán)境則是在/usr/bin這些目錄下,里面會(huì)有一個(gè)django-admin[.exe]可執(zhí)行程序。運(yùn)行這個(gè)程序,后接上參數(shù)startproject <項(xiàng)目名>可以在當(dāng)前工作目錄下生成Django項(xiàng)目的目錄框架。得到的框架是這樣的:

  這些也不全是空文件,像manage.py,settings.py等文件都是帶有默認(rèn)內(nèi)容的。

  考慮到一般開發(fā)肯定是在windows上用IDE比如Pycharm,Pycharm也可以一鍵生成Django項(xiàng)目框架,而且比django-admin生成的多一個(gè)templates文件夾用來盛放模板文件。

  構(gòu)建完成框架之后可以python manage.py runserver 8000來運(yùn)行起這個(gè)server,內(nèi)容由Django內(nèi)置好??吹降慕缑媸穷愃朴谶@樣的:

 

  ●  第一次為請(qǐng)求返回HTTP內(nèi)容

  Django框架采用MVC架構(gòu),F(xiàn)lask框架中對(duì)于路由的響應(yīng)通過裝飾器來綁定響應(yīng)函數(shù)完成。而Django的路由設(shè)置統(tǒng)一放在urls.py這個(gè)文件中。下面將修改一下urls.py(因?yàn)橹按嬖谝恍﹥?nèi)容了)

from django.conf.urls import url
from django.contrib import admin

#####下面這行是新加的#####
from DjangoTest.views import first_page

urlpatterns = [
    url(r'^admin/', admin.site.urls),

    #####下面這行是新加的#####
    url(r'^$', first_page)
]

  先來解釋一下urlpatterns這個(gè)列表,維護(hù)了整個(gè)項(xiàng)目的url和響應(yīng)函數(shù)的對(duì)應(yīng)關(guān)系。這里比較NB的一點(diǎn)在于支持的是正則表達(dá)式,也就是說可以為一批URL綁定相同的響應(yīng)函數(shù)。這一個(gè)和Flask還是比較不同的。Flask如果需要正則路由匹配的支持,則需要自己到werkzeug.routing中自己實(shí)現(xiàn)一個(gè)支持正則的Convertor對(duì)象。

  默認(rèn)的自帶了Django服務(wù)器后面的URI如果是/admin/的話,那么路由到Django-Admin界面,而下面我們添加的那條,則是說明了當(dāng)請(qǐng)求URL為空(即訪問的URI是/時(shí)),則路由到first_page這個(gè)函數(shù)中去。那么first_page在哪里定義呢,看上面的import語句,是DjangoTest目錄下的views文件。這個(gè)文件是我們自己建的并且要往里面寫內(nèi)容的。比如下面這樣:

from django.http import HttpResponse

def first_page(request):
    return HttpResponse('<h1>Hello World</h1>')

 

  ●  進(jìn)行模塊化管理

  一個(gè)網(wǎng)站可能有很多功能,因此肯定需要進(jìn)行模塊化的代碼管理。這一點(diǎn)在Flask中可以用類似于blueprint的結(jié)構(gòu)來實(shí)現(xiàn)。而在Django中這個(gè)被稱為app(默默吐槽,比Flask剛好高了一級(jí))

  運(yùn)行一個(gè)項(xiàng)目中的manage.py比如python manage.py startapp new_app就可以在當(dāng)前項(xiàng)目中增加一個(gè)名為new_app的目錄,下面也有admin.py,__init__.py,models.py,tests.py和views.py等文件。

  光添加一個(gè)新的目錄并沒有用,還需要將這個(gè)目錄所代表的APP和當(dāng)前項(xiàng)目關(guān)聯(lián)起來。關(guān)聯(lián)的方法就是修改DjangoTest下的settings.py文件。這個(gè)文件中有一個(gè)INSTALLED_APPS列表,在其中添加'new_app'即可。另外可以看到這個(gè)INSTALLED_APP里面已經(jīng)有一些內(nèi)容存在了,這些內(nèi)容代表了Django內(nèi)置的一些功能比如用戶驗(yàn)證,會(huì)話管理,顯示靜態(tài)文件等等。Django識(shí)別APP是從項(xiàng)目的根目錄開始的,所以不用像已有的那些寫得比較復(fù)雜比如django.contrib.admin,而直接寫new_app即可。

  為了訪問到一個(gè)單獨(dú)APP中的頁面,我們首先在項(xiàng)目總的urls.py中添加new_app的urls的相關(guān)信息(這樣做有利于不同模塊的url映射的各自維護(hù),模塊間解耦)。把DjangoTest下的urls.py修改:

from django.conf.urls import url,include
from django.contrib import admin
from DjangoTest.views import first_page

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^$', first_page)
    #####下面這行新增#####
    url(r'^new/', include('new_app.urls'))
]

 

  看到這里其實(shí)已經(jīng)可以大概看出來Django中如何進(jìn)行url的配置了。往urlpatterns里面可以增加url對(duì)象。url對(duì)象構(gòu)建時(shí)第一個(gè)參數(shù)是正則匹配路徑,第二個(gè)參數(shù)可以是一個(gè)callable的對(duì)象,此時(shí)需要在之前import進(jìn)去;也可以是include方法的返回,include方法的參數(shù)是一個(gè)字符串,字符串中以endpoint的形式指向另一個(gè)urls文件,此時(shí)那個(gè)urls文件中規(guī)定的正則匹配路徑在整個(gè)項(xiàng)目中應(yīng)該加上調(diào)用其include方法前面的路徑整個(gè)拿來匹配。

  上面把new_app.urls文件中定義的url映射都include到了根目錄下,然而在new_app下目前還沒有urls.py文件,所以在這個(gè)目錄下新建urls.py。文件中的內(nèi)容參考下面這樣子:

from django.conf.urls import url

from .views import new_first_page

urlpatterns = [
  url('^$', new_first_page),
]

 

  這么處理之后訪問/new/就會(huì)映射到new_first_page這個(gè)函數(shù)下了。

 

■  數(shù)據(jù)庫和ORM初步

  一個(gè)WEB應(yīng)用的根基在于數(shù)據(jù)庫中的數(shù)據(jù),一個(gè)好的web框架必須有很好的和數(shù)據(jù)庫交互的手段。之前在Flask的時(shí)候,采用了SQLAlchemy的第三方模塊的方法,將flask和數(shù)據(jù)庫的交互做得比較友好。到了Django的場合,Django有一套自己的ORM機(jī)制,看起來很像SQLAlchemy(事實(shí)上好像就是改造了SQLAlchemy),貼合度更好。

  要進(jìn)行數(shù)據(jù)庫交互,首先得有數(shù)據(jù)庫。比如我先到虛擬機(jī)的mysql中創(chuàng)建一個(gè)Django項(xiàng)目用的數(shù)據(jù)庫,并且指定(或者創(chuàng)建)一個(gè)用戶來管理這個(gè)庫:

$mysql -u root -p
password:
mysql>CREATE DATABASE Django_Test DEFAULT CHARSET utf8;

mysql>GRANT ALL PRIVILEGES ON Django_Test.* TO weiyz@'%';
/*將新建的數(shù)據(jù)庫的操作權(quán)限賦給管理用戶*/
mysql>FLUSH PRIVILEGES;

 

  然后在Django項(xiàng)目的settings.py中的數(shù)據(jù)庫相關(guān)配置更改:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'Django_Test',
        'USER' : 'weiyz',
        'PASSWORD' : '123456',
        'HOST' : '192.168.191.112',
        'PORT' : '3306',
    }
}

 

   這樣就關(guān)聯(lián)了數(shù)據(jù)庫和Django項(xiàng)目。

  web和數(shù)據(jù)庫的交互形式是一個(gè)很重要的問題。如果我們使用MySQLdb這類包裝的比較低級(jí)的模塊來做的話,每一個(gè)數(shù)據(jù)庫操作都要寫一個(gè)SQL語句出來,略顯笨拙。ORM的妙處就在于能夠把數(shù)據(jù)庫操作封裝得像是一段原生的程序。Django采取的抽象數(shù)據(jù)庫操作的方式和SQLAlchemy很像,就是把一張表抽象成一個(gè)python類。比如我們?cè)趎ew_app這個(gè)APP中的models.py中加入以下內(nèi)容:

from __future__ import unicode_literals

from django.db import models

class Character(models.Model):
    name = models.CharField(max_length=200)
    age = models.IntergerField()

    def __unicode__(self):
        return self.name

 

  此時(shí)項(xiàng)目中已經(jīng)設(shè)計(jì)好了表,就差把表結(jié)構(gòu)給注入數(shù)據(jù)庫了。然而這個(gè)過程如果手動(dòng)做就沒有意義了。Django給出了自動(dòng)的解決方案。依次運(yùn)行如下命令:

python manage.py migrate

python manage.py makemigrations

python manage.py migrate

  第一個(gè)migrate可以看做是數(shù)據(jù)庫的初始化,運(yùn)行完第一條之后進(jìn)入數(shù)據(jù)庫看可以看到Django_Test庫中有了下面這些表

+----------------------------+
| Tables_in_Django_Test      |
+----------------------------+
| auth_group                 |
| auth_group_permissions     |
| auth_permission            |
| auth_user                  |
| auth_user_groups           |
| auth_user_user_permissions |
| django_admin_log           |
| django_content_type        |
| django_migrations          |
| django_session             |
+----------------------------+

  這些表也不是空表,都是有數(shù)據(jù)的而且比較重要。至于為什么后面再說。

  第二條命令是將我們新建的表(也就是models里面的類)給記錄到APP的migrations目錄中的一個(gè)文件。這個(gè)目錄在python manage.py startapp的時(shí)候自動(dòng)創(chuàng)建,且里面自帶一個(gè)__init__.py。這些文件是作為后續(xù)數(shù)據(jù)庫版本的升降級(jí)操作的依據(jù),所以也不應(yīng)該擅自刪改。此時(shí)migrations目錄下應(yīng)該就有了一個(gè)0001_initial.py的文件了。

  第三條則是把本地的數(shù)據(jù)庫信息同步到真的數(shù)據(jù)庫中,在操作完這個(gè)命令之后,我們可以看到數(shù)據(jù)庫中會(huì)多出一張new_app_character的表,其表結(jié)構(gòu)是和我們的Character類定義的相同。

  ●  如何初始化migrations相關(guān)數(shù)據(jù)

  可以看到有django_migrations這個(gè)表,說明在數(shù)據(jù)庫升降級(jí)的時(shí)候并不是單單看migrations目錄下面有哪些文件的,而是參考了數(shù)據(jù)庫中的數(shù)據(jù)。所以說數(shù)據(jù)庫中的那些初始化信息也很重要。這么一來,想要初始化所有數(shù)據(jù)庫數(shù)據(jù)就不能簡單的把migrations下面的文件刪光了。比較徹底的做法是把整個(gè)Django_Test數(shù)據(jù)庫drop掉,然后把migrations中的除了__init__外所有文件刪掉。再重新建庫,migrate,makemigrations這樣來做。

  當(dāng)然在正式生產(chǎn)中肯定不能這么做,這就表明,對(duì)于數(shù)據(jù)庫初始化出來的數(shù)據(jù)以及migrations中的文件一定不能輕易修改刪除。理想的做法是對(duì)表結(jié)構(gòu)做出調(diào)整之后先makemigrations再migrate一下。

  這里順便一提,進(jìn)行數(shù)據(jù)庫版本升級(jí)的時(shí)候django做得還是很智能的。比如我一開始沒有age字段,migrate的時(shí)候添加了age字段但是沒指定default,django就提示說如果表里原來有記錄的話就不知道新插入這個(gè)age字段該取什么值,讓我選擇時(shí)系統(tǒng)自動(dòng)給一個(gè)default值呢還是回models.py中手動(dòng)指定一個(gè)default值。

  通過ORM進(jìn)行增刪查改以后慢慢說,這里只展示一下:

  首先通過后臺(tái)插入數(shù)據(jù):

INSERT INTO new_app_character (name,age) VALUES('Django',50);

  需要注意的是一定要給出(name,age),因?yàn)樯厦娑x的時(shí)候我們沒有給出主鍵,orm自動(dòng)為這個(gè)表添加一個(gè)名為id的字段作為主鍵,從1開始自然計(jì)數(shù)。

  然后在程序中比如在views中可以:

from .models import Character
from django.http import HttpResponse

def new_first_page(request):
    namelist = Character.objects.all()
    res = ''
    for name in namelist:
        res += '<p>%s</p>' % name
    return HttpResponse(res)

  這就實(shí)現(xiàn)了通過ORM從數(shù)據(jù)庫中取出數(shù)據(jù)的目的了。

 

■  Django模板初步

  如上面目錄中那樣,在項(xiàng)目的根目錄級(jí)下有一個(gè)templates目錄,里面存放的自然就是項(xiàng)目的模板文件了。

  在settings.py中,可以看到一個(gè)配置項(xiàng)是TEMPLATES,下面有一個(gè)DIRS的配置項(xiàng),這是一個(gè)list。其中默認(rèn)的是那個(gè)templates目錄,也可以自己手動(dòng)再增加一些其他的目錄,這樣就實(shí)現(xiàn)了多個(gè)模板目錄的設(shè)置了。至于模板的語法和渲染模板的方法以下面這個(gè)例子做個(gè)最簡單的說明:

####模板文件test.html####
<h1>{{ label }}</h1>

####某個(gè)views.py文件中增加內(nèi)容####
from django.shortcuts import render

def template_show(request):
    context = {}
    context['label'] = 'Hello World'
    return render(request, 'test.html', context)

  之后在相應(yīng)的APP的urls.py中添加對(duì)url的路由,訪問相關(guān)頁面就可以看到html為<h1>Hello World</h1>的頁面了。這里可以注意一下render方法和flask中render_template的一些不同,為了避免大量變量渲染時(shí)引起的參數(shù)過長的問題,把所有參數(shù)都維護(hù)到一個(gè)context字典里面可以說是一個(gè)非常好的辦法。

  Django在渲染模板的時(shí)候,首先將上下文數(shù)據(jù)context傳遞給模板文件,分析模板文件中需要渲染的部分,具體化之后又自動(dòng)生成了HTTPResponse返回,所以我們?cè)谶@里可以直接return render方法的返回。結(jié)合上面說的ORM,可以從數(shù)據(jù)庫中取出數(shù)據(jù),進(jìn)行一定程度的處理之后再傳遞給模板,這就完成了一個(gè)非常MVC的流程。

  之前在學(xué)習(xí)flask的時(shí)候就聽說過Django的模板和Jinja2不太一樣,但是粗粗看了下教程,發(fā)現(xiàn)是大同小異的,這里就不再費(fèi)口舌說一些基本的東西了。主要補(bǔ)充一些據(jù)說和jinja2不同的地方(動(dòng)態(tài)更新中...),比如在Django的模板中,無參函數(shù)的調(diào)用時(shí)不用機(jī)加括號(hào)的,但是jinja2是和原生的Python一樣加括號(hào)。

  總體而言,Django的模板系統(tǒng)比Jinja2有更多的限制,也更不像是python或者其他的編程語言。比如Jinja2中可能會(huì)有{% if name == 'takanashi' %}這樣的表達(dá)但是據(jù)說Django是不行的等等。

 

  ●  關(guān)于宏

  之前似乎沒有提到,django的模板系統(tǒng)中是不存在宏這種設(shè)定的。也就是說不能直接使用{% macro xxx %}這樣的方式來定義宏從而減少編寫重復(fù)代碼的次數(shù)。

  不過好在有解決方案就是django-macros。pip install一下之后,在項(xiàng)目的settings中的INSTALLED_APPS中添加'macros',然后再在相關(guān)模板中{% load macros %}之后,這個(gè)模板文件里就可以自由使用macro了。

  ●  關(guān)于自動(dòng)反轉(zhuǎn)義

  如果后端傳到模板的字符串中含有一些HTML敏感的字符比如<,>,&等,Django在渲染模板的時(shí)候會(huì)自動(dòng)將這些內(nèi)容進(jìn)行一個(gè)反轉(zhuǎn)義,從而使頁面可以正確地顯示這些文本。比如

  <div>{{ text }}</div>是模板,然后后端的ctx={'text': 'Hello,<b>World</b>'},渲染出得到的頁面會(huì)是Hello,<b>World</b>,而不是Hello,World這樣加粗字體的。

  有時(shí)如果需要反過來,不要他強(qiáng)行自動(dòng)轉(zhuǎn)義,則可以在模板中使用{% autoescape %}標(biāo)簽,包含在{% autoescape off %}{% endescape %}這個(gè)block中的所有待渲染的內(nèi)容,是不會(huì)自動(dòng)轉(zhuǎn)義,而是保持HTML原有的樣式的。

 

■  Django的表單處理

  任何一個(gè)Web框架都少不了對(duì)表單的支持。下面演示一個(gè)最簡單的通過POST方法發(fā)送數(shù)據(jù)給WEB應(yīng)用然后將數(shù)據(jù)存入數(shù)據(jù)庫之后返回一個(gè)頁面的Django的結(jié)構(gòu)。models等一些數(shù)據(jù)復(fù)用了前面提到過的東西:

<!-- 模板頁面 -->
<form method="post" action="/new/process/">
  {% csrf_token %}
  <input type="text" name="name" />
  <input type="number" name="age" />
  <input type="submit" value="Submit" />
</form>

<p>{{ rlt }}</p>
<p>{{ age }}</p>

  在后臺(tái)的new_app/views.py中:

from django.shortcuts import render
from django.template.context_processors import csrf

def process(request):
  ctx = {}
  ctx.update(csrf(request))
  if request.POST:
    ctx['rlt'] = request.POST['name']
    ctx['age'] = request.POST['age']
  return render(request, 'formtest.html', ctx)

 

  這里需要注意的是在模板中我們就做了csrf的處理,然后在后臺(tái)也要進(jìn)行一個(gè)csrf的處理,然后根據(jù)處理完之后的context再來渲染頁面??梢钥吹?,在Django里面默認(rèn)不做出對(duì)某個(gè)url的訪問方法的限制。所以在urls.py中定義了到這個(gè)處理函數(shù)的路由(/new/process)后訪問這個(gè)路由,首先是GET方法獲取頁面,此時(shí)因?yàn)閏ontext中沒有定義rlt和age這兩個(gè)模板中的變量,所以頁面下方是兩個(gè)空行。然后填完數(shù)據(jù)表單提交,因?yàn)閒orm標(biāo)簽的action指向還是這個(gè)路由,所以POST數(shù)據(jù)到process函數(shù)下面。因?yàn)槭荘OST,進(jìn)入分支,context中有了關(guān)于rlt和age的值,于是就渲染出有值的頁面了。

  如果需要將POST上來的數(shù)據(jù)根據(jù)剛才定義的model存進(jìn)數(shù)據(jù)庫那么可以:

def process(request):
  ctx = {}
  ctx.update(csrf(request))
  if request.POST:
    name,age = request.POST.get('name'),request.POST.get('age')
    new_record = Character(name=name,age=age)
    new_record.save()
  return render(request, 'formtest.html', ctx)

  這也是大概地展示一下如何用ORM進(jìn)行“增”的數(shù)據(jù)庫操作

  

  在flask中,我們用到了wtforms來進(jìn)行方便的表單渲染和管理,Django也有類似的功能。而且Django把表單管理的模塊也一并整合到了Django這個(gè)大模塊中,所以使得表單的描述和數(shù)據(jù)庫表結(jié)構(gòu)的描述可以統(tǒng)一起來。而這兩者在實(shí)際中又常常是互相關(guān)聯(lián)的。比如上面的那個(gè)表單,我們可以做以下改造:

from django import forms

class CharacterForm(froms.Form):
    name = forms.Charfield(max_length=200,label="Your Name")
    age = forms.IntegerField(min_value=18)

def process(request):
    context = {}
    context.update(csrf(request))
    if request.POST:
        form = CharacterForm(request.POST)
        if form.is_valid():
            #do something with data
    form = CharacterForm()
    context['form'] = form
    return render(request, 'form_test.html', context)

####在模板中可以這么寫####
{{ form.as_p }}
####這樣就可以自動(dòng)地生成一個(gè)表單了####

   雖說是自動(dòng)生成了表單,但是需要注意的是并不是全部要素,只是要填的一些字段和相關(guān)的label等等,比如<form> 標(biāo)簽已經(jīng)submit的input等還是要自己手寫的,相當(dāng)于as_p方法只是放回了純的變成了p標(biāo)簽形式的表單html代碼。

  ●  對(duì)于ajax發(fā)起post請(qǐng)求的csrf處理

  以上對(duì)于表單發(fā)起post請(qǐng)求的舉例都是通過了<form>這個(gè)DOM來實(shí)現(xiàn)的。但是在有ajax的時(shí)候我們可以不必拘泥于form而采用更加自由的ajax發(fā)起POST請(qǐng)求。這就引起了一個(gè)小問題,在form的時(shí)候我們只要在前端模板里面寫上{% csrf_token %}就可以自動(dòng)給我們的表單DOM增加防csrf驗(yàn)證功能。但是在ajax的時(shí)候如何將這部分信息和一個(gè)特定的ajax請(qǐng)求聯(lián)系起來。辦法有很多種,比如可以在頁面中引入額外的一個(gè)csrf.js文件來適應(yīng)csrf驗(yàn)證【參考https://code./django/django-csrf.html】。

  一個(gè)更加簡單的方法是在全局ajax設(shè)置中增肌相關(guān)csrf驗(yàn)證的設(shè)置:

$.ajaxSetup({
  data: {
    csrfmiddlewaretoken: '{{ csrf_token }}'
  }
});

 

  這個(gè)辦法需要注意的是1. 這段代碼應(yīng)該寫在模板文件的<script>標(biāo)簽中因?yàn)閧{ csrf_token }}這個(gè)只有在模板里面才能被識(shí)別,寫在.js中是無法被識(shí)別的。2. csrf_token要用{{ }}括起來而不是{% %},具體原因不知道。??傊挥羞@樣才行。

  還有一個(gè)不是辦法的辦法,就是在相關(guān)的ajax的POST發(fā)向的那個(gè)view,from django.views.decorators.csrf import csrf_exempt,然后在這個(gè)view函數(shù)上面增加裝飾器@csrf_exempt來迫使這個(gè)view接受到的請(qǐng)求不進(jìn)行CSRF驗(yàn)證。

■  Django自帶的WebApp

  之所以稱Django是一個(gè)很大的框架,原因在于它自帶了很多功能,其中感覺到最神奇的就是這個(gè),自帶的一個(gè)管理數(shù)據(jù)庫的APP。這個(gè)APP通常在settings.py的INSTALLED_APPS中已經(jīng)預(yù)安裝好,并且在項(xiàng)目根目錄的urls.py中還設(shè)置好了url,通常是[site]/admin來訪問。

  這個(gè)App其實(shí)是一個(gè)管理數(shù)據(jù)庫模型的一個(gè)App,在通過它管理模型之前還需要在相關(guān)模型所在的應(yīng)用中的admin.py下進(jìn)行模型的注冊(cè)。做法是:

###admin.py###
from models import Character

admin.site.register(Character)

 

  如果是第一次訪問管理界面,那么需要用manage.py工具的createsuperuser命令來建立管理員用戶,按照字符界面的提示輸入管理員的用戶名密碼等信息來注冊(cè)管理員用戶。

  登錄之后我們可以看到這樣的界面:

  可以看到我們注冊(cè)的new_app下面的Character模型已展示在頁面上了。至于上面的是Django預(yù)裝的Auth模塊,我們以后還可以用它來進(jìn)行用戶的管理。因?yàn)橛脩粽f到底也只是數(shù)據(jù)庫中的一張表,一個(gè)模型而已。另外這個(gè)web界面管理真的十分方便,這個(gè)Character的模型還略顯簡單了點(diǎn),如果是個(gè)稍微復(fù)雜一點(diǎn)的模型比如:

class Role(models.Model):
    role_code = models.IntegerField(primary_key=True)
    role_name = models.CharField(max_length=100)
    def __unicode__(self):
        return self.role_name

class User(models.Model):
    name = models.CharField(max_length=100,primary_key=True)
    age = models.IntegerField()
    email = models.EmailField()
    role = models.ForeignKey(Role)
    def __unicode__(self):
        return '%s(%s)  Mail:%s' % (self.name,self.age,self.email)

  涉及到了外鍵的設(shè)置,此時(shí)如果先點(diǎn)擊Role旁邊的Add,可以手動(dòng)為數(shù)據(jù)庫中添加角色信息:

  當(dāng)添加完一些信息之后,到添加User的界面中還可以看到剛才添加過的角色信息供選擇:

  需要注意的是添加一條記錄后會(huì)給出一個(gè)提示中有中文,再有就是比如這邊角色的幾個(gè)名字,這些都是根據(jù)__unicode__的返回決定的。所以在model類實(shí)現(xiàn)的時(shí)候需要實(shí)現(xiàn)__unicode__方法,并且想好一種表達(dá)清晰的返回。在開發(fā)階段進(jìn)行小批量的數(shù)據(jù)插入的時(shí)候,這個(gè)界面顯然比到后臺(tái)用SQL插入數(shù)據(jù)要友好很多。

  此外如果需要對(duì)某些字段進(jìn)行隱藏處理的話可以修改一下new_app/admin.py中的內(nèi)容,之前我們直接admin.site.register了所有模型類。如果想要進(jìn)行字段顯示的調(diào)整可以在new_app/admin.py中進(jìn)行:

from django.contrib import admin

from models import User,Role

class UserShow(admin.ModelAdmin):
    fields = ('name','age','role')    #沒加email

admin.site.register(User,UserShow)
admin.site.register(Role)    #Role表不變,但是User表有所調(diào)整

 

  這樣的話在界面上無論是讀取User記錄的信息還是新增一個(gè)User的記錄,Email字段就都不會(huì)顯示出來了。其實(shí)這么做的原理顯而易見,就是把一個(gè)ModelAdmin類的衍生類和我們的模型類關(guān)聯(lián)起來。上面這個(gè)ModelAdmin的子類UserShow用到了fields這個(gè)屬性來設(shè)置顯示不顯示,其實(shí)還有更強(qiáng)大的屬性比如fieldsets:

class UserShow(admin.ModelAdmin):
    fieldsets = (
        ['基本信息',{
            'classes' : ('collapse',),    # CSS設(shè)置
            'fields' : ('name','age')
        }],
        ['更多信息',{
            'classes' : ('collapse',),
            'fields' : ('email','role')
        }]
    )

 

   如果UserShow跟上面這樣寫的話,得到的界面就是:

  基本信息和更多信息兩個(gè)Panel都可以通過點(diǎn)擊旁邊的hide和show來隱藏顯示。

  類似的,設(shè)置這個(gè)類中的list_display屬性可以改變展示界面的字段展示,下面貼出代碼和修改前后界面的圖:

class UserShow(admin.ModelAdmin):
    list_display = ('name','age','email','role')

   改變前:

  改變后:

 

■  用戶驗(yàn)證與管理

  之前提到過Django預(yù)裝了Auth這個(gè)用戶管理模塊,那么要怎么使用。首先在settings.py中的INSTALLED_APPS中一般是有admin.contrib.auth這個(gè)APP在了。在http://site/admin這個(gè)管理界面上可以在系統(tǒng)自帶的那個(gè)Users中去添加刪除用戶,當(dāng)然這個(gè)頁面最好不要暴露給一般用戶,正確的做法應(yīng)該是自己設(shè)計(jì)一個(gè)表單收集用戶提供的信息,然后根據(jù)信息進(jìn)行后臺(tái)的相關(guān)操作。因?yàn)橛脩舻男畔⒁苍贒jango設(shè)計(jì)的用戶系統(tǒng)的框架內(nèi)所以后臺(tái)那些操作自然也是Django自身提供的一些封裝好的方法。

  在進(jìn)行下面的說明之前,我們先建立一個(gè)名為users的App來單獨(dú)進(jìn)行用戶的一些操作:python manage.py startapp users

  ●  用戶的登錄、驗(yàn)證和登出

  前端模板:

<!-- login.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{{ request.path }}</title>
</head>
<body>
<form method="post" action="/users/login">
    {% csrf_token %}
    {{ form.as_p }}
    <input type="submit" value="Go!" />
</form>

</body>
</html>

  后端views.py:

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.shortcuts import render,redirect
from django.template.context_processors import csrf
from django import forms
from django.contrib.auth import authenticate,login
# Create your views here.

class LoginForm(forms.Form):
    username = forms.CharField(max_length=100,min_length=3)
    password = forms.CharField(min_length=8,widget=forms.PasswordInput)
    email = forms.EmailField()

def user_login(request):
    context = {}
    context.update(csrf(request))
    login_form = LoginForm()
    if request.POST:
        username = password = ''
        username = request.POST.get('username')
        password = request.POST.get('password')
        user = authenticate(username=username,password=password)
        if user is not None and user.is_active:
            login(request,user)
            return redirect('/')
        else:
            return redirect('/users/login')
    context['form'] = login_form
    return render(request,'login.html',context)

 

  這里比較新鮮的就是contrib.auth中的authentication和login兩個(gè)方法。當(dāng)用戶在表單中輸入信息然后POST上來之后,我們可以直接調(diào)用authentication方法來快速驗(yàn)證用戶密碼的正確性,如果驗(yàn)證通過將返回這個(gè)用戶的User對(duì)象。如果沒有通過則是返回None。需要注意的是Django內(nèi)建的User對(duì)象還具有active這個(gè)屬性即用戶是否在有效期內(nèi),如果不是的那么也不能將用戶放行。另外,自帶的這個(gè)驗(yàn)證機(jī)制似乎不能判別是用戶不存在還是密碼錯(cuò)誤導(dǎo)致的驗(yàn)證沒通過。

  login方法則更像是一個(gè)狀態(tài)置活方法,通過驗(yàn)證之后調(diào)用這個(gè)方法來告訴系統(tǒng)當(dāng)前用戶XXX是登錄狀態(tài)的。在調(diào)用過login方法之后就可以保持整個(gè)會(huì)話過程中用戶身份的保持了。

  在其他的視圖中,可以通過request.user這個(gè)對(duì)象來調(diào)用當(dāng)前登錄用戶相關(guān)的一些信息。比如user.get_username()返回用戶名,user.set_password('xxx')可以重設(shè)密碼,user.password則可以看到密碼的密文,date_joined和last_login分別可以看到賬號(hào)創(chuàng)建時(shí)間和上次登錄時(shí)間,不過這兩個(gè)時(shí)間的時(shí)區(qū)有點(diǎn)詭異,反正都不是東八區(qū)。user.check_password('xxx')可以對(duì)一段明文是否是密碼進(jìn)行驗(yàn)證,可以用于用戶登錄之后還需要驗(yàn)證密碼的場合比如授權(quán)等等。下面是一個(gè)在其他視圖(非登錄相關(guān)視圖)中調(diào)用user信息的示例:

def auth_test(request):
    context = {}
    if request.user.is_authenticated():
        return HttpResponse('<p>%s</p>' % request.user.get_username())
    else:
        return redirect('/user/login')

 

  這里用的判斷當(dāng)前是否有用戶的方式是用了if 語句判斷user.is_authenticated方法返回的狀態(tài)。其實(shí)還有更加方便的方法就是使用裝飾器login_required:

from django.contrib.auth.decorators import login_required

@login_required
def auth_test(request):
    return HttpResponse('<p>%s</p>' % request.user.get_username())

  這里一個(gè)小問題是當(dāng)用戶處于登出狀態(tài)的時(shí)候,如果訪問@login_required修飾的路由函數(shù)會(huì)怎么樣。默認(rèn)情況下,會(huì)轉(zhuǎn)送到uri為accounts/login?next=/xxxx(auth_test的路由),如果沒有定義過accounts/login的話那么引起的就是404了。其實(shí)在使用@login_required的時(shí)候可以加上參數(shù)(login_url='/users/login')來把頁面重定向到我們?cè)O(shè)計(jì)好的/users/login下面去。只不過next這個(gè)參數(shù)還是沒有自帶的實(shí)現(xiàn)的,所以還需要我們?cè)趌ogin的路由函數(shù)中再添加對(duì)GET參數(shù)next的一些處理。如果不希望在后臺(tái)做判斷的話也可以在前臺(tái)的模板中進(jìn)行判斷,比如添加一條{% if user.is_authenticated %}(Django模板函數(shù)不加括號(hào)哦),具體就不寫出來了。

  說到登出,登出更加簡單:

from django.contrib.auth import logout

def user_logout(request):
    logout(request)
    return redirect('/')

  相比于login,logout只需要request這一個(gè)參數(shù)。

 

■  用戶注冊(cè)

   用戶注冊(cè)和用戶登錄類似,只不過接受表單的數(shù)據(jù)之后做的處理不太一樣。當(dāng)然我們可以手動(dòng)寫一個(gè)表單的html來做,不過對(duì)于簡單的用戶注冊(cè),還有更加方便的操作:

from django.contrib.auth.forms import UserCreationForm
from django.shortcuts import redirect,render
from django.template.context_processors import csrf

def user_register(request):
    if request.method == 'POST':
        form = UserCreationForm(request.POST)
        if form.is_valid():
            new_user = form.save()
        return redirect('/')

    else:
        form = UserCreationForm()
        context = {'form':form}
        context.update(csrf(request))
        return render(request, 'register.html', context)

  前端模板:

<form action="" method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <input type="submit" value="Submit" />
</form>

  嘗試了一下,渲染出來的表單還是非常難看的。。

 

 ■  自定義用戶表

  如果覺得django.contrib.models.User這個(gè)模型不能滿足你的需求的話,也可以通過繼承這個(gè)模型來自定義一個(gè)用戶類。這個(gè)自定義的用戶類可以適用于之前所有User類可以用的方法和函數(shù)。相當(dāng)于是對(duì)django自帶的User類進(jìn)行了一個(gè)很好的擴(kuò)展。

  繼承是一種辦法,另一種辦法就是自定義一個(gè)模型類之后,在類中增加一個(gè)OneToOneField映射到User這個(gè)表上。通過OneToOneField映射的好處就是在調(diào)用時(shí)可以直接request.user.xxx來調(diào)用我們自定義的類,十分方便。

  如果對(duì)于定制要求比較高,那么也可以到更底層去,比如從AbstractBaseUser(User類的父類的父類)和AbstractUserManager開始繼承。

===============

至此,Django的基本介紹結(jié)束,原博主還寫了兩篇關(guān)于用Web容器部署項(xiàng)目以及買服務(wù)器部署服務(wù)的,這里不太需要就不多說了。

這篇文章頂多是對(duì)Django有一個(gè)大概的印象,接下來我會(huì)看書本,把上面提到的知識(shí)細(xì)化,分塊記錄下來。

以上。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    亚洲国产成人久久99精品| 天海翼精品久久中文字幕| 日本高清视频在线播放| 精品丝袜一区二区三区性色| 国内精品伊人久久久av高清| 99久久精品免费精品国产| 国产精品福利一级久久| 亚洲精品av少妇在线观看| 国产精品亚洲欧美一区麻豆| 日本深夜福利视频在线| 亚洲中文字幕熟女丝袜久久| 国自产拍偷拍福利精品图片| 亚洲欧美日韩在线中文字幕| 在线观看国产午夜福利| 丰满的人妻一区二区三区| 99热在线播放免费观看| 日韩国产亚洲一区二区三区| 国产一区国产二区在线视频| 伊人色综合久久伊人婷婷| 91精品国产综合久久不卡| 日本人妻精品中文字幕不卡乱码| 中文字幕av诱惑一区二区| 亚洲国产精品久久综合网| 一区二区三区国产日韩| 精品国产成人av一区二区三区| 美国欧洲日本韩国二本道| 精品国产亚洲一区二区三区| 免费黄片视频美女一区| 亚洲综合色在线视频香蕉视频 | 欧美大粗爽一区二区三区| 欧美丰满大屁股一区二区三区| 国产一区欧美午夜福利| 欧美人妻少妇精品久久性色| 国产欧美性成人精品午夜| 丰满人妻少妇精品一区二区三区| 国产一区二区三区口爆在线| 久久精品亚洲精品一区| 伊人天堂午夜精品草草网| 久久91精品国产亚洲| 美女露小粉嫩91精品久久久| 亚洲性日韩精品一区二区|