CentOS下的Django项目——
六、用户账号的登录注销注册+七、让用户拥有自己的数据
【创建用户账号】
[应用程序users]
1.创建应用程序users:python manage.py startapp users
2.将应用程序users添加到setting.py:
打开learning_log/learning_log/settings.py,修改为
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# My apps
'learning_logs',
'users',
]
3.包含应用程序users的URL
打开learning_log/learning_log/urls.py,添加
#匹配http://localhost:8000/users/打头的URL,后面可以继续添加目录
url(r'^users/',include(('users.urls','users'),namespace='users')),
[登录页面]
1.新建learning_log/users/urls.py,内容为
"""为应用程序users定义URL模式"""
from django.conf.urls import url
from django.contrib.auth.views import LoginView
from . import views
urlpatterns=[
#login http://localhost:8000/users/login/
url(r'^login/$',LoginView.as_view(template_name='users/login.html'),name='login'),
]
2.模板login.html
新建learning_log/users/templates/users/login.html,内容为
{%extends "learning_logs/base.html"%}
{%block content%}
{%if form.errors%}
<p>Your username and password didn't match.Please try again.</p>
{%endif%}
<form method="post" action="{%url 'users:login'%}">
{%csrf_token%}
{{form.as_p}}
<button name='submit'>log in</button>
<input type='hidden' name="next" value="{%url 'learning_logs:index'%}"/>
</form>
{%endblock content%}
3.链接到登录页面
打开learning_log/learning_logs/templates/learning_logs/base.html,修改为
<p>
<a href="{% url 'learning_logs:index' %}">Learning Log</a> -
<a href="{% url 'learning_logs:topics' %}">Topics</a> -
{%if user.is_authenticated%}
Hello,{{user.username}}.
{%else%}
<a href={%url 'users:login'%}>log in</a>
{%endif%}
</p>
{% block content %}{% endblock content %}
4.使用登录界面
浏览器打开http://localhost:8000/users/login/
ll_admin
[注销]
单击链接注销并返回主页
1.注销url
打开learning_log/users/urls.py,增加
#logout
url(r'^logout/$',views.logout_view,name='logout'),
2.视图函数logout_view()
打开learning_log/users/views.py,添加
from django.http import HttpResponseRedirect
from django.urls import reverse #django2.0 把原来的django.core.urlresolvers包更改为了django.urls包
from django.contrib.auth import logout
def logout_view(request):
"""注销用户"""
logout(request)
return HttpResponseRedirect(reverse('learning_logs:index'))
3.链接到注销视图
打开learning_log/learning_logs/templates/learning_logs/base.html,修改为
<p>
<a href="{% url 'learning_logs:index' %}">Learning Log</a> -
<a href="{% url 'learning_logs:topics' %}">Topics</a> -
{%if user.is_authenticated%}
Hello,{{user.username}}.
<a href="{%url 'users:logout'%}">log out</a>
{%else%}
<a href="{%url 'users:login'%}">log in</a>
{%endif%}
</p>
{% block content %}{% endblock content %}
[注册页面]
新用户注册页面:使用已提供表单UserCreationForm,但自己编写视图函数和模板。
1.注册页面的URL模式
打开learning_log/users/urls.py,增加
#register
url(r'^register/$',views.register,name='register'),
注:该模式与URL(http://localhost:8000/users/register)匹配
2.视图函数register()
打开learning_log/users/views.py,
修改from django.contrib.auth import logout为
from django.contrib.auth import logout,login,authenticate
添加
from django.contrib.auth.forms import UserCreationForm
添加
def register(request):
"""register new user"""
if request.method != 'POST':
form=UserCreationForm()
else:
form=UserCreationForm(data=request.POST)
if form.is_valid():
new_user=form.save()
authenticated_user=authenticate(username=new_user.username,password=request.POST['password1'])
login(request,authenticated_user)
return HttpResponseRedirect(reverse('learning_logs:index'))
context={'form':form}
return render(request,'users/register.html',context)
3.注册模板
新建learning_log/users/templates/users/register.html,内容为
{% extends "learning_logs/base.html"%}
{% block content %}
<form method='post' action="{%url 'users:register'%}">
{%csrf_token%}
{{form.as_p}}
<button name='submit'>register</button>
<input type="hidden" name="next" value="{%url 'learning_logs:index'%}"/>
</form>
{% endblock content %}
4.链接到注册页面
打开learning_log/learning_logs/templates/learning_logs/base.html,修改为
<p>
<a href="{% url 'learning_logs:index' %}">Learning Log</a> -
<a href="{% url 'learning_logs:topics' %}">Topics</a> -
{%if user.is_authenticated%}
Hello,{{user.username}}.
<a href="{%url 'users:logout'%}">log out</a>
{%else%}
<a href="{%url 'users:register'%}">register</a> -
<a href="{%url 'users:login'%}">log in</a>
{%endif%}
</p>
{% block content %}{% endblock content %}
5.尝试注册
账号guest,密码ll_guest123
【让用户拥有自己的数据】
[限制数据的显示]
修改模型Topic,让每个主题属于特定的用户,这将影响条目,因为条目属于特定主题
[使用@login_required限制访问]
注:@login_required是装饰器(decorators)
1.限制对topics页面的访问
因为主题属于特定用户,所以只允许已登录的用户请求topics页面
(1)给views.py添加检查登录
打开learning_log/learning_logs/views.py,添加
from django.contrib.auth.decorators import login_required
在def topics(request):前面添加
@login_required
注:login_required检查用户是否已登录,当登录时,才运行topics()
(2)给settings.py添加重定向
为实现用户未登录,则重定向到登录页面,需修改settings.py
打开learning_log/learning_log/settings.py,在其末尾添加
#我的设置
LOGIN_URL='/users/login/'
(3)测验限制效果
浏览器打开http://localhost:8000,尝试不登录和登录查看Topics的结果
2.全面限制对项目“学习笔记”的访问
要求实现:不限制对主页、注册页面和注销页面的访问,限制对其他所有页面的访问
(1)给除index()外的每个视图添加@login_required
打开learning_log/learning_logs/views.py,修改为
@login_required
def topics(request):
……
@login_required
def topic(request,topic_id):
……
@login_required
def new_topic(request):
……
@login_required
def new_entry(request,topic_id):
……
@login_required
def edit_entry(request,entry_id):
[将数据关联到用户]
注意:只要将最高层的数据关联到用户,本项目是“主题”归属于特定用户就能确定“条目”归属
1.修改模型Topic
打开learning_log/learning_logs/models.py
添加
from django.contrib.auth.models import User
将Topic模型修改为
class Topic(models.Model):
"""learning topics"""
text = models.CharField(max_length=200)
date_added = models.DateTimeField(auto_now_add=True)
owner=models.ForeignKey(User,on_delete=models.CASCADE)
def __str__(self):
return self.text
2.确定当前有哪些用户
查看已创建的所有用户的ID:
启动Django shell会话:python manage.py shell
from django.contrib.auth.models import User
User.objects.all()
for user in User.objects.all():
print(user.username,user.id)
可查看到用户ll_admin 1 guest 2
3.迁移数据库
(1)迁移数据库
确认数据:python manage.py makemigrations learning_logs
根据提示:选择1(现在提供默认值)(注:2是退出后在models.py里添加默认值)
根据提示,由于ll_admin的ID是1,这里为了让所有既有主题都关联到管理用户ll_admin,选1
执行迁移:python manage.py migrate
注:如果想要一个全新的数据库,可以执行命令python manage.py flush,此时会重建数据库的结构,此时必须重新创建超级用户且原来的数据都将丢失
(2)验证迁移效果
启动Django shell会话:python manage.py shell
from learning_logs.models import Topic
for topic in Topic.objects.all():
print(topic,topic.owner)
此时会显示ll_admin下的所有主题
[将新主题关联到当前用户]
此时添加新主题有问题,需要创建新主题时,指定其owner字段的值
打开learning_log/learning_logs/views.py,将new_topic()修改为
def new_topic(request):
"""add new topic"""
if request.method !='POST':
form=TopicForm
else:
form =TopicForm(request.POST)
if form.is_valid():
new_topic=form.save(commit=False)
new_topic.owner=request.user
new_topic.save()
return HttpResponseRedirect(reverse('learning_logs:topics'))
context={'form':form}
return render(request,'learning_logs/new_topic.html',context)
[只允许用户访问自己的主题]
(1)实现只向用户显示属于自己的主题
打开learning_log/learning_logs/views.py,修改函数topics()为
def topics(request):
"""show all topics"""
topics=Topic.objects.filter(owner=request.user).order_by('date_added')
context={'topics':topics}
return render(request,'learning_logs/topics.html',context)
(2)测试效果
在浏览器里分别登录两个用户,查看Topics,此时只有ll_admin下有主题
[保护用户的主题]
限制对显示单个主题的页面的访问,防止已登录用户输入http://localhost:8000/topics/1(该内容不属于这个用户)
方法:在视图函数topic()获取请求的条目前执行检查
打开learning_log/learning_logs/views.py,将
from django.http import HttpResponseRedirect
修改为
from django.http import HttpResponseRedirect, Http404
将
def topic(request,topic_id):
"""show one of the topics and its' items"""
topic=Topic.objects.get(id=topic_id)
entries=topic.entry_set.order_by('-date_added')
context={'topic':topic,'entries':entries}
return render(request,'learning_logs/topic.html',context)
修改为
def topic(request,topic_id):
"""show one of the topics and its' items"""
topic=Topic.objects.get(id=topic_id)
if topic.owner != request.user:
raise Http404
entries=topic.entry_set.order_by('-date_added')
context={'topic':topic,'entries':entries}
return render(request,'learning_logs/topic.html',context)
[保护页面edit_entry]
防止已登录用户(guest)输入http://localhost:8000/edit_entry/1(该内容不属于这个用户)
打开learning_log/learning_logs/views.py,将edit_entry()修改为
def edit_entry(request,entry_id):
"""edit item"""
entry=Entry.objects.get(id=entry_id)
topic=entry.topic
if topic.owner !=request.user:
raise Http404
if request.method !='POST':
form=EntryForm(instance=entry)
else:
form=EntryForm(instance=entry,data=request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('learning_logs:topic',args=[topic.id]))
context={'entry':entry,'topic':topic,'form':form}
return render(request,'learning_logs/edit_entry.html',context)
[保护页面new_entry]
现在一个用户可在另一个用户的学习笔记中添加条目(如guest输入http://localhost:8000/new_topic/2),防止发生这种事
打开learning_log/learning_logs/views.py,将函数new_entry()修改为
def new_entry(request,topic_id):
"""add new item about one of the topics"""
topic=Topic.objects.get(id=topic_id)
if topic.owner != request.user:
raise Http404
if request.method !='POST':
form=EntryForm()
else:
form=EntryForm(data=request.POST)
if form.is_valid():
new_entry=form.save(commit=False)
new_entry.topic=topic
new_entry.save()
return HttpResponseRedirect(reverse('learning_logs:topic',args=[topic_id]))
context={'topic':topic,'form':form}
return render(request,'learning_logs/new_entry.html',context)
[优化核实当前主题关联到的用户为当前登录的用户]
1.在view.py中,已经核实当前主题关联到的用户为当前登录的用户。将执行这种检查的代码放在一个名为check_topic_owner()的函数中,并在恰当的地方调用这个函数
打开learning_log/learning_logs/views.py,添加
def check_topic_owner(request,topic_id):
"""检查是否是当前登录用户的主题"""
topic=Topic.objects.get(id=topic_id)
if topic.owner != request.user:
raise Http404
修改topic()、new_entry()、edit_entry()中的
if topic.owner != request.user:
raise Http404
为
check_topic_owner(request,topic.id)