مشخصات مقاله
-
444
-
0.0
-
7350
-
0
-
0
آموزش احراز هویت کاربر و مجوز ها در Django
آموزش احراز هویت کاربر ( user authentication) و مجوز ها (permissions) در جنگو Django
در این بخش به شما می آموزیم که چگونه به کاربران اجازه دهید، با استفاده از حساب کاربری خود، به سایت وارد شده و اطلاعات نمایش داده شده و عملکرد های مجاز کاربران را، در زمان استفاده و یا عدم استفاده از حساب کاربری، تعیین کنید. همچنین صفحات login و logout را به وبسایت LocalLibrary اضافه کرده و صفحاتی مختص کاربران و کارکنان ، برای مشاهده کتاب ها، ایجاد میکنیم.
پیش نیاز آموزش احراز هویت کاربر و مجوز ها در جنگو
تمامی بخش های قبل، شامل session framework را مطالعه کنید.
هدف :
یادگیری روش ایجاد و استفاده از احراز هویت کاربران و مجوز ها
بررسی کلی
Django علاوه بر session framework، که در بخش قبل بحث شد، سیستم authentication و authorization را نیز، برای مشخص کردن مجوز های کاربر و اعمالی که مجاز به انجام آنها هستند، فراهم کرده است. این framework دارای مدل های User و Group ( یک روش عمومی برای اعمال تغییراتی در permission های چند کاربر به صورت هم زمان )، permission و flag برای تشخیص عملکرد های کاربر، forms و view برای کاربران وارد شده و view tool هایی برای محدود کردن محتواست.
سیستم احراز هویت Django به شکل کلی عمل کرده و قابلیت کمتری نسبت به سیستم های دیگر موجود برای احراز هویت وب دارد. البته برخی از این مشکلات با کمک third party package ها برطرف میشوند.
در این بخش آموزش به شما نشان میدهیم که چگونه user authentication را در وب سایت LocalLibrary فعال کرده، صفحات login و logout ساخته، به مدل های خود permission اضافه کرده و دسترسی به صفحات را کنترل کنید. همچنین با استفاده از authentication / permission لیست کتاب هایی که توسط کاربران و کارکنان به امانت گرفته شده است را نمایش میدهیم.
سیستم authentication بسیار انعطاف پذیر بوده و میتوانید، در صورت نیاز ، تنها با فراخوانی API های ورود کاربر، URL، form ها، view ها و template های خود را بسازید. در این آموزش، ما برای صفحات login و logout خود از view و form های “stock” موجود در Django استفاده کرده و template های مورد نیاز خود را ایجاد میکنیم، که البته کار نسبتا ساده ایست.
همچنین نشان میدهیم که چگونه میتوانید permission ایجاد کرده و وضعیت ورود و مجوز ها را در view و template ها بررسی کنید.
فعال کردن authentication
با ساخت skeleton website ، authentication به شکل خود کار فعال شده است.
تمامی تنظیمات ضروری در زمان استفاده از دستور django-admin startproject و ساخت اپلیکیشن، انجام شده است. همچنین با اولین فراخوانی python manage.py migrate ، جداول user و model permission را نیز ساخته ایم.
همانطور که در شکل زیر نمایش داده شده است، تنظیمات در بخش INSTALLED_APPS و MIDDLEWAARE فایل پروژه (locallibrary/locallibrary/settings.py) قرار دارد:
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.
....
ساخت user و group ها
با ساخت Django admin site ، اولین user خود را ایجاد کرده ایم ( این کاربر یک superuser است که با دستور python manage.py createsuperuser ساخته شده است). این superuser احزار هویت شده و دارای تمامی مجوز های موجود است. برای بررسی وضعیت کاربران معمولی سایت، از یک user آزمایشی استفاده کرده و با استفاده از admin ، group های LocalLibrary وlogin های وب سایت را ایجاد میکنیم ( که یکی از سریع ترین روش های موجود است).
همانطور که در بخش زیر مشاهده میکنید، میتوان با کدنویسی نیز کاربر جدید ایجاد کرد. مثلا در زمان ساخت یک interface میتوانید به کاربران اجازه ایجاد login دهید ( اما کاربران نباید به admin site دسترسی داشته باشند).
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()
در بخش زیر، ابتدا یک group و سپس یک user ایجاد میکنیم. دقت کنید که در حال حآضر مجوزی برای اضافه کردن به قابلیت های کاربران کتابخانه وجود ندارد، اما پس از ایجاد مجوز ها، استفاده از group ها بسیار ساده تر از اضافه کردن مجوز به تمامی کاربران خواهد بود.
development server را فعال کرده و در صفحه جستجوگر خود به admin site بروید ( http://127.0.0.1:8000/admin/). سپس با استفاده از حساب superuser خود، به سایت وارد شوید. در بالای admin site، تمامی model های شما، که بر اساس “Django application” مرتب شده اند، نمایش داده شده است. در بخش Authentication and Authorization ، میتوانید بر لینک های Users و Groups کلیک کرده و رکورد های موجود را مشاهده کنید.

ابتدا یک group جدید برای اعضا کتابخانه ایجاد میکنیم.
1. بر کلید Add ( در کنار Group) کلیک کرده و یک گروه جدید ساخته و نام آن را “Library Members” بگذارید.

2. نیازی به اضافه کردن permission به group ندارید، پس SAVE را انتخاب کنید ( تا لیست گروه ها را مشاهده کنید).
حالا user را ایجاد میکنیم :
به صفحه اصلی admin site بروید.
-
بر دکمه Add موجود در کنار Users کلیک کنید تا پنجره Add user را مشاهده کنید.
![مدیر سایت در جنگو - اضافه کردن کاربر pt1 مدیر سایت در جنگو - اضافه کردن کاربر pt1]()
برای کاربر آزمایشی خود Username و Password/Password confirmation را وارد کنید.
-
SAVE را انتخاب کنید تا کاربر ایجاد شود.
admin site ، کاربر جدید را ساخته و شما را به Change user screen هدایت میکند. در این بخش میتوانید username خود را تغییر داده و اطلاعاتی در فیلد های انتخابی مدل کاربر وارد کنید. این فیلد ها شامل نام کوچک، نام خانوادگی، آدرس ایمیل و وضعیت و مجوز های کاربر است ( در این بخش تنها لازم است Active flag را فعال کنید). در بخش های پایین تر میتوانید group و permission ها را برای کاربر مشخص کرده تاریخ های مهم مرتبط با کاربر ( مانند تاریخ ثبت نام و تاریخ آخرین ورود) را مشاهده کنید.
![مدیر سایت در جنگو - اضافه کردن کاربر pt2 مدیر سایت در جنگو - اضافه کردن کاربر pt2]()
-
در بخش انتخاب گروه، گروه Library Member را از لیست گروه های موجود انتخاب کرده و فلش سمت راست را برای انتقال کاربر به group box بزنید.
![]()
حالا گزینه SAVE را انتخاب کنید.
تمام ! حالا یک کاربر معمولی کتابخانه دارید که میتوانید برای تست کردن بخش های مختلف از آن استفاده کنید ( البته پس از ساخت صفحات login) .
یک کاربر دیگر نیز ایجاد کنید. همچنین یک گروه برای کارکنان کتابخانه ایجاد کرده و یک کاربر به آن بیفزایید!
ساخت authentication view در Django
Django تمامی لوازم ساخت authentication page برای مدیریت login ، logout و password ها را در اختیار ما قرار میدهد. این امکانات شامل یک URL mapper، view ها form ها است، اما ساخت template به عهده خودمان است!
در این بخش به شما آموزش میدهیم که سیستم پیش فرض را در وب سایت LocalLibrary فعال کرده، template های لازم را ساخته و آنها را در URL های اصلی پروژه قرار دهید.
استفاده از این کد ها ضروری نیست اما کار را برایتان ساده خواهد کرد. دقت کنید که با تغییر مدل، این کد ها نیز تغییر خواهند کرد ( که البته مبحثی پیشرفته است ) اما همچنان میتوانید از بخشی از این کد ها استفاده کنید.
در این پروژه میتوانید صفحه authentication ، که شامل URL ها و template ها است، را در catalog application قرار دهید، اما درصورت وجود چند application ، بهتر است login از بقیه بخش ها جدا شده و، به شکل زیر، در دسترس تمامی بخش ها قرار بگیرد .
URL های پروژه در Django
بخش زیر را در انتهای فایل url.py پروژه قرار دهید (locallibrary/locallibrary/urls.py) :
#Add Django site authentication urls (for login, logout, password management)
urlpatterns += [
path('accounts/', include('django.contrib.auth.urls')),
]
به http://127.0.0.1:8000/accounts/ بروید. Django، یک error نمایش خواهد داد که این URL را نیافته و لیستی از URL هایی که امتحان کرده است ( که لیستی URL های موجود است ) به شما نمایش میدهد ، مثلا:
روش بالا URL های زیر، با نام داخل کروشه، را ایجاد میکند که میتوانید برای URL mapping معکوس از آنها استفاده کنید. با این روش نیاز به پیاده سازی های دیگر ندارید زیرا URL mapping بالا به شکل اتوماتیک URL های زیر را map خواهد کرد.
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// / [name='password_reset_confirm'] accounts/ reset/done/ [name='password_reset_complete']
حالا به URL، http://127.0.0.1:8000/accounts/login/ بروید. دوباره با خطا مواجه میشوید اما این بار error به شما میگوید که template های لازم در مسیر مشخص شده وجود ندارد (registration/login.html). خطوط زیر را در بخش زرد بالای صفحه مشاهده خواهید کرد:
Exception Type: TemplateDoesNotExist
Exception Value: registration/login.html
گام بعد، ساخت registration directory در مسیر جستجو و اضافه کردن فایل login.html است.
Template directory
URL ها ( و view ها به شکل ضمنی) باید template های مورد نیاز خود را در دایرکتوری /registration/ در مسیر مشخص شده برای template بیابند.
در این وب سایت، ما صفحات HTML خود را در دایرکتوری template/registration قرار میدهیم. این دایرکتوری باید در root directory پروژه ( که فولدر های catalog و locallibrary در آن قرار دارند) قرار بگیرد. این فولدرها را بسازید.
درخت فولدر هایتان باید به این شکل باشد:
|_catalog
|_locallibrary
|_templates (new)
|_registration
با اضافه کردنdirectory template به مسیر جستجو، آن را در دسترس بارگذار template ( template loader ) قرار میدهیم. تنظیمات پروژه را باز کنید (/locallibrary/locallibrary/settings.py) سپس ( با اضافه کردن خط زیر به اوایل فایل ) ماژول os را import کنید.
import os # needed by code below
به شکل زیر، بخش ‘DIRS’ موجود در TEMPLATES را به روز رسانی کنید:
...
TEMPLATES = [
{
...
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
...
Login template
مهم :
authentication template های استفاده شده در این بخش، بسیار ساده بوده و تنها مقدار اندکی با login template های موجود در Django متفاوت اند. برای استفاده های آینده خود باید تغیراتی در آنها ایجاد کنید!
یک فایل HTML جدید به نام /locallibrary/templates/registration/login.html ساخته و محتوا زیر را در آن قرار دهید:
{% extends "base_generic.html" %}
{% block content %}
{% if form.errors %}
Your username and password didn't match. Please try again.
{% endif %}
{% if next %}
{% if user.is_authenticated %}
Your account doesn't have access to this page. To proceed,
please login with an account that has access.
{% else %}
Please login to see this page.
{% endif %}
{% endif %}
{# Assumes you setup the password_reset view in your URLconf #}
{% endblock %}
این template، مانند template های قبل، base template را extend کرده و content block را override میکند. بقیه کد بسیار ساده بوده و در آموزش بعدی بحث میشود. کافی است بدانید که میتوان در form نمایش داده شده username و password خود را وارد کنید. اگر مقادیر وارد شده نادرست باشد، با refresh کردن صفحه، از شما خواسته میشود که مقادیر صحیح وارد کنید.
به صفحه login بازگردید ( http://127.0.0.1:8000/accounts/login/) پس از ذخیره template ، صفحه شما به شکل زیر خواهد بود:

با وارد کرده اطلاعات صحیح، به صفحه دیگری وارد میشوید ( به شکل پیش فرض صفحه http://127.0.0.1:8000/accounts/profile/ ). Django انتظار دارد که شما با وارد شدن، به صفحه profile هدایت شوید ( که البته ممکن است این عملکرد مد نظر ما نباشد). اما توجه به اینکه هنوز صفحه profile را ایجاد نکرده ایم، با error مواجه خواهید شد!
setting پروژه را باز کرده (/locallibrary/locallibrary/settings.py) و متن زیر را به انتهای آن بیفزایید. حالا با وارد شدن به سایت، به شکل پیشفرض به home page سایت هدایت میشوید.
# Redirect to home URL after login (Default redirects to /accounts/profile/)
LOGIN_REDIRECT_URL = '/'
Logout template
اگر به صفحه logout URL ( http://127.0.0.1:8000/accounts/logout/ ) بروید، رفتار غیر منتظره ای را مشاهده خواهید کرد. از صفحه کاربر خارج شده و به صفحه Admin logout هدایت میشوید. دلیل این اتفاق، وجود لینک Admin login در لینک login این صفحه است ( که تنها برای کاربرانی که دارای مجوز is_staff هستند، در دسترس است).
/locallibrary/templates/registration/logged_out.html را ایجاد کرده و آن را باز کنید. سپس متن زیر را در آن کپی کنید:
{% extends "base_generic.html" %}
{% block content %}
Logged out!
Click here to login again.
{% endblock %}
این template بسیار ساده بوده و تنها با یک پیام، خروج از سایت را به شما اطلاع داده و لینک بازگشت به صفحه login را به شما نمایش میدهد. اگر به logout URL سر بزنید، با صفحه زیر مواجه خواهید شد :

template ریست password
سیستم تعویض password پیش فرض، یک لینک به email کاربر ارسال میکند. برای این کار باید form مورد نیاز برای دریافت ایمیل کاربر را ایجاد و یک ایمیل به آن آدرس ارسال کنید. سپس به کاربر اجازه دهید password جدید را وارد کرده و زمان اتمام این فرآیند را بیابید.
برای شروع میتوانید از template زیر استفاده کنید.
form تغییر password
این form برای دریافت آدرس ایمیل کاربر استفاده میشود ( تا بتوانیم به آن یک ایمیل ارسال کنیم ). /locallibrary/templates/registration/password_reset_form.html را ایجاد کرده و محتوای زیر را در آن قرار دهید:
{% extends "base_generic.html" %}
{% block content %}
{% endblock %}
اتمام تغییر password
پس از دریافت آدرس ایمیل، form زیر نمایش داده میشود. /locallibrary/templates/registration/password_reset_done.html را ایجاد کرده و محتوای زیر را در آن قرار دهید:
{% extends "base_generic.html" %}
{% block content %}
We've emailed you instructions for setting your password. If they haven't arrived in a few minutes, check your spam folder.
{% endblock %}
ایمیل تغییر password
این template حاوی متن HTML email ارسالی برای کاربر بوده و لینک تغییر رمز را به کاربر نمایش میدهد.
/locallibrary/templates/registration/password_reset_email.html را ایجاد کرده و محتوای زیر را در آن قرار دهید:
Someone asked for password reset for email { { email }}. Follow the link below:
{ { protocol}}://{ { domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}
تایید تغییر password
پس از کلیک کردن بر لینک موجود در ایمیل، میتوانید رمز جدید را در این صفحه وارد کنید. /locallibrary/templates/registration/password_reset_confirm.html را ایجاد کرده و محتوای زیر را در آن قرار دهید:
{% extends "base_generic.html" %}
{% block content %}
{% if validlink %}
Please enter (and confirm) your new password.
{% else %}
Password reset failed
The password reset link was invalid, possibly because it has already been used. Please request a new password reset.
{% endif %} {% endblock %}تکمیل تغییر password
پس از تغییر رمز، template زیر ( که آخرین template تغییر رمز است) موفقیت آمیز بودن عملیات تغییر رمز را به شما نمایش میدهد. /locallibrary/templates/registration/password_reset_complete.html را ایجاد کرده و محتوای زیر را در آن قرار دهید:
{% extends "base_generic.html" %}
{% block content %}
The password has been changed!
{% endblock %}
تست صفحه احراز هویت جدید
حالا که تنظیمات URL را اضافه کرده و template های لازم را ساخته ایم، میتوانیم کارکرد صفحه احراز هویت را بررسی کنیم.
با استفاده از URL های زیر به حساب کاربری superuser خود وارد شده و خارج شوید:
http://127.0.0.1:8000/accounts/login/
http://127.0.0.1:8000/accounts/logout/
با استفاده از لینک موجود در صفحه login میتوانید تغییر password را نیز تست کنید.
توجه کنید که Django تنها به آدرس هایی ( کاربرانی ) که در دیتابیس موجود هستند، ایمیل reset password ارسال میکند.
سیستم تغییر password نیازمند پشتیبانی سایت از ایمیل است، که از محدوده بحث ما در این آموزش ها خارج است. پس دقت کنید که این بخش هنوز آماده به کار نیست. برای تست این عملکرد، خط زیر را به انتهای فایل setting.py خود اضافه کنید. با این کار ایمیل های ارسالی به کنسول منتقل میشوند ( و میتوانید با استفاده از کنسول رمز خود را تغییر دهید).
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
تست کاربران تایید شده
این بخش به بررسی چگونگی کنترل محتوای قابل مشاهده برای کاربران، مبنی بر وارد شدن کاربر (logged in )، میپردازد.
تست در template ها
با استفاده از template variable { { user }} میتوانید به اطلاعاتی درباره کاربران وارد شده به template کسب کنید ( این متغییر به شکل پیش فرض، در زمان ساخت پروژه skeleton ، به template context اضافه میشود).
معمولا ابتدا متغییر { { user.is_authenticated }}تست میشود تا از مجاز بودن کاربر ، برای مشاهده محتوا، اطمینان حاصل کنیم. برای این کار sidebar خود را به گونه ای تغییر میدهیم که در صورتlogout بودن کاربر، لینک “login” و در صورت login بودن کاربر، لینک “logout” را نمایش دهد.
base template خود را باز کنید (/locallibrary/catalog/templates/base_generic.html) و متن زیر را در sidebar block، دقیقا قبل از endblock ، کپی کنید.
همانطور که مشاهده میکنید، برای نمایش متن با استفاده از if-else-endif ، از شرط { { user.is_authenticated }} استفاده میکنیم. اگر user.is_authenticated صحیح باشد( true)، کاربر تایید شده است، پس با فراخوانی {{ user.get_username }}نامش را نمایش میدهیم.
با استفاده از url template tag و نام configuration URL مربوطه، لینک های login و logout را ایجاد میکنیم. توجه کنید که ?next={ {request.path}} را در انتهای URL ها قرار داده ایم. این بخش، next ( که یک پارامتر URL و محتوی آدرس URL صفحه حال حاضر است) را به انتهای URL لینک شده اضافه میکند. پس از اینکه کاربر با موفقیت login/logout میشود، view از مقدار next برای بازگشت کاربر به همان صفحه ای که بر لینک login/logout کلیک کرده است، استفاده میکند.
این بخش را تست کنید. به Home page سایت رفته و بر لینک login/logout موجود در sidebar کلیک کنید. پس از اتمام عملیات باید به صفحه Home بازگردید.
تست در view ها
اگر از viewهای function_based استفاده میکنید، ساده ترین روش محدود کردن دسترسی به تابع ، اعمال login_required ( که یکdecorator است) بر تابع view است. اگر کاربر وارد (login) شده باشد، کد شما به شکل معمول اجرا میشود. اما اگر کاربر وارد نشده باشد( logout ) بهlogin URL تعریف شده در تنظیمات پروژه (settings.LOGIN_URL) هدایت شده و path حال حاضر کاربر را در پارامتر next قرار میدهد. اگر کاربر با موفقیت وارد شود، به عنوان یک کاربر تایید شده، همان صفحه برمیگردد.
from django.contrib.auth.decorators import login_required
@login_required
def my_view(request):
...
میتوانید با اعمال تست بر request.user.is_authenticated نیز، این کار را انجام دهید. اما استفاده از decorator کار را برایتان بسیار ساده خواهد کرد!
به طریق مشابه، ساده ترین روش محدود کردن دسترسی کاربران وارد شده به class-based view ها، مشتق گیری (drive) از LoginRequiredMixin میباشد که باید ابتدا در لیست superclass، پیش از main view class تعریف شود.
from django.contrib.auth.mixins import LoginRequiredMixin
class MyView(LoginRequiredMixin, View):
...
عملکرد این کد دقیقا شبیه به دکوراتور login_required میباشد. همچنین میتوانید در صورت تایید نشدن کاربران، آنها را به صفحه مشخصی هدایت کنید (login_url). برای این کار از پارامتری به نام name ( به جای next) استفاده میکنیم تا مسیر را در آن قرار دهیم (redirect_field_name).
class MyView(LoginRequiredMixin, View):
login_url = '/login/'
redirect_field_name = 'redirect_to'
مثال- دریافت لیست کتاب های کاربران
حالا که دریافتیم چگونه دسترسی کاربر به یک صفحه را محدود کنیم، بیایید یک view برای دریافت لیست کتاب های امانت گرفته شده کاربر بسازیم.
متاسفانه در حال حاضر کاربران ما راهی برای امانت گرفتن کتاب ندارند! پس پیش از ساخت لیست کتابها، باید مدل BookInstance گسترش دهیم تا از امانت گرفتن کتاب پشتیبانی کرده و با استفاده از Django Admin application به کاربر آزمایشی کتاب امانت دهد.
Model ها
ابتدا باید به کاربران اجازه دهیم از یک BookInstance برای امانت گرفتن کتاب استفاده کنند ( status و due_back در حال حاضر موجودند، اما ارتباطی بین این مدل و کاربر وجود ندارد. میتوان این ارتباط را با استفاده از فیلد ForeignKey ( یک به چند) ساخت). همچنین باید با استفاده از یک مکانیزم تعویق زمان بازگشت کتاب را نیز بررسی کنیم .
catalog/models.py را باز کرده و مدل user را از django.contrib.auth.models import کنید. ( خط زیر را بعد از import قبلی در بالای فایل قرار دهید تا کد پس از آن قادر به استفاده از user باشد):
from django.contrib.auth.models import User
سپس فیلد borrower را به مدل BookInstance اضافه کنید:
borrower = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
در این بخش میتوانیم صفتی ( property ) نیز بیفزاییم که با فراخوانی از template تعویق بازگشت کتاب را مشخص کند. البته میتوانیم بخش را در داخل template نیز محاسبه کنیم اما استفاده از property ، به شکل زیر، بسیار کارآمد است.
این خط را به اوایل فایل اضافه کنید:
from datetime import date
حالا تعریف صفت را به کلاس BookInstance بیفزایید:
@property
def is_overdue(self):
if self.due_back and date.today() > self.due_back:
return True
return False پیش از مقایسه due_back باید خالی بودن آن را بررسی کنید. خالی بودن این فیلد باعث ایجاد error مقابل خواهد شد: مقادیر خالی قابل مقایسه نیستند ( empty values are not comapareble) ، که تجربه خوشایندی برای کاربران ندارد.
حالا که مدل خود را به روز رسانی کرده ایم، باید migration های جدید در پروژه ایجاد و اعمال کنیم :
python3 manage.py makemigrations
python3 manage.py migrate
Admin
catalog/admin.py را باز کرده و در کلاس BookInstanceAdmin ، در list_display و fieldsets ، فیلد borrower را بسازید. با این کار، فیلد در بخش Admin قابل مشاهده خواهد بود و به ما اجازه میدهد بین یک 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')
}),
)
چند کتاب امانت دهید
حالا میتوانیم چند رکورد BookInstance را به کاربران امانت دهیم. مقدارفیلد borrowed را ، کاربر آزمایشی خود قرار داده و status را به “On loan” تغیید دهید. همچنین باید تاریخ بازگشت کتاب را نیز مشخص کنید ( یک بار از یک تاریخ در آینده و یک بار از تاریخی در گذشته استفاده کنید).
با توجه اینکه شما کار با Admin site را آموختید، در این بخش تمامی مراحل را توضیح نخواهیم داد.
view امانت
حالا میتوانیم یک view برای مشاهده لیست کتاب های امانت گرفته شده توسط کاربر ایجاد کنیم و این کار را با استفاده از generic class-based list view ، که پیش تر با آن آشنا شده ایم، انجام میدهیم. اما این بار از مشتق LoginRequiredMixin نیز استفاده میکنیم تا تنها کاربرانی که وارد سایت شده اند بتوانند به این view دسترسی پیدا کنند. همچنین یک template_name تعریف کرده و از حالت پیش فرض استفاده نمیکنیم، زیرا ممکن است لیست های مختلفی از رکورد های BookInstance ، با view ها و template های مختلف، ایجاد شود.
بخش زیر را به 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')
get_queryset ، به منظور محدود کردن query به اشیا BookInstance کاربر حال حاضر، دوباره پیاده سازی شده است. دقت کنید که “o” کد ذخیره شده برای “on loan” ( امانت داده شده) است و due_back نیز به شکلی مرتب شده که ابتدا item های قدیمی تر را نمایش دهد.
URL conf برای کتاب های امانت داده شده
حالا /catalog/urls.py را باز کره و یک تابع path() که به view بالا اشاره میکند به آن بیفزایید ( و یا میتوانید متن زیر را در انتهای فایل کپی کنید):
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')
get_queryset ، به منظور محدود کردن query به اشیا BookInstance کاربر حال حاضر، دوباره پیاده سازی شده است. دقت کنید که “o” کد ذخیره شده برای “on loan” ( امانت داده شده) است و due_back نیز به شکلی مرتب شده که ابتدا item های قدیمی تر را نمایش دهد.
URL conf برای کتاب های امانت داده شده
حالا /catalog/urls.py را باز کره و یک تابع path() که به view بالا اشاره میکند به آن بیفزایید ( و یا میتوانید متن زیر را در انتهای فایل کپی کنید):
urlpatterns += [
path('mybooks/', views.LoanedBooksByUserListView.as_view(), name='my-borrowed'),
]
template برای کتاب های امانت داده شده
حالا تنها کاری که باید انجام دهیم، اضافه کردن template به این صفحه است. ابتدا فایل template (/catalog/templates/catalog/bookinstance_list_borrowed_user.html) را ایجاد کرده و محتوای زیر را در آن قرار دهید:
{% extends "base_generic.html" %}
{% block content %}
Borrowed books
{% if bookinstance_list %}
-
{% for bookinst in bookinstance_list %}
- { {bookinst.book.title} } ({ { bookinst.due_back }}) {% endfor %}
There are no books borrowed.
{% endif %} {% endblock %}این template بسیار شبیه template هایی است که برای اشیا Book و Author ایجاد کردیم. تنها چیزی که تا به حال با آن روبرو نشده اید این است که متد اضافه شده به مدل (bookinst.is_overdue) را بررسی میکنیم تا بتوانیم برای تغییر رنگ item های با تاخیر از آن استفاده کنیم.
پس از راه اندازی development server، باید قادر باشید لیست کتاب های امانت گرفته شده یک کاربر وارد شده را در http://127.0.0.1:8000/catalog/mybooks/ مشاهده کنید. در حالت login و logout به این صفحه سر بزنید ( در حالت دوم باید به صفحه login هدایت شوید).
اضافه کردن لیست به sidebar
آخرین گام، اضافه کردن لینک این صفحه جدید به sidebar ، در کنار اطلاعات دیگر موجود برای کاربر وارد شده است.
template اصلی را باز کرده (/locallibrary/catalog/templates/base_generic.html) و خطوط زیر را به sidebar اضافه کنید:
نتیجه نهایی به چه شکل است؟
کاربر پس از وارد شدن، لینک My Barrowed ( امانتی های من ) را در sidebar مشاهده خواهد کرد ( دقت کنید که اولین کتاب تاریخ بازگشت ندارد! امیدواریم بتوانیم این مشکل را در آموزش های بعدی حل کنیم ).

permissionها
مجوز ها ( permission ها ) با مدل ها در ارتباط بوده و عملکرد هایی که یک کاربر مجاز است در یک model instance انجام دهد را مشخص میکنند. Django به شکل پیش فرض، مجوز add، delete و change را برای تمامی مدل ها، از طریق admin site به کاربران میدهد. همچنین میتوانید مجوز های مختلفی برای instance های یک مدل ایجاد کنید.
مراحل تست مجوز ها در view و template بسیار شبیه به تست وضیعت احراز هویت است ( و با تست مجوز ها، احراز هویت نیز بررسی میشود).
Model ها
مجوز ها در بخش “class meta” مدل، و با استفاده از فیلد permissions، تعریف میشوند. میتوانید در هر tuple، با ایجاد nested tuple محتوی نام مجوز و display value مجوز، به تعداد دلخواه مجوز ایجاد کنید. برای مثال، میتوانیم به کاربر اجازه دهیم که بازگشت یک کتاب را مشخص کند:
class BookInstance(models.Model):
...
class Meta:
...
permissions = (("can_mark_returned", "Set book as returned"),)
و سپس این مجوز را در Admin site به گروه کتابخانه داران " librarian" نسبت دهیم.
catalog/models.py را باز کرده و مجوز بالا را اضافه کنید. پس از این گام باید migration های خود را دوباره اجرا کرده ( با فراخوانی python3 manage.py makemigrations و python3 manage.py migrate ) و دیتابیس خود را به روز رسانی کنید.
Template ها
مجوزهای کاربر در یک template variable به نام { { perms }} ذخیره میشود. با استفاده از نام متغیر و در “app” مرتبط Django، مجوز های کاربر را بررسی کنید. مثلا مجوز
{ { perms.catalog.can_mark_returned }} در صورت وجود True و در غیر این صورت False خواهد بود. معمولا با استفاده از template tag {% if %} وجود مجوز ها را بررسی میکنیم :
{% if perms.catalog.can_mark_returned %}
{% endif %}
View ها
مجوز ها را میتوان با استفاده از دکوراتور permission_required در function view و یا با استفاده از PermissionRequiredMixin در class based view، تست کرد. مراحل تست با تست login authentication یکسان است، البته باید تعدادی مجوز اضافه کنید.
function view decorator :
from django.contrib.auth.decorators import permission_required
@permission_required('catalog.can_mark_returned')
@permission_required('catalog.can_edit')
def my_view(request):
...
یک permission- required mixin برای class-based view ها.
from django.contrib.auth.mixins import PermissionRequiredMixin
class MyView(PermissionRequiredMixin, View):
permission_required = 'catalog.can_mark_returned'
# Or multiple permissions
permission_required = ('catalog.can_mark_returned', 'catalog.can_edit')
# Note that 'catalog.can_edit' is just an example
# the catalog application doesn't have such permission!
در عملکرد های بالا تفاوت کوچکی وجود دارد. به طور پیش فرض برای یک کاربر وارد شده که مجوزی را نقض کرده است:
-
@permission_required – به صفحه login هدایت خواهد کرد ( HTTP Status 302).
-
PermissionRequiredMixin- 403 باز میگرداند ( HTTP Status Forbiden) .
و معمولا عملکرد PermissionRequiredMixin دلخواه ماست: اگر کاربر وارد شده اما مجوز لازم را ندارد 403 نمایش بده. برای پیاده سازی این عملکرد در function view، از @login_required و @permission_required به همراه raise_exception=True استفاده کنید:
from django.contrib.auth.decorators import login_required, permission_required
@login_required
@permission_required('catalog.can_mark_returned', raise_exception=True)
def my_view(request):
...
مثال
در این بخش LocalLobrary را به روز رسانی نخواهیم کرد، شاید در آموزش های بعد !
خود را به چالش بکشید
در بخش های قبل به شما نشان دادیم که چگونه میتوانید یک لیست از کتاب های امانت گرفته شده برای کاربر ایجاد کنید. چالش شما این است که یک صفحه مشابه برای کتابخانه داران ایجاد کنید که تمام کتاب های امانت گرفته شده را، به همراه نام کاربری که آن را امانت گرفته است، نمایش دهد.
میتوانید از گام هایی مشابه با view دیگر استفاده کنید. تفاوت اصلی، محدود کردن view به کتابخانه داران است. میتوانید کارمند بودن یا نبودن کاربر را بررسی کنید ( دکوراتور : staff_member_required ، template variable : user.is_staff ) اما توصیه میشود که مانند بخش قبل از مجوز can_mark_returned و PermissionRequiredMixin استفاده کنید.
مهم :
دقت کنید که برای تست مجوز های خود از superuser استفاده نکنید ( تست مجوز با superuser همواره true خواهد بود، حتی اگر مجوز هنوز تعریف نشده باشد!). یک کاربر کتابخانه دار ایجاد کرده و قابلیت های لازم را برایش ایجاد کنید.
پس از اتمام این کار، صفحه نهایی شما باید مشابه تصویر زیر باشد.

خلاصه
کارتان عالی بود! تا به حال شما یک وب سایت ایجاد کردید که اعضا میتوانند به آن وارد شده و محتوا مشخص شده را مشاهده کنند و کتابخانه داران نیز ( با مجوز های صحیح) میتوانند لیست تمامی کتاب های امانت داده شده به همراه نام افرادی که آنها را امانت گرفته اند، را مشاهده کنند. اما تا به حال فقط توانسته ایم اطلاعات موجود را مشاهده کنیم، با تکنیک ها و اصول مشابه میتوان اطلاعات را تغییر داد و یا داده هایی به سایت اضافه کرد.
در آموزش بعد می آموزیم که چگونه با استفاده از Django forms داده های ورودی کاربر را دریافت کرده و بخشی از داده های ذخیره شده را ویرایش کنیم.


