為你的Django視圖使用裝飾器
視圖裝飾器可用于限制對某些視圖的訪問,Django附帶一些內(nèi)置的裝飾,如login_required ,require_POST 或has_permission ,它們非常有用,但有時您可能需要以不同的粒度級別限制訪問,例如只允許創(chuàng)建模型條目的用戶編輯或刪除它。
一個簡單的方法來解決這個問題,沒有在每個函數(shù)里面添加一個if語句,就是寫一個自定義的裝飾器。
示例
首先我們需要創(chuàng)建一個項(xiàng)目,名為view_decorators :
$ django-admin startproject view_decorators
在某個項(xiàng)目下創(chuàng)建一個名為blog 的應(yīng)用程序。
$ cd view_decorators/
$ python3 manage.py startapp blog
blog/models.py
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Article(models.Model):
title = models.CharField(max_length=255, verbose_name='標(biāo)題')
create_by = models.ForeignKey(User, verbose_name='用戶')
create_date = models.DateTimeField(auto_created=True, verbose_name='創(chuàng)建時間')
class Meta:
verbose_name = '文章'
verbose_name_plural = verbose_name
def __str__(self):
return self.title
創(chuàng)建裝飾器模塊
編輯blog/decorators.py 文件中創(chuàng)建一個名為user_is_article_author 的裝飾器
#!/use/bin/env python
# _*_ coding:utf-8 __
from django.core.exceptions import PermissionDenied
from .models import Article
def user_is_article_author(function):
def wrap(request, *args, **kwargs):
article = Article.objects.get(id=kwargs['article_id'])
if article.create_by == request.user:
return function(request, *args, **kwargs)
else:
raise PermissionDenied
wrap.__doc__ = function.__doc__
wrap.__name__ = function.__name__
return wrap
blog/views.py
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.shortcuts import render, get_object_or_404, redirect
from .models import Article
from .decorators import user_is_article_author
# Create your views here.
@login_required
def index(request):
# 獲取所有的文章列表
articles = Article.objects.all()
return render(request, 'index.html', {'articles': articles})
@login_required
@user_is_article_author
def remove(request, article_id):
# 如果查詢不到文章,則直接拋出異常
article = get_object_or_404(Article, id=article_id)
# 刪除成功之后的提示信息
message = '文章:{0},刪除成功'.format(article.title)
# 刪除文章
article.delete()
# 把message添加到request
messages.success(request, message)
# 轉(zhuǎn)到index函數(shù)
return redirect('index')
templates/index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<link rel="stylesheet" href="https://cdnjs./ajax/libs/materialize/0.97.8/css/materialize.min.css">
</head>
<body>
<table class="striped">
<thead>
<tr>
<th>創(chuàng)建用戶</th>
<th>文章標(biāo)題</th>
<th>創(chuàng)建時間</th>
<th>操作</th>
</tr>
</thead>
<tbody>
\{\% for article in articles \%\}
<tr>
<td>\{\{ article.create_by \}\}</td>
<td>\{\{ article.title \}\}</td>
<td>\{\{ article.create_date \}\}</td>
<td>
<form action="\{\% url 'remove' article.id \%\}" method="post">
\{\% csrf_token \%\}
<input type="submit" value="刪除" class="btn">
</form>
</td>
</tr>
\{\% endfor \%\}
</tbody>
</table>
\{\% for message in messages \%\}
<div class="card-panel teal lighten-2">\{\{ message \}\}</div>
\{\% endfor \%\}
</body>
</html>
blog/admin.py
from django.contrib import admin
from .models import Article
# Register your models here.
admin.site.register(Article)
view_decorators/urls.py
from django.conf.urls import url
from django.contrib import admin
from blog.views import index, remove
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^blog/$', index, name='index'),
url(r'^blog/remove/(?P<article_id>\d+)/$', remove, name='remove'),
]
由于使用了@login_required 裝飾器,我們還需要在settings.py 文件中定義LOGIN_URL 參數(shù):
# 未登錄的用戶跳轉(zhuǎn)到后臺登錄頁面,登錄成功之后再跳轉(zhuǎn)回之前的頁面
LOGIN_URL = '/admin/login/'
生成數(shù)據(jù)庫并創(chuàng)建超級用戶
$ python3 manage.py makemigrations
$ python3 manage.py migrate
# 創(chuàng)建的超級用戶賬號為ansheng密碼為
$ python3 manage.py createsuperuser
打開http://127.0.0.1:8000/admin/ 頁面,輸入剛才創(chuàng)建好的超級管理員賬號與密碼,登錄進(jìn)去之后創(chuàng)建兩個用戶,密碼隨意:
退回上一級頁面,添加三篇文章
我們剛才看到有三個用戶,所以呢,需要創(chuàng)建三篇文章,每篇文章對應(yīng)一個用戶
打開http://127.0.0.1:8000/blog/ 頁面,試著刪除不是其他用戶的文章,看看是什么結(jié)果。
轉(zhuǎn)自:https://blog./article/use-the-decorator-for-your-django-view.html
|