赞
踩
就是用户身份验证 是django的一个app 用于验证身份 另外授权
这里有user group的概念 就是为了统一管理 统一授权
比如一组人 统一授予 能够借书的权力
这个app早就启用了 和admin session 是一样的情况:在setting.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.
....
还记得我们当时 createsuperuser 嘛 那个超级用户是用来管理的
然而我们想模拟普通用户的操作环境 就需要 创立普通账户
当然 做快捷的方法 admin
但是那是基于后台的
这明显不符合实际情况
一般用户只会得到:
(我不会告诉你我忘了root密码是啥了)
代码操作应当是更改user数据库:
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()
总之 无论哪种方式 我们到后台都会看到:
我们之前是有两个url映射集合的
path('catalog/', include('catalog.urls')),
现在 同样的道理
我们将authentication这个应用的url映射集合 也放进去 locallibrary/locallibrary/urls.py(根目录的) 添加
path('accounts/', include('django.contrib.auth.urls'))
django帮我们已经集成了一堆url映射 如下:
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/<uidb64>/<token>/ [name='password_reset_confirm']
accounts/ reset/done/ [name='password_reset_complete']
由于authentication是内建的 我们没必要像catalog一样另外立一个模板目录 而是在
locallibrary (django project folder)
|_catalog
|_locallibrary
|_templates (new)
|_registration
也就是根目录template那边新建registeration文件夹
然后 在settings.py 添加 模板文件的搜索路径
这样我们django就可以找到 我们创立的文件夹里面的模板了2333
如果所有模板都创立完成 大概是这个样子
下面开始弄模板啦
{% 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="{{ next }}" /> </div> </form> {# Assumes you setup the password_reset view in your URLconf #} <p><a href="{% url 'password_reset' %}">Lost password?</a></p> {% endblock %}
这时 如果你访问 http://127.0.0.1:8000/accounts/login/
就会有登录界面
问题在于 用户登录以后 第一个重定向的页面应当是主页才对 但django默认设置并不是
我们设置一波 settings.py: 添加:
# Redirect to home URL after login (Default redirects to /accounts/profile/)
LOGIN_REDIRECT_URL = '/'
这样 登录以后就直接到主页去了
{% extends "base_generic.html" %}
{% block content %}
<p>Logged out!</p>
<a href="{% url 'login'%}">Click here to login again.</a>
{% endblock %}
你可以像我一样 把这玩意放到侧边栏sidebar
登录前
登录后
具体实现就是在 base_genric.html 那个模板的模板
sidebar 部分:
<ul class="sidebar-nav"> <li></li> <li></li> {% if user.is_authenticated %} <li>Hello, {{ 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}}">Hey, wanna Login?</a></li> {% endif %} <li><a href="{% url 'index' %}">Home</a></li> <li><a href="{% url 'books' %}">All books</a></li> <li><a href="{% url 'authors' %}">All authors</a></li> </ul> <ul>
这里 我们 根据 {{ user.is_authenticated }} 是否为 true(用户是否通过身份验证) ,来有条件地显示文本。
另外 怎么实现 我登录后要跳转回登陆前的信息页呢?
这里就搞定了! ?next={{}}
指定 下一个跳转页面的地址 就是你点击login的地址
比如 我在显示books的时候
点击login
http://127.0.0.1:8000/accounts/login/?next=/catalog/books/
这样登陆以后 我们就会转到 books的页面 也就是我们登录前的页面 又回去了 不同的是 添加了身份
4. registration/password_reset_form.html 密码重置页面 就是拿到你的邮箱然后发email的
{% 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 %}
{% 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 %}
Someone asked for password reset for email {{ email }}. Follow the link below:
{{ protocol}}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}
{% extends "base_generic.html" %} {% block content %} {% if validlink %} <p>Please enter (and confirm) your new password.</p> <form action="" method="post"> {% csrf_token %} <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 %}
{% extends "base_generic.html" %}
{% block content %}
<h1>The password has been changed!</h1>
<p><a href="{% url 'login' %}">log in again?</a></p>
{% endblock %}
不过 其实这里我们不会发送email 因此这是框架 但并没有真正实现email验证 重设密码的操作 你可以试试 忘记密码 选项:就会报错
你可以参考官方文档 我这里就不展开了 感觉目前没啥用2333 后面会讲怎么实现 这里跳过
对于 基于函数的视图view 也就是我们的主页那种 view.py 写了个def index(request)就完事的
我们用一个装饰符 实现 限制未登陆用户 并且还能在用户登陆完以后再跳转回去:)
只需要加两句话 (我自己都不相信django把这事变得这么简单2333)
from django.contrib.auth.decorators import login_required
然后index函数前面 上一行 加上@login_required
:如图
然后你访问 http://127.0.0.1:8000/ 或者 http://127.0.0添加链接描述.1:8000/catalog (两个其实一样的view)
页面就会跳转
当然 如果没有装饰符的页面 当然就没有限制
比如 你点击那个all books 它就进入books里面了 正常显示
这次我们对all books 试一下 这个view的确是基于 类的
我们改成这个样子:
class BookListView(LoginRequiredMixin,generic.ListView):
model = Book
paginate_by = 4
login_url = '/accounts/login/'
redirect_field_name = 'miaomiaomiao'
login_url 就是要跳转的登录页面
然后redirect_field_name 就是 类似‘next’ 的工作
你可以自定义 不过为了和前面主页跳转的那个名字统一 还是用next为好
这里欢乐一下用了miaomiaomiao
然后未登录状态下 点击all books
然后登录 再成功跳转
注意 下面这种写法有什么问题?
你会发现 代码是无效的
super(继承) 类的时候 记得顺序是有讲究的(~ ̄▽ ̄)~
除了上述两大重要的 页面显示的控制问题
针对我们图书馆的应用 我们可以弄个用户借书的功能实现
首先 数据库是关键 要建立 用户到书本实例的 外键 这样谁借了书 借了什么书 啥时候还 一目了然
model.py 添加:
from django.contrib.auth.models import User
from datetime import date
在book instance里面 添加borrow这个外键
borrower = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
@property
def is_overdue(self):
if self.due_back and date.today() > self.due_back:
return True
return False
然后 数据库迁移
python3 manage.py makemigrations
python3 manage.py migrate
然后 在admin添加上borrow字段
接下啦 我们就去创造数据咯
在admin添加就好
然后 我们就可以着手 设计“我的借阅”这种页面了
首先是view的设计:
class LoanedBooksByUserListView(LoginRequiredMixin,generic.ListView):
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')
·(status__exact='o')
这个o 指的是on load 被借走的状态 也就是筛选了借阅者和书本状态 两个因素 然后显示出来
接下来 url 映射添加:
path('mybooks/', views.LoanedBooksByUserListView.as_view(), name='my-borrowed'),
然后是模板:catalog/bookinstance_list_borrowed_user.html
{% 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 %}
当然 catalog/templates/base_generic.html 添加一项 我的借阅(my borrow)
最后大概是这个样式:
我们除了普通用户的管理 还有管理员账户的问题
这里就涉及 具体的权限问题
那么如何添加具体的权限呢?比如 图书管理员可以设置 这本书已经还了 然而普通用户不可以
我们在model.py book instance类 meta字段:
class BookInstance(models.Model):
...
class Meta:
...
permissions = (("Set_book_as_returned", "可以还书"),)
这里我们就添加一个权限
之后 admin 设计另一个账户为 图书馆管理员账号
当然记得添加上我们刚刚那个“可以还书”的权限:) 我们直接添加user组 然后所有组里的都是图书管理员
如图
一定把超级用户权限关了
这里关上超级权限 否则没有实践我们权限控制的意义了
之后 模板中 我们就可以用{{perm}} 这个模板变量来筛选用户了 比如 这个是区分普通人与图书管理员的 其实就是可以标记图书还书的权限
{% if perms.catalog.Set_book_as_returned %}
<!-- We can mark a BookInstance as returned. -->
<!-- Perhaps add code to link to a "book return" view here. -->
{% endif %}
之前 我们设计过 基于函数 或者基于类 视图 的显示的控制
也就没登录的不能看什么页面之类的
现在我们设计了一些权限 比如 是否能够还书 也可以利用这些自定义权限 限制视图的显示
也就是限制一些没有权限的用户 比如:
from django.contrib.auth.decorators import permission_required
@permission_required('catalog.can_mark_returned')
@permission_required('catalog.can_edit')
def my_view(request):
...
class MyView(PermissionRequiredMixin, View):
permission_required = ('catalog.can_mark_returned', 'catalog.can_edit')
用元祖放置多个权限 而且是同时满足的:)
实现这个只有图书管理员能看的部分 只有图书管理员能看:)
实际上在base_generic.html 这么写就行了 if控制一波
{% if perms.catalog.Set_book_as_returned %}
<ul>
<li>-----staff management------</li>
<li><a href="{% url 'borrowed' %}">staff manage books</a>
</li>
</ul>
{% endif %}
runserver 效果:
普通用户 user
将近1.5k 写博客到头秃:)
下一站 我们玩玩表单 图书馆应用还有一些功能没实现呢:)
服务端编程(十三)- Django - forms 表单的使用
我的专栏 希望能够帮到你 ( •̀ ω •́ )✧
本文专栏
手把手带你学后端(服务端)
想学习数据库嘛? 不妨从MySQL入手
MySQL专栏
python这么火 想要深入学习python 玩一下简单的应用嘛?
python应用
谢谢大佬支持! 萌新有礼了:)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。