【Django】 初步學習

這個系列(或者成不了一個系列。。)預計會全程參考Vamei様的Django系列,膜一發。說句題外話,其實更加崇拜像Vamei那樣的可以玩轉生活、各個領域都能取得不小成就的人。html

【Django】前端

■  概述python

  Django久聞大名,是Python中最爲有名的Web框架之一了。相比於其餘框架,D的特色就是提供了各類各樣的組件,重量級,能夠解決不少不少問題。讓Web編程一簡再簡。以前一直都學習使用Flask,不否定Flask有其有點,可是一個很大的不方便的地方在於,Flask的擴展沒有統一的標準並且開放,全部人均可以寫本身的Flask擴展。雖說是具備開源精神,可是一些比較常見的功能出現多種實現仍是會讓人有些困擾。下面簡單說說Django的使用mysql

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

  下載完成後能夠在Python shell中運行如下命令:ajax

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

  說明安裝成功。正則表達式

  ●  構建一個Django項目目錄框架的快捷方法sql

  讓我第一次感覺到Django的重型和周到是相比較於Flask構建項目時要本身一個個文件創建,Django能夠一鍵幫助生成一個較爲完整的項目框架等待你填充內容。在pip安裝完成以後,若是是windows環境則在$PYTHON_HOME的scripts,若是是Linux環境則是在/usr/bin這些目錄下,裏面會有一個django-admin[.exe]可執行程序。運行這個程序,後接上參數startproject <項目名>能夠在當前工做目錄下生成Django項目的目錄框架。獲得的框架是這樣的:shell

  這些也不全是空文件,像manage.py,settings.py等文件都是帶有默認內容的。數據庫

  考慮到通常開發確定是在windows上用IDE好比Pycharm,Pycharm也能夠一鍵生成Django項目框架,並且比django-admin生成的多一個templates文件夾用來盛放模板文件。

  構建完成框架以後能夠python manage.py runserver 8000來運行起這個server,內容由Django內置好。看到的界面是相似於這樣的:

 

  ●  第一次爲請求返回HTTP內容

  Django框架採用MVC架構,Flask框架中對於路由的響應經過裝飾器來綁定響應函數完成。而Django的路由設置統一放在urls.py這個文件中。下面將修改一下urls.py(由於以前存在一些內容了)

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這個列表,維護了整個項目的url和響應函數的對應關係。這裏比較NB的一點在於支持的是正則表達式,也就是說能夠爲一批URL綁定相同的響應函數。這一個和Flask仍是比較不一樣的。Flask若是須要正則路由匹配的支持,則須要本身到werkzeug.routing中本身實現一個支持正則的Convertor對象。

  默認的自帶了Django服務器後面的URI若是是/admin/的話,那麼路由到Django-Admin界面,而下面咱們添加的那條,則是說明了當請求URL爲空(即訪問的URI是/時),則路由到first_page這個函數中去。那麼first_page在哪裏定義呢,看上面的import語句,是DjangoTest目錄下的views文件。這個文件是咱們本身建的而且要往裏面寫內容的。好比下面這樣:

from django.http import HttpResponse

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

 

  ●  進行模塊化管理

  一個網站可能有不少功能,所以確定須要進行模塊化的代碼管理。這一點在Flask中能夠用相似於blueprint的結構來實現。而在Django中這個被稱爲app(默默吐槽,比Flask恰好高了一級)

  運行一個項目中的manage.py好比python manage.py startapp new_app就能夠在當前項目中增長一個名爲new_app的目錄,下面也有admin.py,__init__.py,models.py,tests.py和views.py等文件。

  光添加一個新的目錄並無用,還須要將這個目錄所表明的APP和當前項目關聯起來。關聯的方法就是修改DjangoTest下的settings.py文件。這個文件中有一個INSTALLED_APPS列表,在其中添加'new_app'便可。另外能夠看到這個INSTALLED_APP裏面已經有一些內容存在了,這些內容表明瞭Django內置的一些功能好比用戶驗證,會話管理,顯示靜態文件等等。Django識別APP是從項目的根目錄開始的,因此不用像已有的那些寫得比較複雜好比django.contrib.admin,而直接寫new_app便可。

  爲了訪問到一個單獨APP中的頁面,咱們首先在項目總的urls.py中添加new_app的urls的相關信息(這樣作有利於不一樣模塊的url映射的各自維護,模塊間解耦)。把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'))
]

 

  看到這裏其實已經能夠大概看出來Django中如何進行url的配置了。往urlpatterns裏面能夠增長url對象。url對象構建時第一個參數是正則匹配路徑,第二個參數能夠是一個callable的對象,此時須要在以前import進去;也能夠是include方法的返回,include方法的參數是一個字符串,字符串中以endpoint的形式指向另外一個urls文件,此時那個urls文件中規定的正則匹配路徑在整個項目中應該加上調用其include方法前面的路徑整個拿來匹配。

  上面把new_app.urls文件中定義的url映射都include到了根目錄下,然而在new_app下目前尚未urls.py文件,因此在這個目錄下新建urls.py。文件中的內容參考下面這樣子:

from django.conf.urls import url

from .views import new_first_page

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

 

  這麼處理以後訪問/new/就會映射到new_first_page這個函數下了。

 

■  數據庫和ORM初步

  一個WEB應用的根基在於數據庫中的數據,一個好的web框架必須有很好的和數據庫交互的手段。以前在Flask的時候,採用了SQLAlchemy的第三方模塊的方法,將flask和數據庫的交互作得比較友好。到了Django的場合,Django有一套本身的ORM機制,看起來很像SQLAlchemy(事實上好像就是改造了SQLAlchemy),貼合度更好。

  要進行數據庫交互,首先得有數據庫。好比我先到虛擬機的mysql中建立一個Django項目用的數據庫,而且指定(或者建立)一個用戶來管理這個庫:

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

mysql>GRANT ALL PRIVILEGES ON Django_Test.* TO weiyz@'%';
/*將新建的數據庫的操做權限賦給管理用戶*/
mysql>FLUSH PRIVILEGES;

 

  而後在Django項目的settings.py中的數據庫相關配置更改:

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

 

   這樣就關聯了數據庫和Django項目。

  web和數據庫的交互形式是一個很重要的問題。若是咱們使用MySQLdb這類包裝的比較低級的模塊來作的話,每個數據庫操做都要寫一個SQL語句出來,略顯笨拙。ORM的妙處就在於可以把數據庫操做封裝得像是一段原生的程序。Django採起的抽象數據庫操做的方式和SQLAlchemy很像,就是把一張表抽象成一個python類。好比咱們在new_app這個APP中的models.py中加入如下內容:

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

 

  此時項目中已經設計好了表,就差把表結構給注入數據庫了。然而這個過程若是手動作就沒有意義了。Django給出了自動的解決方案。依次運行以下命令:

python manage.py migrate

python manage.py makemigrations

python manage.py migrate

  第一個migrate能夠看作是數據庫的初始化,運行完第一條以後進入數據庫看能夠看到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             |
+----------------------------+

  這些表也不是空表,都是有數據的並且比較重要。至於爲何後面再說。

  第二條命令是將咱們新建的表(也就是models裏面的類)給記錄到APP的migrations目錄中的一個文件。這個目錄在python manage.py startapp的時候自動建立,且裏面自帶一個__init__.py。這些文件是做爲後續數據庫版本的升降級操做的依據,因此也不該該擅自刪改。此時migrations目錄下應該就有了一個0001_initial.py的文件了。

  第三條則是把本地的數據庫信息同步到真的數據庫中,在操做完這個命令以後,咱們能夠看到數據庫中會多出一張new_app_character的表,其表結構是和咱們的Character類定義的相同。

  ●  如何初始化migrations相關數據

  能夠看到有django_migrations這個表,說明在數據庫升降級的時候並非單單看migrations目錄下面有哪些文件的,而是參考了數據庫中的數據。因此說數據庫中的那些初始化信息也很重要。這麼一來,想要初始化全部數據庫數據就不能簡單的把migrations下面的文件刪光了。比較完全的作法是把整個Django_Test數據庫drop掉,而後把migrations中的除了__init__外全部文件刪掉。再從新建庫,migrate,makemigrations這樣來作。

  固然在正式生產中確定不能這麼作,這就代表,對於數據庫初始化出來的數據以及migrations中的文件必定不能輕易修改刪除。理想的作法是對錶結構作出調整以後先makemigrations再migrate一下。

  這裏順便一提,進行數據庫版本升級的時候django作得仍是很智能的。好比我一開始沒有age字段,migrate的時候添加了age字段可是沒指定default,django就提示說若是表裏原來有記錄的話就不知道新插入這個age字段該取什麼值,讓我選擇時系統自動給一個default值呢仍是回models.py中手動指定一個default值。

  經過ORM進行增刪查改之後慢慢說,這裏只展現一下:

  首先經過後臺插入數據:

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

  須要注意的是必定要給出(name,age),由於上面定義的時候咱們沒有給出主鍵,orm自動爲這個表添加一個名爲id的字段做爲主鍵,從1開始天然計數。

  而後在程序中好比在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)

  這就實現了經過ORM從數據庫中取出數據的目的了。

 

■  Django模板初步

  如上面目錄中那樣,在項目的根目錄級下有一個templates目錄,裏面存放的天然就是項目的模板文件了。

  在settings.py中,能夠看到一個配置項是TEMPLATES,下面有一個DIRS的配置項,這是一個list。其中默認的是那個templates目錄,也能夠本身手動再增長一些其餘的目錄,這樣就實現了多個模板目錄的設置了。至於模板的語法和渲染模板的方法如下面這個例子作個最簡單的說明:

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

####某個views.py文件中增長內容####
from django.shortcuts import render

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

  以後在相應的APP的urls.py中添加對url的路由,訪問相關頁面就能夠看到html爲<h1>Hello World</h1>的頁面了。這裏能夠注意一下render方法和flask中render_template的一些不一樣,爲了不大量變量渲染時引發的參數過長的問題,把全部參數都維護到一個context字典裏面能夠說是一個很是好的辦法。

  Django在渲染模板的時候,首先將上下文數據context傳遞給模板文件,分析模板文件中須要渲染的部分,具體化以後又自動生成了HTTPResponse返回,因此咱們在這裏能夠直接return render方法的返回。結合上面說的ORM,能夠從數據庫中取出數據,進行必定程度的處理以後再傳遞給模板,這就完成了一個很是MVC的流程。

  以前在學習flask的時候就據說過Django的模板和Jinja2不太同樣,可是粗粗看了下教程,發現是大同小異的,這裏就再也不費口舌說一些基本的東西了。主要補充一些聽說和jinja2不一樣的地方(動態更新中...),好比在Django的模板中,無參函數的調用時不用機加括號的,可是jinja2是和原生的Python同樣加括號。

  整體而言,Django的模板系統比Jinja2有更多的限制,也更不像是python或者其餘的編程語言。好比Jinja2中可能會有{% if name == 'takanashi' %}這樣的表達可是聽說Django是不行的等等。

 

  ●  關於宏

  以前彷佛沒有提到,django的模板系統中是不存在宏這種設定的。也就是說不能直接使用{% macro xxx %}這樣的方式來定義宏從而減小編寫重複代碼的次數。

  不過好在有解決方案就是django-macros。pip install一下以後,在項目的settings中的INSTALLED_APPS中添加'macros',而後再在相關模板中{% load macros %}以後,這個模板文件裏就能夠自由使用macro了。

  ●  關於自動反轉義

  若是後端傳到模板的字符串中含有一些HTML敏感的字符好比<,>,&等,Django在渲染模板的時候會自動將這些內容進行一個反轉義,從而使頁面能夠正確地顯示這些文本。好比

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

  有時若是須要反過來,不要他強行自動轉義,則能夠在模板中使用{% autoescape %}標籤,包含在{% autoescape off %}{% endescape %}這個block中的全部待渲染的內容,是不會自動轉義,而是保持HTML原有的樣式的。

 

■  Django的表單處理

  任何一個Web框架都少不了對錶單的支持。下面演示一個最簡單的經過POST方法發送數據給WEB應用而後將數據存入數據庫以後返回一個頁面的Django的結構。models等一些數據複用了前面提到過的東西:

<!-- 模板頁面 -->
<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>

  在後臺的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的處理,而後在後臺也要進行一個csrf的處理,而後根據處理完以後的context再來渲染頁面。能夠看到,在Django裏面默認不作出對某個url的訪問方法的限制。因此在urls.py中定義了到這個處理函數的路由(/new/process)後訪問這個路由,首先是GET方法獲取頁面,此時由於context中沒有定義rlt和age這兩個模板中的變量,因此頁面下方是兩個空行。而後填完數據表單提交,由於form標籤的action指向仍是這個路由,因此POST數據到process函數下面。由於是POST,進入分支,context中有了關於rlt和age的值,因而就渲染出有值的頁面了。

  若是須要將POST上來的數據根據剛纔定義的model存進數據庫那麼能夠:

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進行「增」的數據庫操做

  

  在flask中,咱們用到了wtforms來進行方便的表單渲染和管理,Django也有相似的功能。並且Django把表單管理的模塊也一併整合到了Django這個大模塊中,因此使得表單的描述和數據庫表結構的描述能夠統一塊兒來。而這二者在實際中又經常是互相關聯的。好比上面的那個表單,咱們能夠作如下改造:

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 }}
####這樣就能夠自動地生成一個表單了####

   雖然說是自動生成了表單,可是須要注意的是並非所有要素,只是要填的一些字段和相關的label等等,好比<form> 標籤已經submit的input等仍是要本身手寫的,至關於as_p方法只是放回了純的變成了p標籤形式的表單html代碼。

  ●  對於ajax發起post請求的csrf處理

  以上對於表單發起post請求的舉例都是經過了<form>這個DOM來實現的。可是在有ajax的時候咱們能夠沒必要拘泥於form而採用更加自由的ajax發起POST請求。這就引發了一個小問題,在form的時候咱們只要在前端模板裏面寫上{% csrf_token %}就能夠自動給咱們的表單DOM增長防csrf驗證功能。可是在ajax的時候如何將這部分信息和一個特定的ajax請求聯繫起來。辦法有不少種,好比能夠在頁面中引入額外的一個csrf.js文件來適應csrf驗證【參考https://code.ziqiangxuetang.com/django/django-csrf.html】。

  一個更加簡單的方法是在全局ajax設置中增肌相關csrf驗證的設置:

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

 

  這個辦法須要注意的是1. 這段代碼應該寫在模板文件的<script>標籤中由於{{ csrf_token }}這個只有在模板裏面才能被識別,寫在.js中是沒法被識別的。2. csrf_token要用{{ }}括起來而不是{% %},具體緣由不知道。。總之只有這樣才行。

  還有一個不是辦法的辦法,就是在相關的ajax的POST發向的那個view,from django.views.decorators.csrf import csrf_exempt,而後在這個view函數上面增長裝飾器@csrf_exempt來迫使這個view接受到的請求不進行CSRF驗證。

■  Django自帶的WebApp

  之因此稱Django是一個很大的框架,緣由在於它自帶了不少功能,其中感受到最神奇的就是這個,自帶的一個管理數據庫的APP。這個APP一般在settings.py的INSTALLED_APPS中已經預安裝好,而且在項目根目錄的urls.py中還設置好了url,一般是[site]/admin來訪問。

  這個App實際上是一個管理數據庫模型的一個App,在經過它管理模型以前還須要在相關模型所在的應用中的admin.py下進行模型的註冊。作法是:

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

admin.site.register(Character)

 

  若是是第一次訪問管理界面,那麼須要用manage.py工具的createsuperuser命令來創建管理員用戶,按照字符界面的提示輸入管理員的用戶名密碼等信息來註冊管理員用戶。

  登陸以後咱們能夠看到這樣的界面:

  能夠看到咱們註冊的new_app下面的Character模型已展現在頁面上了。至於上面的是Django預裝的Auth模塊,咱們之後還能夠用它來進行用戶的管理。由於用戶說到底也只是數據庫中的一張表,一個模型而已。另外這個web界面管理真的十分方便,這個Character的模型還略顯簡單了點,若是是個稍微複雜一點的模型好比:

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)

  涉及到了外鍵的設置,此時若是先點擊Role旁邊的Add,能夠手動爲數據庫中添加角色信息:

  當添加完一些信息以後,到添加User的界面中還能夠看到剛纔添加過的角色信息供選擇:

  須要注意的是添加一條記錄後會給出一個提示中有中文,再有就是好比這邊角色的幾個名字,這些都是根據__unicode__的返回決定的。因此在model類實現的時候須要實現__unicode__方法,而且想好一種表達清晰的返回。在開發階段進行小批量的數據插入的時候,這個界面顯然比到後臺用SQL插入數據要友好不少。

  此外若是須要對某些字段進行隱藏處理的話能夠修改一下new_app/admin.py中的內容,以前咱們直接admin.site.register了全部模型類。若是想要進行字段顯示的調整能夠在new_app/admin.py中進行:

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表有所調整

 

  這樣的話在界面上不管是讀取User記錄的信息仍是新增一個User的記錄,Email字段就都不會顯示出來了。其實這麼作的原理顯而易見,就是把一個ModelAdmin類的衍生類和咱們的模型類關聯起來。上面這個ModelAdmin的子類UserShow用到了fields這個屬性來設置顯示不顯示,其實還有更強大的屬性好比fieldsets:

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

 

   若是UserShow跟上面這樣寫的話,獲得的界面就是:

  基本信息和更多信息兩個Panel均可以經過點擊旁邊的hide和show來隱藏顯示。

  相似的,設置這個類中的list_display屬性能夠改變展現界面的字段展現,下面貼出代碼和修改先後界面的圖:

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

   改變前:

  改變後:

 

■  用戶驗證與管理

  以前提到過Django預裝了Auth這個用戶管理模塊,那麼要怎麼使用。首先在settings.py中的INSTALLED_APPS中通常是有admin.contrib.auth這個APP在了。在http://site/admin這個管理界面上能夠在系統自帶的那個Users中去添加刪除用戶,固然這個頁面最好不要暴露給通常用戶,正確的作法應該是本身設計一個表單收集用戶提供的信息,而後根據信息進行後臺的相關操做。由於用戶的信息也在Django設計的用戶系統的框架內因此後臺那些操做天然也是Django自身提供的一些封裝好的方法。

  在進行下面的說明以前,咱們先創建一個名爲users的App來單獨進行用戶的一些操做:python manage.py startapp users

  ●  用戶的登陸、驗證和登出

  前端模板:

<!-- 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兩個方法。當用戶在表單中輸入信息而後POST上來以後,咱們能夠直接調用authentication方法來快速驗證用戶密碼的正確性,若是驗證經過將返回這個用戶的User對象。若是沒有經過則是返回None。須要注意的是Django內建的User對象還具備active這個屬性即用戶是否在有效期內,若是不是的那麼也不能將用戶放行。另外,自帶的這個驗證機制彷佛不能判別是用戶不存在仍是密碼錯誤致使的驗證沒經過。

  login方法則更像是一個狀態置活方法,經過驗證以後調用這個方法來告訴系統當前用戶XXX是登陸狀態的。在調用過login方法以後就能夠保持整個會話過程當中用戶身份的保持了。

  在其餘的視圖中,能夠經過request.user這個對象來調用當前登陸用戶相關的一些信息。好比user.get_username()返回用戶名,user.set_password('xxx')能夠重設密碼,user.password則能夠看到密碼的密文,date_joined和last_login分別能夠看到帳號建立時間和上次登陸時間,不過這兩個時間的時區有點詭異,反正都不是東八區。user.check_password('xxx')能夠對一段明文是不是密碼進行驗證,能夠用於用戶登陸以後還須要驗證密碼的場合好比受權等等。下面是一個在其餘視圖(非登陸相關視圖)中調用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')

 

  這裏用的判斷當前是否有用戶的方式是用了if 語句判斷user.is_authenticated方法返回的狀態。其實還有更加方便的方法就是使用裝飾器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())

  這裏一個小問題是當用戶處於登出狀態的時候,若是訪問@login_required修飾的路由函數會怎麼樣。默認狀況下,會轉送到uri爲accounts/login?next=/xxxx(auth_test的路由),若是沒有定義過accounts/login的話那麼引發的就是404了。其實在使用@login_required的時候能夠加上參數(login_url='/users/login')來把頁面重定向到咱們設計好的/users/login下面去。只不過next這個參數仍是沒有自帶的實現的,因此還須要咱們在login的路由函數中再添加對GET參數next的一些處理。若是不但願在後臺作判斷的話也能夠在前臺的模板中進行判斷,好比添加一條{% if user.is_authenticated %}(Django模板函數不加括號哦),具體就不寫出來了。

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

from django.contrib.auth import logout

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

  相比於login,logout只須要request這一個參數。

 

■  用戶註冊

   用戶註冊和用戶登陸相似,只不過接受表單的數據以後作的處理不太同樣。固然咱們能夠手動寫一個表單的html來作,不過對於簡單的用戶註冊,還有更加方便的操做:

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這個模型不能知足你的需求的話,也能夠經過繼承這個模型來自定義一個用戶類。這個自定義的用戶類能夠適用於以前全部User類能夠用的方法和函數。至關因而對django自帶的User類進行了一個很好的擴展。

  繼承是一種辦法,另外一種辦法就是自定義一個模型類以後,在類中增長一個OneToOneField映射到User這個表上。經過OneToOneField映射的好處就是在調用時能夠直接request.user.xxx來調用咱們自定義的類,十分方便。

  若是對於定製要求比較高,那麼也能夠到更底層去,好比從AbstractBaseUser(User類的父類的父類)和AbstractUserManager開始繼承。

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

至此,Django的基本介紹結束,原博主還寫了兩篇關於用Web容器部署項目以及買服務器部署服務的,這裏不太須要就很少說了。

這篇文章頂可能是對Django有一個大概的印象,接下來我會看書本,把上面提到的知識細化,分塊記錄下來。

以上。

相關文章
相關標籤/搜索