1. 程式人生 > >15.Django基礎十一之認證系統

15.Django基礎十一之認證系統

一 auth模組

  

  我們在開發一個網站的時候,無可避免的需要設計實現網站的使用者系統。此時我們需要實現包括使用者註冊、使用者登入、使用者認證、登出、修改密碼等功能,這還真是個麻煩的事情呢。

  Django作為一個完美主義者的終極框架,當然也會想到使用者的這些痛點。它內建了強大的使用者認證系統--auth,它預設使用 auth_user 表來儲存使用者資料,使用auth模組來進行使用者認證,那麼需要使用人家django自帶的auth_user表來儲存使用者的資訊資料。

  模組匯入:

from django.contrib import auth

  那麼有人就有疑問 了,這個auth_user表並不是我們自己在models.py檔案中建立的啊,這通過程式碼怎麼操作啊?

  其中一個往auth_user表裡面新增資料的命令,可以先多新增幾個使用者,方便後面操作:

python manage.py createsuperuser  #要通過這個指令來建立使用者,因為這個指令會將你的密碼加密。

    

    然後表中就有資料了:這個表裡面的資料現在先關注username和password欄位就可以了,其他的欄位可為空。

    

 

  User表具有以下欄位:

內建的User模型擁有以下的欄位:
username: 使用者名稱。150個字元以內。可以包含數字和英文字元,以及_、@、+、.和-字元。不能為空,且必須唯一!
first_name:歪果仁的first_name,在30個字元以內。可以為空。
last_name:歪果仁的last_name,在150個字元以內。可以為空。
email:郵箱。可以為空。
password:密碼。經過雜湊過後的密碼。
#groups:分組。一個使用者可以屬於多個分組,一個分組可以擁有多個使用者。groups這個欄位是跟Group的一個多對多的關係。
#user_permissions:許可權。一個使用者可以擁有多個許可權,一個許可權可以被多個使用者所有用。和Permission屬於一種多對多的關係。
is_staff:是否可以進入到admin的站點。代表是否是員工。這個欄位如果不使用admin的話,可以自行忽略,不影響使用
is_active:是否是可用的。對於一些想要刪除賬號的資料,我們設定這個值為False就可以了,而不是真正的從資料庫中刪除。
is_superuser:是否是超級管理員。如果是超級管理員,那麼擁有整個網站的所有許可權。
last_login:上次登入的時間。
date_joined:賬號建立的時間。

  auth中提供了許多實用方法:

authenticate()

    提供了使用者認證功能,即驗證使用者名稱以及密碼是否正確,一般需要username 、password兩個關鍵字引數,因為你仔細看看auth_user表的話,你會發現使用者名稱和密碼的欄位名稱就是username和password。

    如果認證成功(使用者名稱和密碼正確有效,就是去auth_user表中查詢一下是否存在這條記錄),便會返回一個 User 物件,查詢認證失敗返回None。

    authenticate()會在該 User 物件上設定一個屬性來標識後端已經認證了該使用者,且該資訊在後續的登入過程中是需要的。

    用法:

user = auth.authenticate(username='theuser',password='thepassword')

  

login(HttpRequest, user)  

    該函式接受一個HttpRequest物件,以及一個經過認證的User物件。

    該函式實現一個使用者登入的功能。它本質上會在後端為該使用者生成相關session資料,保持會話用。

    用法:

from django.contrib.auth import authenticate, login
   
def my_view(request):
  username = request.POST['username']
  password = request.POST['password']
  user_obj = authenticate(username=username, password=password)
  if user_obj:
    login(request, user_obj) #可以簡單理解為request.session['user_id']=user_id,並且將user_obj封裝到了request裡面,通過request.user=user_obj
    # Redirect to a success page.
    ...
  else:
    # Return an 'invalid login' error message.
    ...

    注意:

      只要使用login(request, user_obj)之後,request.user就能拿到當前登入的使用者物件。否則request.user得到的是一個匿名使用者物件(AnonymousUser Object,是request.user的預設值),這個匿名使用者的狀態在我的檢視函式部落格的那個request那一節有介紹,都是空。

      詳細原理請檢視 AuthenticationMiddleware 中介軟體原始碼。

        使用login方法之前,列印user的狀態

def index(request):
    print(request.user) #沒有經過login方法來封裝使用者的資訊,那麼這個顯示的是一個匿名使用者
    print(request.user.id) #None
    print(request.user.username) #空的
    print(request.user.is_active) #False
    return render(request,'index.html')

        使用login方法之後,列印user的狀態

def index(request):
    print(request.user) #chao,request.user物件本身是全域性的,是當前登陸的user物件,並且可以在模板語言裡面直接使用{{ request.user.username }},萬能的句點號
    print(request.user.id) #1  #通過id、username等可以判斷使用者是否登陸了,但是一般我們都用後面要學的is_authenticated()方法來進行判斷。
    print(request.user.username) #chao
    print(request.user.is_active) #True
    return render(request,'index.html')

logout(request)

    該函式接受一個HttpRequest物件,無返回值。

    當呼叫該函式時,當前請求的session資訊會全部清除。該使用者即使沒有登入,使用該函式也不會報錯。

    用法:

from django.contrib.auth import logout
   
def logout_view(request):
  logout(request) #其實內部就是執行了request.session.flush()
  # Redirect to a success page.

  關於User表的擴充套件閱讀內容(目前作為了解)

Django內建的User模型雖然已經足夠強大了。但是有時候還是不能滿足我們的需求。比如在驗證使用者登入的時候,他用的是使用者名稱作為驗證,而我們有時候需要通過手機號碼或者郵箱來進行驗證。還有比如我們想要增加一些新的欄位。那麼這時候我們就需要擴充套件使用者模型了。擴充套件使用者模型有多種方式。這裡我們來一一討論下。

1. 設定Proxy模型:
作用: 給模型增加操作方法

侷限: 不能增加或減少User模型的欄位

好處: 不破壞原來的User模型的表結構

如果你對Django提供的欄位,以及驗證的方法都比較滿意,沒有什麼需要改的。但是隻是需要在他原有的基礎之上增加一些操作的方法。那麼建議使用這種方式。示例程式碼如下:

# models.py
class Person(User):
    # 如果模型是一個代理模型
    # 那麼就不能在這個模型中新增新的Field
    # telephone = models.CharField(max_length=11)  # 錯誤寫法
    class Meta:
        proxy = True
 
    # proxy正確用法是給模型新增自定義方法
    # 如新增列出黑名單的方法
    def get_blacklist(self):
        return self.objects.filter(is_active=False)
在以上,我們定義了一個Person類,讓他繼承自User,並且在Meta中設定proxy=True,說明這個只是User的一個代理模型。他並不會影響原來User模型在資料庫中表的結構。以後如果你想方便的獲取所有黑名單的人,那麼你就可以通過Person.get_blacklist()就可以獲取到。並且User.objects.all()和Person.objects.all()其實是等價的。因為他們都是從User這個模型中獲取所有的資料。

2. 一對一外來鍵:
作用: 給模型增加新的欄位, 新方法

侷限: 只能增加, 不能減少欄位, 不能修改戶驗證方法: authenticate

好處: 不破壞原來的User模型的表結構

如果你對使用者驗證方法authenticate沒有其他要求,就是使用username和password即可完成。但是想要在原來模型的基礎之上新增新的欄位,那麼可以使用一對一外來鍵的方式。示例程式碼如下:

# models.py
from django.contrib.auth.models import User
from django.db import models
from django.dispatch import receiver
from django.db.models.signals import post_save
 
class UserExtension(models.Model):
    user = models.OneToOneField(User,on_delete=models.CASCADE,related_name='extension')
    birthday = models.DateField(null=True,blank=True)
    school = models.CharField(max_length=100)
 
 
@receiver(post_save,sender=User)
def create_user_extension(sender,instance,created,**kwargs):
    if created:
        UserExtension.objects.create(user=instance)
    else:
        instance.extension.save()
以上定義一個UserExtension的模型,並且讓她和User模型進行一對一的繫結,以後我們新增的欄位,就新增到UserExtension上。並且還寫了一個接受儲存模型的訊號處理方法,只要是User呼叫了save方法,那麼就會建立一個UserExtension和User進行繫結。

# views.py
from django.contrib.auth.models import User
from django.http import HttpResponse
 
 
def one_to_one_view(request):
    user = User.objects.create_user(username='Tom',email='[email protected]',password='111111')
    # 給擴充套件的欄位設定值
    user.extension.school = 'Harvard'
    user.save()
    return HttpResponse('一對一擴充套件User模型')
3. 繼承自AbstractUser:
作用: 給模型增加新的欄位, 修改戶驗證方法: authenticate

侷限: 只能增加, 不能減少欄位

壞處: 破壞了原來的User模型的表結構

對於authenticate不滿意,並且不想要修改原來User物件上的一些欄位,但是想要增加一些欄位,那麼這時候可以直接繼承自django.contrib.auth.models.AbstractUser,其實這個類也是django.contrib.auth.models.User的父類。比如我們想要在原來User模型的基礎之上新增一個telephone和school欄位。示例程式碼如下:

# models.py
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
    telephone = models.CharField(max_length=11,unique=True)
    school = models.CharField(max_length=100)
    # 指定telephone作為USERNAME_FIELD, 而不是原來的username欄位, 所以username要重寫
    username = models.CharField(max_length=150)
 
    # 指定telephone作為USERNAME_FIELD,以後使用authenticate
    # 函式驗證的時候,就可以根據telephone來驗證
    # 而不是原來的username
    USERNAME_FIELD = 'telephone'
    # USERNAME_FIELD對應的'telephone'欄位和密碼欄位預設是必須的欄位
    # 下[]可以新增其它必須的欄位, 比如['username', 'email']
    REQUIRED_FIELDS = []
 
    # 重新定義Manager物件,在建立user的時候使用telephone和
    # password,而不是使用username和password
    objects = UserManager()
 
 
# 重寫UserManager
class UserManager(BaseUserManager):
    use_in_migrations = True
 
    def _create_user(self, telephone, password, **extra_fields):
        if not telephone:
            raise ValueError("請填入手機號碼!")
        if not password:
            raise ValueError("請填入密碼!")
        user = self.model(telephone=telephone, **extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        return user
 
    def create_user(self, telephone, password, **extra_fields):
        extra_fields.setdefault('is_staff', False)
        extra_fields.setdefault('is_superuser', False)
        return self._create_user(telephone, password, **extra_fields)
 
    def create_superuser(self, telephone, password, **extra_fields):
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)
 
        if extra_fields.get('is_staff') is not True:
            raise ValueError('Superuser must have is_staff=True.')
        if extra_fields.get('is_superuser') is not True:
            raise ValueError('Superuser must have is_superuser=True.')
 
        return self._create_user(telephone, password, **extra_fields)
然後再在settings中配置好

# settings.py
AUTH_USER_MODEL = 'youappname.User'
這種方式因為破壞了原來User模型的表結構,所以必須要在第一次migrate前就先定義好。

4. 繼承自AbstractBaseUser模型:
作用: 給模型增加或減少欄位, 修改戶驗證方法: authenticate

壞處: 破壞了原來的User模型的表結構

注意: 繼承自AbstractBaseUser同時還要繼承PermissionsMixin

如果你想修改預設的驗證方式,並且對於原來User模型上的一些欄位不想要,那麼可以自定義一個模型,然後繼承自AbstractBaseUser,再新增你想要的欄位。這種方式會比較麻煩,最好是確定自己對Django比較瞭解才推薦使用。步驟如下:

建立模型。示例程式碼如下:

# models.py
from django.contrib.auth.base_user import AbstractBaseUser
from django.contrib.auth.models import PermissionsMixin
from django.db import models
 
 
class User(AbstractBaseUser,PermissionsMixin):
     email = models.EmailField(unique=True)
     username = models.CharField(max_length=150)
     telephone = models.CharField(max_length=11,unique=True)
     is_staff = models.BooleanField(default=False)
     is_active = models.BooleanField(default=True)
 
     USERNAME_FIELD = 'telephone'
     REQUIRED_FIELDS = []
 
    # 這裡的UserManager同方法3, 需要重寫
     objects = UserManager()
 
     def get_full_name(self):
         return self.username
 
     def get_short_name(self):
         return self.username
其中password和last_login是在AbstractBaseUser中已經新增好了的,我們直接繼承就可以了。然後我們再新增我們想要的欄位。比如email、username、telephone等。這樣就可以實現自己想要的欄位了。但是因為我們重寫了User,所以應該儘可能的模擬User模型:

USERNAME_FIELD:用來描述User模型名字欄位的字串,作為唯一的標識。如果沒有修改,那麼會使用USERNAME來作為唯一欄位。
REQUIRED_FIELDS:一個欄位名列表,用於當通過createsuperuser管理命令建立一個使用者時的提示。
is_active:一個布林值,用於標識使用者當前是否可用。
get_full_name():獲取完整的名字。
get_short_name():一個比較簡短的使用者名稱。
重新定義UserManager:我們還需要定義自己的UserManager,因為預設的UserManager在建立使用者的時候使用的是username和password,那麼我們要替換成telephone。示例程式碼如下:

# models.py
from django.contrib.auth.base_user import BaseUserManager
 
 
# 重寫UserManager
class UserManager(BaseUserManager):
    use_in_migrations = True
 
    def _create_user(self, telephone, password, **extra_fields):
        if not telephone:
            raise ValueError("請填入手機號碼!")
        if not password:
            raise ValueError("請填入密碼!")
        user = self.model(telephone=telephone, **extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        return user
 
    def create_user(self, telephone, password, **extra_fields):
        extra_fields.setdefault('is_staff', False)
        extra_fields.setdefault('is_superuser', False)
        return self._create_user(telephone, password, **extra_fields)
 
    def create_superuser(self, telephone, password, **extra_fields):
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)
 
        if extra_fields.get('is_staff') is not True:
            raise ValueError('Superuser must have is_staff=True.')
        if extra_fields.get('is_superuser') is not True:
            raise ValueError('Superuser must have is_superuser=True.')
 
        return self._create_user(telephone, password, **extra_fields)
 

在建立了新的User模型後,還需要在settings中配置好。配置AUTH_USER_MODEL='appname.User'。

# settings.py
AUTH_USER_MODEL = 'youappname.User'
 

如何使用這個自定義的模型:比如以後我們有一個Article模型,需要通過外來鍵引用這個User模型,那麼可以通過以下兩種方式引用。
第一種就是直接將User匯入到當前檔案中。示例程式碼如下:

# models.py
from django.db import models
 from myauth.models import User
 class Article(models.Model):
     title = models.CharField(max_length=100)
     content = models.TextField()
     author = models.ForeignKey(User, on_delete=models.CASCADE)
這種方式是可以行得通的。但是為了更好的使用性,建議還是將User抽象出來,使用settings.AUTH_USER_MODEL來表示。示例程式碼如下:

# models.py
from django.db import models
 from django.conf import settings
 class Article(models.Model):
     title = models.CharField(max_length=100)
     content = models.TextField()
     author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
這種方式因為破壞了原來User模型的表結構,所以必須要在第一次migrate前就先定義好。

二 User物件

  User 物件屬性:username, password(必填項)password用雜湊演算法儲存到資料庫

user物件的 is_authenticated()

    如果是真正的 User 物件,返回值恆為 True 。 用於檢查使用者是否已經通過了認證。
    通過認證並不意味著使用者擁有任何許可權,甚至也不檢查該使用者是否處於啟用狀態,這只是表明使用者成功的通過了認證。 這個方法很重要, 在後臺用request.user.is_authenticated()判斷使用者是否已經登入,如果true則可以向前臺展示request.user.name

    要求:

      1 使用者登陸後才能訪問某些頁面,

      2 如果使用者沒有登入就訪問該頁面的話直接跳到登入頁面

      3 使用者在跳轉的登陸介面中完成登陸後,自動訪問跳轉到之前訪問的地址

    方法1:

def my_view(request):
  if not request.user.is_authenticated():
    return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))

    方法2:

      django已經為我們設計好了一個用於此種情況的裝飾器:login_requierd()

from django.contrib.auth.decorators import login_required
      
@login_required
def my_view(request):
  ...

    若使用者沒有登入,則會跳轉到django預設的 登入URL '/accounts/login/ ' (這個值可以在settings檔案中通過LOGIN_URL進行修改)。並傳遞 當前訪問url的絕對路徑 (登陸成功後,會重定向到該路徑)。

login_requierd()

    auth 給我們提供的一個裝飾器工具,用來快捷的給某個檢視新增登入校驗。

    用法:

from django.contrib.auth.decorators import login_required
      
@login_required
def my_view(request):
  ...

    若使用者沒有登入,則會跳轉到django預設的 登入URL '/accounts/login/ ' 並傳遞當前訪問url的絕對路徑 (登陸成功後,會重定向到該路徑)。

    如果需要自定義登入的URL,則需要在settings.py檔案中通過LOGIN_URL進行修改。

    示例:

LOGIN_URL = '/login/'  # 這裡配置成你專案登入頁面的路由

  

create_user()

    auth 提供的一個建立新使用者的方法,需要提供必要引數(username、password)等。

    用法:

from django.contrib.auth.models import User
user = User.objects.create_user(username='使用者名稱',password='密碼',email='郵箱',...)

  

create_superuser()

    auth 提供的一個建立新的超級使用者的方法,需要提供必要引數(username、password)等。

    用法:

from django.contrib.auth.models import User
user_obj = User.objects.create_superuser(username='使用者名稱',password='密碼',email='郵箱',...)

check_password(raw_password)(瞭解)

    auth 提供的一個檢查密碼是否正確的方法,需要提供當前請求使用者的密碼。

    密碼正確返回True,否則返回False。

    用法:

ok = user_obj.check_password('密碼')

    或者直接針對當前請求的user物件校驗原密碼是否正確:

ok = request.user.check_password(raw_password='原密碼')

set_password(raw_password)

    auth 提供的一個修改密碼的方法,接收 要設定的新密碼 作為引數。

    注意:設定完一定要呼叫使用者物件的save方法!!!

    用法:

user_obj.set_password('新密碼')  #user_obj其實就是request.user
user_obj.save()                 #request.user.save()

  

  使用者物件的屬性

    user_obj能夠拿到認證所用使用者表的資料屬性,比如username, password等。

    其他常用屬性含義如下:

      is_staff : 使用者是否擁有網站的管理許可權.

      is_active : 是否允許使用者登入, 設定為 False,可以在不刪除使用者的前提下禁止使用者登入。

  簡單示例:

    註冊:

def sign_up(request):
 
    state = None
    if request.method == 'POST':
 
        password = request.POST.get('password', '')
        repeat_password = request.POST.get('repeat_password', '')
        email=request.POST.get('email', '')
        username = request.POST.get('username', '')
        if User.objects.filter(username=username):
                state = 'user_exist'
        else:
                new_user = User.objects.create_user(username=username, password=password,email=email)
                new_user.save()
 
                return redirect('/book/')
    content = {
        'state': state,
        'user': None,
    }
    return render(request, 'sign_up.html', content)  

    修改密碼:

@login_required
def set_password(request):
    user = request.user
    state = None
    if request.method == 'POST':
        old_password = request.POST.get('old_password', '')
        new_password = request.POST.get('new_password', '')
        repeat_password = request.POST.get('repeat_password', '') 
        if user.check_password(old_password): #校驗老密碼是否正確
            if not new_password:
                state = 'empty'
            elif new_password != repeat_password:
                state = 'repeat_error'
            else:
                user.set_password(new_password)
                user.save()
                return redirect("/log_in/")
        else:
            state = 'password_error'
    content = {
        'user': user,
        'state': state,
    }
    return render(request, 'set_password.html', content)

  

  留個作業吧:給圖書館裡系統新增一個登陸註冊功能。

三 擴充套件預設的auth_user表

  這內建的認證系統這麼好用,但是auth_user表字段都是固定的那幾個,我在專案中沒法拿來直接使用啊!

  比如,我想要加一個儲存使用者手機號的欄位,怎麼辦?

  聰明的你可能會想到新建另外一張表然後通過一對一和內建的auth_user表關聯,這樣雖然能滿足要求但是有沒有更好的實現方式呢?

  答案是當然有了。

  我們可以通過繼承內建的 AbstractUser 類,來定義一個自己的Model類。django給我們自動建立的一張user表,而如果要用auth模組,就必須要使用(或繼承)這張表。

  這樣既能根據專案需求靈活的設計使用者表,又能使用Django強大的認證系統了。繼承表的好處是我們可以增加一些自己需要的欄位,並且同時可以使用auth模組提供的介面、方法

from django.contrib.auth.models import AbstractUser
class UserInfo(AbstractUser):
    """
    使用者資訊表
    """
    nid = models.AutoField(primary_key=True)
    phone = models.CharField(max_length=11, null=True, unique=True)
    
    def __str__(self):
        return self.username

  需要注意的是,UserInfo表裡就不需要有auth_user裡重複的欄位了,比如說username以及password等,但是還是可以直接使用這些欄位的,並且django會自動將password進行加密

  按上面的方式擴充套件了內建的auth_user表之後,一定要在settings.py中告訴Django,我現在使用我新定義的UserInfo表來做使用者認證。寫法如下:

# 引用Django自帶的User表,繼承使用時需要設定,這樣django就知道從我們的app名的應用下的models檔案中去查詢UserInfo這張表了
AUTH_USER_MODEL = "app名.UserInfo"

  自定義認證系統預設使用的資料表之後,我們就可以像使用預設的auth_user表那樣使用我們的UserInfo表了。比如:

  建立普通使用者:

UserInfo.objects.create_user(username='使用者名稱', password='密碼')

  建立超級使用者:

UserInfo.objects.create_superuser(username='使用者名稱', password='密碼')

  再次注意:

    一旦我們指定了新的認證系統所使用的表,我們就需要重新在資料庫中建立該表,而不能繼續直接使用原來預設的auth_user表了。

四 xxx

程式碼示例:

views.py內容如下

from django.shortcuts import render,HttpResponse,redirect
from django.urls import reverse
from crm import models
# Create your views here.

#1.引入auth認證元件來操作django的auth_user表
from django.contrib import auth

def login(request):
    if request.method == 'GET':
        return render(request, 'login.html')
    else:
        user = request.POST.get('user')
        pwd = request.POST.get('pwd')
        print(user, pwd)
        #2.authenticate方法回去auth_user表中查詢記錄,查詢成功返回使用者物件,查詢失敗返回None
        user_obj = auth.authenticate(username=user,password=pwd)
        if user_obj:
            #3.儲存使用者的狀態資訊,之前我們儲存到了session表中,現在也是儲存到裡面,但是通過一個auth模組的login方法就搞定了,然後重定向到首頁index
            auth.login(request,user_obj) #做的事情request.session["user_id"] = user_obj.pk,還加了一些其他的內容,先不用管他其他的內容,還做了一個事情就是request.user = user_obj當前登陸物件

            # return redirect('index') #不寫reverse也行
            return redirect(reverse('index'))


        else:
            return redirect(reverse('login'))


from django.contrib.auth.decorators import login_required
@login_required
def index(request):
    #關於這個預設的匿名使用者,看一下我的django的檢視系統的那個部落格,有相關介紹
    print(request.user) #沒有經過login方法來封裝使用者的資訊,那麼這個顯示的是一個匿名使用者
    print(request.user.id) #None
    print(request.user.is_superuser) #False
    print(request.user.username) #空的
    print(request.user.is_active) #False

    # if not request.user.id: #還有一個驗證是否登陸的方法,request.user.is_authenticated(),常用的是這個方法
    # if not request.user.is_authenticated(): #還有一個驗證是否登陸的方法,request.user.is_authenticated(),常用的是這個方法
    #     return redirect('login')

    return render(request,'index.html')

def logout(request):
    auth.logout(request) #其實就是和咱們django提供的session做的事情差不多

    return redirect('login')


#註冊
#註冊就是要往django的auth_user表中新增一條記錄,所以要想操作User表必須先引入user表,這個auth_user表是auth這個內建應用的表,所以django生成表的時候,表名字是應用名_表名,所以其實表名為User表
#引入Uset表
from django.contrib.auth.models import User
def register(request):

    if request.method == 'GET':

        return render(request,'register.html')

    else:
        user = request.POST.get('user')
        pwd = request.POST.get('pwd')

        # User.objects.create()  #create方法也能插入資料,但是密碼是明文的
        User.objects.create_user(username=user,password=pwd)  #建立普通使用者
        # User.objects.create_superuser(username=user,password=pwd)  #建立超級使用者
        #create_user()和create_superuser()他們兩個區別在admin應用裡面能夠體現出來,但是其實在生成的表記錄裡面唯一的區別就是那個is_superuser的欄位值不同,如果是create_user()方法建立的使用者,那麼is_superuser的值為False,如果是create_superuser()方法建立的使用者,那麼is_superuser的值為True,所以我們可以通過這個字不同的值來判斷使用者是否為管理員啊等操作,這兩個方法的username=user,password=pwd,兩個引數是必須要給的
        return redirect('login')


def set_password(request):
    request.user.set_password(666)
    request.user.save()

    return redirect('login')

urls.py內容如下

from django.conf.urls import url
from django.contrib import admin
from crm import views
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    #登陸
    url(r'^login/', views.login,name='login'),
    url(r'^index/', views.index,name='index'),
    #登出、退出
    url(r'^logout/', views.logout,name='logout'),
    #註冊
    url(r'^register/', views.register,name='register'),
    #修改密碼
    url(r'^set_password/', views.set_password,name='set_password'),


]

index.html內容如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h1>
    這是index頁面
    {{ request.user.username }}
</h1>
<div>
    <a href="{% url 'logout' %}">退出</a>
</div>
<div>
    <a href="{% url 'set_password' %}">修改密碼</a>
</div>

</body>
</html>

login.html內容如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<form action="" method="post">
    {% csrf_token %}
    <input type="text" name="user">
    <input type="password" name="pwd">
    <input type="submit">
</form>

</body>
</html>

  register.html內容如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<form action="{% url 'register' %}" method="post">
    {% csrf_token %}
    <input type="text" name="user">
    <input type="password" name="pwd">
    <input type="submit">
</form>

</body>
</html>

  settings.py檔案中有一個認證裝飾器@login_required需要用的一個配置項:

LOGIN_URL = '/login/' #配置裝飾器跳轉的登陸的url