Django Tutorial Part 8: User authentication and permissions

2018-05-15 17:26 更新
先決條件: 完成所有以前的教學(xué)課題,最多包括 Django教程第7部分:會話框架。
目的: 了解如何設(shè)置和使用用戶身份驗證和權(quán)限。

概述

Django提供了一個認(rèn)證和授權(quán)("權(quán)限")系統(tǒng),該系統(tǒng)構(gòu)建在上一個教程中討論的會話框架之上,允許您驗證用戶憑據(jù) 并定義每個用戶允許執(zhí)行的操作。 該框架包括 Users Groups (一次向多個用戶應(yīng)用權(quán)限的通用方法)的內(nèi)置模型,用于指定用戶 可以執(zhí)行用于登錄用戶的任務(wù),表單和視圖,以及用于限制內(nèi)容的查看工具。

注意:根據(jù)Django,認(rèn)證系統(tǒng)旨在非常通用,因此不提供其他Web認(rèn)證系統(tǒng)中提供的一些功能。 一些常見問題的解決方案可用作第三方包。 例如,限制登錄嘗試和針對第三方的身份驗證(例如OAuth)。

在本教程中,我們將向您介紹如何在 LocalLibrary 中啟用用戶身份驗證, a>網(wǎng)站,創(chuàng)建您自己的登錄和注銷頁面,為您的模型添加權(quán)限,以及控制對頁面的訪問。 我們將使用身份驗證/權(quán)限來顯示為用戶和圖書館員借用的圖書列表。

認(rèn)證系統(tǒng)非常靈活,您可以從頭開始構(gòu)建您的URL,表單,視圖和模板,只需調(diào)用提供的API登錄用戶即可。 但是,在本文中,我們將使用Django的"stock"認(rèn)證視圖和表單登錄和注銷頁面。 我們?nèi)匀恍枰獎?chuàng)建一些模板,但這很容易。

我們還將向您展示如何創(chuàng)建權(quán)限,并檢查視圖和模板中的登錄狀態(tài)和權(quán)限。

啟用身份驗證

當(dāng)我們創(chuàng)建骨架網(wǎng)站(在教程2中)時,會自動啟用身份驗證,因此您無需在此時再執(zhí)行任何操作。

注意:當(dāng)我們使用 django-admin startproject 命令創(chuàng)建應(yīng)用程序時,所有必要的配置都已完成。 當(dāng)我們第一次調(diào)用 python manage.py migrate 時,創(chuàng)建了用戶和模型權(quán)限的數(shù)據(jù)庫表。

配置在項目文件( locallibrary / locallibrary / settings.py )的 INSTALLED_APPS MIDDLEWARE 部分中設(shè)置,如下所示:

INSTALLED_APPS = [
    ...
? ? 'django.contrib.auth',  #Core authentication framework and its default models.
? ? 'django.contrib.contenttypes',  #Django content type system (allows permissions to be associated with models).
    ....

MIDDLEWARE = [
    ...
? ? 'django.contrib.sessions.middleware.SessionMiddleware',  #Manages sessions across requests
    ...
? ? 'django.contrib.auth.middleware.AuthenticationMiddleware',  #Associates users with requests using sessions.
    ....

創(chuàng)建用戶和組

當(dāng)我們在教程4中查看 Django管理網(wǎng)站時,您已經(jīng)創(chuàng)建了第一個用戶(這是一個超級用戶,使用命令 python manage創(chuàng)建)。 py createsuperuser)。 我們的超級用戶已經(jīng)通過身份驗證并擁有所有權(quán)限,因此我們需要創(chuàng)建一個測試用戶來代表一個正常的網(wǎng)站用戶。 我們將使用管理網(wǎng)站創(chuàng)建我們的 locallibrary 組和網(wǎng)站登錄,因為它是最快的方式之一。

注意:您也可以以編程方式創(chuàng)建用戶,如下所示。 你必須這樣做,例如,如果開發(fā)一個接口,允許用戶創(chuàng)建自己的登錄(你不應(yīng)該給用戶訪問管理站點)。

from django.contrib.auth.models import User

# Create user and save to the database
user = User.objects.create_user('myusername', 'myemail@crazymail.com', 'mypassword')

# Update fields and then save again
user.first_name = 'John'
user.last_name = 'Citizen'
user.save()

下面我們先創(chuàng)建一個組,然后創(chuàng)建一個用戶。 即使我們沒有任何權(quán)限為我們的庫成員添加,如果我們需要以后,它會更容易一次添加到組,而不是單獨給每個成員。

啟動開發(fā)服務(wù)器,并導(dǎo)航到本地網(wǎng)絡(luò)瀏覽器中的管理網(wǎng)站( http://127.0.0.1:8000/ admin / )。 使用您的超級用戶帳戶的憑據(jù)登錄到網(wǎng)站。 管理網(wǎng)站的頂層顯示所有模型,按"django應(yīng)用程序"排序。 驗證和授權(quán)部分中,您可以點擊用戶網(wǎng)上論壇鏈接查看其現(xiàn)有記錄。

; width:661px;">

首先讓我們?yōu)閹斐蓡T創(chuàng)建一個新的組。

  1. Click the Add button (next to Group) to create a new Group; enter the Name "Library Members" for the group.
  2. We don't need any permissions for the group, so just press SAVE (you will be taken to a list of groups).

現(xiàn)在讓我們創(chuàng)建一個用戶:

  1. Navigate back to the home page of the admin site
  2. Click the Add button next to Users to open the Add user dialog.
  3. Enter an appropriate Username and Password/Password confirmation for your test user
  4. Press SAVE to create the user.

    The admin site will create the new user and immediately take you to a Change user screen where you can change your username and add information for the User model's optional fields. These fields include the first name, last name, email address, the users status and permissions (only the Active flag should be set). Further down you can specify the user's groups and permissions, and see important dates related to the user (e.g. their join date and last login date).
  5. In the Groups section, select Library Member group from the list of Available groups, and then press the right-arrow between the boxes to move it into the Chosen groups box.
  6. We don't need to do anything else here, so just select SAVE again, to go to the list of users.

而已!。 現(xiàn)在你有一個"正常的庫成員"帳戶,你將能夠用于測試(一旦我們實現(xiàn)了頁面,使他們能夠登錄)。

注意:您應(yīng)該嘗試創(chuàng)建其他庫成員用戶。 另外,為圖書館員創(chuàng)建一個組,并向其添加一個用戶!

設(shè)置您的身份驗證視圖

Django提供了幾乎所有你需要創(chuàng)建的認(rèn)證頁面來處理登錄,注銷和密碼管理"開箱即用"。 這包括一個url映射器,視圖和表單,但它不包括模板 - 我們必須創(chuàng)建自己的!

在本節(jié)中,我們將介紹如何將默認(rèn)系統(tǒng)集成到LocalLibrary網(wǎng)站并創(chuàng)建模板。 我們將它們放在主項目URL中。

注意:您不必使用任何此類代碼,但很可能是您想要的,因為它使事情變得更容易。 如果您更改用戶模型(高級主題!),您幾乎肯定需要更改表單處理代碼,但即使如此,您仍然可以使用股票視圖功能。

請注意:在這種情況下,我們可以合理地將驗證頁(包括網(wǎng)址和模板)放入我們的目錄應(yīng)用程序中。 但是,如果我們有多個應(yīng)用程序,最好分離出這種共享登錄行為,并使其可用于整個網(wǎng)站,這是我們在這里顯示的!

項目網(wǎng)址

將以下內(nèi)容添加到項目urls.py文件( locallibrary / locallibrary / urls.py )文件的底部:

#Add Django site authentication urls (for login, logout, password management)
urlpatterns += [
    url('^accounts/', include('django.contrib.auth.urls')),
]

導(dǎo)航到 http://127.0.0.1:8000/accounts/ 網(wǎng)址(請注意尾部正斜杠 !)和Django將顯示一個錯誤,它找不到這個URL,并列出了所有的URL。 從中可以看到可以工作的網(wǎng)址,例如:

^accounts/ ^login/$ [name='login']
^accounts/ ^logout/$ [name='logout']
^accounts/ ^password_change/$ [name='password_change']
^accounts/ ^password_change/done/$ [name='password_change_done']
^accounts/ ^password_reset/$ [name='password_reset']
^accounts/ ^password_reset/done/$ [name='password_reset_done']
^accounts/ ^reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$ [name='password_reset_confirm']
^accounts/ ^reset/done/$ [name='password_reset_complete']

現(xiàn)在,嘗試導(dǎo)航到登錄網(wǎng)址( http://127.0.0.1:8000/accounts/login/ / a>)。 此操作會再次失敗,但出現(xiàn)錯誤,告知您我們在模板搜索路徑中缺少必需的模板( registration / login.html )。 您會在頂部的黃色部分看到以下行:

Exception Type:    TemplateDoesNotExist
Exception Value:    registration/login.html

下一步是在搜索路徑上創(chuàng)建注冊目錄,然后添加 login.html 文件。

模板目錄

我們剛才添加的url(和隱式視圖)希望在模板搜索路徑中的某個位置的 / registration / 目錄中找到它們相關(guān)的模板。 對于此網(wǎng)站,我們會將模板放置在 templates / registration / 目錄中(即將模板放置在最上層目錄 locallibrary 文件夾) - 請立即創(chuàng)建模板和注冊目錄。

要使這些目錄對模板加載器可見(即將此目錄放在模板搜索路徑中),請打開項目設(shè)置( /locallibrary/locallibrary/settings.py ),然后更新 TEMPLATES 部分的\'DIRS\'行,如圖所示。

TEMPLATES = [
    {
        ...
        'DIRS': ['./templates',],
        'APP_DIRS': True,
        ...

登錄模板

重要:本文中提供的身份驗證模板是Django演示登錄模板的非常基本/稍微修改的版本。 您可能需要自定義它們?yōu)槟约菏褂茫?/span>

創(chuàng)建一個名為/ locallibrary / templates / registration / login.html 的新HTML文件。 給它以下內(nèi)容:

{% extends "base_generic.html" %}

{% block content %}

{% if form.errors %}
<p>Your username and password didn't match. Please try again.</p>
{% endif %}

{% if next %}
? ? {% if user.is_authenticated %}
? ? <p>Your account doesn't have access to this page. To proceed,
? ? please login with an account that has access.</p>
? ? {% else %}
? ? <p>Please login to see this page.</p>
? ? {% endif %}
{% endif %}

<form method="post" action="{% url 'login' %}">
{% csrf_token %}

<div>
? <td>{{ form.username.label_tag }}</td>
? <td>{{ form.username }}</td>
</div>
<div>
? <td>{{ form.password.label_tag }}</td>
? <td>{{ form.password }}</td>
</div>

<div>
? <input type="submit" value="login" />
? <input type="hidden" name="next" value="" />
</div>
</form>

{# Assumes you setup the password_reset view in your URLconf #}
<p><a href="{% url 'password_reset' %}">Lost password?</a></p>

{% endblock %}

此模板與我們之前看到的模板有一些相似之處 - 它擴展了我們的基本模板,并覆蓋了 content 塊。 其余的代碼是相當(dāng)標(biāo)準(zhǔn)的表單處理代碼,我們將在后面的教程中討論。 您現(xiàn)在需要知道的是,這將顯示一個窗體,您可以在其中輸入您的用戶名和密碼,如果您輸入無效的值,將提示您在頁面刷新時輸入正確的值。

返回登錄頁面( http://127.0.0.1:8000/accounts/login/ >),一旦您保存了模板,您應(yīng)該看到這樣:

; width:441px;">

如果您嘗試登錄將成功,您將被重定向到另一個頁面(默認(rèn)情況下,這將是 http ://127.0.0.1:8000 / accounts / profile / )。 這里的問題是,默認(rèn)情況下Django期望在登錄后,你會想要到一個配置文件頁面,這可能是或不是這種情況。 由于您尚未定義此網(wǎng)頁,因此您會收到另一個錯誤訊息!

打開項目設(shè)置( /locallibrary/locallibrary/settings.py ),然后將下面的文字添加到底部。 現(xiàn)在,當(dāng)您登錄時,您應(yīng)該被重定向到網(wǎng)站主頁默認(rèn)情況下。

# Redirect to home URL after login (Default redirects to /accounts/profile/)
LOGIN_REDIRECT_URL = '/'

注銷模板

如果您導(dǎo)航到注銷網(wǎng)址( http://127.0.0.1:8000/accounts/logout/ a>),那么您會看到一些奇怪的行為 - 您的用戶將被確實注銷,但您會轉(zhuǎn)到管理注銷頁面。 這不是你想要的,如果只是因為該頁面上的登錄鏈接會轉(zhuǎn)到管理員登錄屏幕(只有擁有 is_staff 權(quán)限的用戶才能使用)。

創(chuàng)建并打開/ locallibrary / templates / registration / logged_out.html 。 在下面的文本中復(fù)制:

{% extends "base_generic.html" %}

{% block content %}
<p>Logged out!</p>  

<a href="{% url 'login'%}">Click here to login again.</a>
{% endblock %}

這個模板很簡單。 它只是顯示一條消息,通知您已注銷,并提供一個鏈接,您可以按返回登錄屏幕。 如果再次訪問注銷URL,您應(yīng)該會看到此頁面:

; width:385px;">

密碼重置模板

默認(rèn)密碼重置系統(tǒng)使用電子郵件向用戶發(fā)送重置鏈接。 您需要創(chuàng)建表單以獲取用戶的電子郵件地址,發(fā)送電子郵件,允許他們輸入新密碼,并在整個過程完成時注意。

以下模板可用作起點。

Password reset form

這是用于獲取用戶的電子郵件地址(用于發(fā)送密碼重置電子郵件)的表單。 創(chuàng)建 /locallibrary/templates/registration/password_reset_form.html ,并提供以下內(nèi)容:

{% extends "base_generic.html" %}
{% block content %}

<form action="" method="post">{% csrf_token %}
    {% if form.email.errors %} {{ form.email.errors }} {% endif %}
        <p>{{ form.email }}</p> 
    <input type="submit" class="btn btn-default btn-lg" value="Reset password" />
</form>

{% endblock %}

Password reset done

此表單在您的電子郵件地址收集后顯示。 創(chuàng)建 /locallibrary/templates/registration/password_reset_done.html ,并提供以下內(nèi)容:

{% extends "base_generic.html" %}
{% block content %}
<p>We've emailed you instructions for setting your password. If they haven't arrived in a few minutes, check your spam folder.</p>
{% endblock %}

Password reset email

此模板提供了我們將發(fā)送給用戶的HTML電子郵件的文本,其中包含重置鏈接。 創(chuàng)建 /locallibrary/templates/registration/password_reset_email.html ,并提供以下內(nèi)容:

Someone asked for password reset for email {{ email }}. Follow the link below:
{{ protocol}}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}

Password reset confirm

此頁面是您在單擊密碼重置電子郵件中的鏈接后輸入新密碼的位置。 創(chuàng)建 /locallibrary/templates/registration/password_reset_confirm.html ,并提供以下內(nèi)容:

{% extends "base_generic.html" %}

{% block content %}

    {% if validlink %}
        <p>Please enter (and confirm) your new password.</p>
        <form action="" method="post">
            <div style="display:none">
                <input type="hidden" value="{{ csrf_token }}" name="csrfmiddlewaretoken">
            </div>
            <table>
                <tr>
                    <td>{{ form.new_password1.errors }}
                        <label for="id_new_password1">New password:</label></td>
                    <td>{{ form.new_password1 }}</td>
                </tr>
                <tr>
                    <td>{{ form.new_password2.errors }}
                        <label for="id_new_password2">Confirm password:</label></td>
                    <td>{{ form.new_password2 }}</td>
                </tr>
                <tr>
                    <td></td>
                    <td><input type="submit" value="Change my password" /></td>
                </tr>
            </table>
        </form>
    {% else %}
        <h1>Password reset failed</h1>
        <p>The password reset link was invalid, possibly because it has already been used. Please request a new password reset.</p>
    {% endif %}

{% endblock %}

Password reset complete

這是最后一個密碼重置模板,顯示該模板以在密碼重置成功時通知您。 創(chuàng)建 /locallibrary/templates/registration/password_reset_complete.html ,并提供以下內(nèi)容:

{% extends "base_generic.html" %}
{% block content %}

<h1>The password has been changed!</h1>
<p><a href="{% url 'login' %}">log in again?</a></p>

{% endblock %}

測試新的身份驗證頁面

現(xiàn)在您已添加了網(wǎng)址配置并創(chuàng)建了所有這些模板,驗證頁面現(xiàn)在應(yīng)該可以正常工作了!

您可以嘗試使用以下網(wǎng)址登錄并注銷超級用戶帳戶,以測試新的身份驗證頁:

您可以從登錄頁面的鏈接中測試密碼重置功能。 請注意,Django只會向已存儲在其數(shù)據(jù)庫中的地址(用戶)發(fā)送重置電子郵件!

注意:密碼重置系統(tǒng)要求您的網(wǎng)站支持電子郵件,這超出了本文的范圍,因此此部分無法使用。 要允許測試,請將以下行放在settings.py文件的末尾。 這會記錄發(fā)送到控制臺的任何電子郵件(因此您可以從控制臺復(fù)制密碼重置鏈接)。

EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

有關(guān)詳細(xì)信息,請參見發(fā)送電子郵件(Django docs)。

針對經(jīng)過身份驗證的用戶進(jìn)行測試

本節(jié)討論我們可以做什么來根據(jù)用戶是否登錄來選擇性地控制用戶看到的內(nèi)容。

在模板中測試

您可以使用 {{user}} 模板變量獲取模板中當(dāng)前登錄用戶的信息(當(dāng)我們在我們的骨架中設(shè)置項目時,默認(rèn)將其添加到模板上下文中 )。

通常,您將首先針對 {{user.is_authenticated}} 模板變量進(jìn)行測試,以確定用戶是否有資格查看特定內(nèi)容。 為了演示這一點,接下來我們將更新側(cè)邊欄,如果用戶已注銷則顯示"登錄"鏈接,如果他們已登錄,則顯示"注銷"鏈接。

打開基本模板( /locallibrary/catalog/templates/base_generic.html ),然后將以下文本復(fù)制到 sidebar 塊中緊挨 endblock >模板標(biāo)簽。

  <ul class="sidebar-nav">

    ...

   {% if user.is_authenticated %}
     <li>User: {{ user.get_username }}</li>
     <li><a href="{% url 'logout'%}?next={{request.path}}">Logout</a></li>   
   {% else %}
     <li><a href="{% url 'login'%}?next={{request.path}}">Login</a></li>   
   {% endif %} 
  </ul>

如您所見,我們使用 if - else - endif 模板標(biāo)簽有條件地顯示文本,基于 {{user.is_authenticated }} 為true。 如果用戶通過身份驗證,我們知道我們有一個有效的用戶,因此我們調(diào)用 {{user.get_username}} 來顯示他們的名字。

我們使用 url 模板標(biāo)記和相應(yīng)網(wǎng)址配置的名稱創(chuàng)建登錄和注銷鏈接網(wǎng)址。 還要注意我們?nèi)绾卧赨RL的末尾附加?next = {{request.path}} 此操作是添加包含當(dāng)前頁面的地址(URL)的下一步 ,到鏈接的URL的結(jié)尾。 在用戶成功登錄/注銷后,視圖將使用此" next "值將用戶重定向到他們首次單擊登錄/注銷鏈接的頁面。

注意:嘗試一下! 如果您在主頁上,并單擊側(cè)邊欄中的登錄/注銷,則操作完成后,您應(yīng)該返回到同一頁面。

視圖中的測試

如果使用基于函數(shù)的視圖,限制對函數(shù)的訪問的最簡單的方法是將 login_required 裝飾器應(yīng)用于視圖函數(shù),如下所示。 如果用戶登錄,那么您的視圖代碼將正常執(zhí)行。 如果用戶未登錄,則將重定向到項目設(shè)置( settings.LOGIN_URL )中定義的登錄URL,將當(dāng)前絕對路徑作為 next URL參數(shù)傳遞 如果用戶成功登錄,則他們將返回此頁面,但這次被驗證。

from django.contrib.auth.decorators import login_required

@login_required
def my_view(request):
    ...

注意:您可以通過在 request.user.is_authenticated 上測試手動完成相同類型的事情,但裝飾器更方便!

同樣,在基于類的視圖中限制對已登錄用戶的訪問的最簡單方法是從 LoginRequiredMixin 派生。 您需要在超類列表中,在主視圖類之前首先聲明此混合。

from django.contrib.auth.mixins import LoginRequiredMixin

class MyView(LoginRequiredMixin, View):
    ...

這具有與 login_required 裝飾器完全相同的重定向行為。 您還可以指定用戶重定向的替代位置(如果未通過身份驗證( login_url )和URL參數(shù)名稱而不是" next "以插入當(dāng)前絕對 路徑( redirect_field_name )。

class MyView(LoginRequiredMixin, View):
    login_url = '/login/'
    redirect_field_name = 'redirect_to'

有關(guān)其他詳細(xì)信息,請查看 > Django docs here 。

示例 - 列出當(dāng)前用戶的圖書

現(xiàn)在我們知道如何將頁面限制為特定用戶,讓我們創(chuàng)建當(dāng)前用戶借用的書籍的視圖。

不幸的是,我們還沒有辦法讓用戶借書! 因此,在我們創(chuàng)建書籍列表之前,我們首先擴展 BookInstance 模型,以支持借用的概念,并使用Django Admin應(yīng)用程序?qū)⒁恍杞o我們的測試用戶。

楷模

首先,我們必須讓用戶有一個 BookInstance (我們已經(jīng)有一個狀態(tài) due_back 日期 ,但是我們還沒有在這個模型和用戶之間有任何關(guān)聯(lián),我們將使用 ForeignKey (一對多)字段創(chuàng)建一個,我們還需要一個簡單的機制來測試 一本借來的書已經(jīng)逾期了。

打開 catalog / models.py ,然后從 django.contrib.auth.models 中導(dǎo)入 User 在文件的頂部,因此 User 可用于使用它的后續(xù)代碼):

from django.contrib.auth.models import User

接下來將 borrower 字段添加到 BookInstance 模型中:

borrower = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)

當(dāng)我們在這里時,我們添加一個屬性,我們可以從我們的模板調(diào)用,以告訴特定的書實例是否過期。 雖然我們可以在模板本身計算,使用如下所示的屬性將更加高效。

from datetime import date

@property
def is_overdue(self):
    if date.today() > self.due_back:
        return True
    return False

現(xiàn)在我們更新了模型,我們需要對項目進(jìn)行新的遷移,然后應(yīng)用這些遷移:

python3 manage.py makemigrations
python3 manage.py migrate

管理員

現(xiàn)在打開 catalog / admin.py ,并將 borrower 字段添加到 list_display 中的 BookInstanceAdmin fieldsets ,如下所示。 這將使該字段在管理員部分中可見,以便我們可以在需要時將 User 分配給 BookInstance 。

@admin.register(BookInstance)
class BookInstanceAdmin(admin.ModelAdmin):
? ? list_display = ('book', 'status', 'borrower', 'due_back', 'id')
? ? list_filter = ('status', 'due_back')
? ??
? ? fieldsets = (
? ? ? ? (None, {
? ? ? ? ? ? 'fields': ('book','imprint', 'id')
? ? ? ? }),
? ? ? ? ('Availability', {
? ? ? ? ? ? 'fields': ('status', 'due_back','borrower',)
? ? ? ? }),
? ? )

貸了幾本書

現(xiàn)在,它可以借書給特定的用戶,去借出一些 BookInstance 記錄(設(shè)置他們的借用字段給你的測試用戶,使 狀態(tài)"貸款"并在未來和過去設(shè)置到期日。

注意:我們不會拼寫此過程,因為您已經(jīng)知道如何使用管理網(wǎng)站!

在貸款視圖

現(xiàn)在,我們將添加一個視圖,以獲取已借給當(dāng)前用戶的所有圖書的列表。 我們將使用我們熟悉的相同的通用基于類的列表視圖,但是這次我們還將從 LoginRequiredMixin 導(dǎo)入和派生,以便只有已登錄的用戶可以調(diào)用此視圖。 我們還將選擇聲明一個 template_name ,而不是使用默認(rèn)值,因為我們最終可能會有一些不同的BookInstance記錄列表,以及不同的視圖和模板。

將以下內(nèi)容添加到catalog / views.py中:

from django.contrib.auth.mixins import LoginRequiredMixin

class LoanedBooksByUserListView(LoginRequiredMixin,generic.ListView):
    """
    Generic class-based view listing books on loan to current user. 
    """
    model = BookInstance
    template_name ='catalog/bookinstance_list_borrowed_user.html'
    paginate_by = 10
    
    def get_queryset(self):
        return BookInstance.objects.filter(borrower=self.request.user).filter(status__exact='o').order_by('due_back')

為了將我們的查詢限制為當(dāng)前用戶的BookInstance對象,我們?nèi)缟纤局匦聦崿F(xiàn) get_queryset() 請注意,"o"是"借出"的存儲代碼,我們通過 due_back 日期排序,以便先顯示最早的項目。

貸款簿的URL conf

現(xiàn)在打開 /catalog/urls.py ,并添加一個指向上述視圖的 url()(您只需將下面的文本復(fù)制到文件末尾即可)。

urlpatterns += [   
    url(r'^mybooks/$', views.LoanedBooksByUserListView.as_view(), name='my-borrowed'),
]

貸款書的模板

現(xiàn)在我們需要為這個頁面做的是添加一個模板。 首先,創(chuàng)建模板文件 /catalog/templates/catalog/bookinstance_list_borrowed_user.html ,并提供以下內(nèi)容:

{% extends "base_generic.html" %}

{% block content %}
    <h1>Borrowed books</h1>

    {% if bookinstance_list %}
    <ul>

      {% for bookinst in bookinstance_list %} 
      <li class="{% if bookinst.is_overdue %}text-danger{% endif %}">
        <a href="{% url 'book-detail' bookinst.book.pk %}">{{bookinst.book.title}}</a> ({{ bookinst.due_back }})        
      </li>
      {% endfor %}
    </ul>

    {% else %}
      <p>There are no books borrowed.</p>
    {% endif %}       
{% endblock %}

此模板非常類似于之前為 Book Author 對象創(chuàng)建的模板。 這里唯一的"新"是我們檢查在模型(bookinst.is_overdue )中添加的方法,并使用它來改變過期項目的顏色。

當(dāng)開發(fā)服務(wù)器運行時,您現(xiàn)在應(yīng)該可以在瀏覽器中查看登錄用戶的列表, > http://127.0.0.1:8000/catalog/mybooks/ 。 嘗試這與您的用戶登錄并注銷(在第二種情況下,您應(yīng)該被重定向到登錄頁面)。

將列表添加到側(cè)欄

最后一步是將這個新頁面的鏈接添加到側(cè)邊欄。 我們將把它放在我們顯示已登錄用戶的其他信息的同一部分。

打開基本模板( /locallibrary/catalog/templates/base_generic.html ),然后將粗線添加到側(cè)邊欄,如圖所示。

 <ul class="sidebar-nav">
   {% if user.is_authenticated %}
   <li>User: {{ user.get_username }}</li>
   <li><a href="{% url 'my-borrowed' %}">My Borrowed</a></li>
   <li><a href="{% url 'logout'%}?next={{request.path}}">Logout</a></li>   
   {% else %}
   <li><a href="{% url 'login'%}?next={{request.path}}">Login</a></li>   
   {% endif %} 
 </ul>

它是什么樣子的?

當(dāng)任何用戶登錄時,他們會在側(cè)邊欄中看到我的借閱鏈接,并且顯示的書籍列表如下(第一本書沒有到期日,這是我們希望的錯誤 在后面的教程中修復(fù)!)。

; width:530px;">

權(quán)限

權(quán)限與模型相關(guān)聯(lián),并定義具有權(quán)限的用戶可以在模型實例上執(zhí)行的操作。 默認(rèn)情況下,Django會自動為所有模型提供添加更改權(quán)限,允許具有相關(guān)權(quán)限的用戶通過 管理網(wǎng)站。 您可以為模型定義自己的權(quán)限,并將其授予特定用戶。 您還可以更改與同一模型的不同實例關(guān)聯(lián)的權(quán)限。

測試視圖和模板中的權(quán)限非常類似,用于測試身份驗證狀態(tài)(實際上,測試權(quán)限也會測試身份驗證)。

楷模

使用 permissions 字段在模型" class Meta "中定義權(quán)限。 您可以在元組中指定任意數(shù)量的權(quán)限,每個權(quán)限本身在包含權(quán)限名稱和權(quán)限顯示值的嵌套元組中定義。 例如,我們可以定義一個權(quán)限,以允許用戶標(biāo)記圖書已返回,如圖所示:

class BookInstance(models.Model):
    ...
?   class Meta:
?       ...
        permissions = (("can_mark_returned", "Set book as returned"),)   

然后,我們可以將權(quán)限分配給管理網(wǎng)站中的"圖書管理員"組。

打開 catalog / models.py ,然后添加如上所示的權(quán)限。 您需要重新運行遷移(調(diào)用 python3 manage.py makemigrations python3 manage.py migrate )以適當(dāng)?shù)馗聰?shù)據(jù)庫。

模板

當(dāng)前用戶的權(quán)限存儲在名為 {{perms}} 的模板變量中。 您可以使用相關(guān)聯(lián)的Django"應(yīng)用"中的特定變量名稱來檢查當(dāng)前用戶是否具有特定權(quán)限。 如果用戶具有此權(quán)限,則 {{perms.catalog.can_mark_returned}} 將為 True ,否則為 False 。 我們通常使用模板 {%if%} 來測試權(quán)限,如下所示:

{% if perms.catalog.can_mark_returned %}
    <!-- We can mark a BookInstance as returned. -->
?   <!-- Perhaps add code to link to a "book return" view here. -->
{% endif %}

視圖

權(quán)限可以在函數(shù)視圖中使用 permission_required 裝飾器或在基于類的視圖中使用 PermissionRequiredMixin 來測試。 模式和行為與登錄身份驗證相同,但當(dāng)然您可能需要添加多個權(quán)限。

函數(shù)視圖裝飾器:

from django.contrib.auth.decorators import permission_required

@permission_required('catalog.can_mark_returned')
@permission_required('catalog.can_edit')
def my_view(request):
    ...

基于類的視圖的權(quán)限所需的混合。

from django.contrib.auth.mixins import PermissionRequiredMixin

class MyView(PermissionRequiredMixin, View):
    permission_required = 'catalog.can_mark_returned'
    # Or multiple of permissions:
    permission_required = ('catalog.can_mark_returned', 'catalog.can_edit')

例子

我們不會在此更新 LocalLibrary ; 也許在下一個教程!

挑戰(zhàn)自己

在本文前面,我們向您展示了如何為當(dāng)前用戶創(chuàng)建一個頁面,列出他們借用的書籍。 現(xiàn)在的挑戰(zhàn)是創(chuàng)建一個類似的頁面,該頁面僅對圖書館員可見,顯示已借用的所有圖書,其中包括每位借款人的姓名。

您應(yīng)該能夠遵循與其他視圖相同的模式。 主要區(qū)別是,您需要將視圖限制為只有圖書館員。 您可以根據(jù)用戶是否是工作人員(函數(shù)裝飾: staff_member_required ,模板變量: user.is_staff )來執(zhí)行此操作,但建議您改用 > can_mark_returned 權(quán)限和 PermissionRequiredMixin ,如上一節(jié)所述。

重要:記住不要使用超級用戶進(jìn)行基于權(quán)限的測試(即使尚未定義權(quán)限,權(quán)限檢查也始終對超級用戶返回true)。 而是創(chuàng)建庫管理器用戶,并添加所需的功能。

完成后,您的網(wǎng)頁應(yīng)該如下面的屏幕截圖所示。

; width:500px;">

    概要

    優(yōu)秀的工作 - 你現(xiàn)在創(chuàng)建了一個網(wǎng)站,圖書館成員可以登錄并查看自己的內(nèi)容,圖書館員(具有正確的權(quán)限)可以使用查看所有借出的圖書和他們的借款人。 目前我們?nèi)匀恢皇遣榭磧?nèi)容,但是當(dāng)您想要開始修改和添加數(shù)據(jù)時,使用相同的原理和技術(shù)。

    在下一篇文章中,我們將討論如何使用Django表單收集用戶輸入,然后開始修改一些存儲的數(shù)據(jù)。

    也可以看看

    以上內(nèi)容是否對您有幫助:
    在線筆記
    App下載
    App下載

    掃描二維碼

    下載編程獅App

    公眾號
    微信公眾號

    編程獅公眾號