《Python编程从入门到实践》学习笔记——Django
内容包括【7.让用户拥有自己的数据】
目标:修改模型Topic,让每个主题属于特定的用户,这将影响条目,因为条目属于特定主题
[准备工作]
1.Blog里打开命令行
2.激活虚拟环境:
ll_env\Scripts\activate
3.运行服务器:
python manage.py runserver
4.浏览器查看:
http://localhost:8000
5.Blog里再次打开命令行
6.激活虚拟环境:
ll_env\Scripts\activate
[使用@login_required限制访问]
注:@login_required是装饰器(decorators)
1.限制对topics页面的访问
因为主题属于特定用户,所以只允许已登录的用户请求topics页面
(1)给views.py添加检查登录
打开F:\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
打开F:\learning_log\learning_log\settings.py,在其末尾添加
#我的设置
LOGIN_URL='/users/login/'
(3)测验限制效果
浏览器打开http://localhost:8000,尝试不登录和登录查看Topics的结果
2.全面限制对项目“学习笔记”的访问
要求实现:不限制对主页、注册页面和注销页面的访问,限制对其他所有页面的访问
(1)给除index()外的每个视图添加@login_required
打开F:\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
打开F:\learning_log\learning_logs\models.py
添加
from django.contrib.auth.models import User #导入django.contrib.auth中的模型User
将Topic模型修改为
class Topic(models.Model):
"""用户学习的主题"""
text = models.CharField(max_length=200)
date_added = models.DateTimeField(auto_now_add=True)
owner=models.ForeignKey(User,on_delete=models.CASCADE) #新加的,建立到模型User的外键关系
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下的所有主题
[只允许用户访问自己的主题]
(1)实现只向用户显示属于自己的主题
打开F:\learning_log\learning_logs\views.py,修改函数topics()为
def topics(request):
"""显示所有的主题"""
#用户登录后,request对象将有一个user属性,这里让Django只从并数据库获取owner属性为当前用户的Topic对象
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下有主题
[保护用户的主题]views.py
限制对显示单个主题的页面的访问,防止已登录用户输入http://localhost:8000/topics/1(该内容不属于这个用户)
方法:在视图函数topic()获取请求的条目前执行检查
打开F:\learning_log\learning_logs\views.py,将
from django.http import HttpResponseRedirect
修改为
from django.http import HttpResponseRedirect, Http404
将
def topic(request,topic_id):
"""显示单个主题及其所有的条目"""
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):
"""显示单个主题及其所有的条目"""
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)
[保护修改主题页面]views.py
防止已登录用户输入http://localhost:8000/edit_entry/6(该内容不属于这个用户)
打开F:\learning_log\learning_logs\views.py,将edit_entry()修改为
def edit_entry(request,entry_id):
"""编辑既有条目"""
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:
#POST提交的数据,对数据进行处理
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)
[将新主题关联到当前用户]
此时添加新主题有问题,需要创建新主题时,指定其owner字段的值
打开F:\learning_log\learning_logs\views.py,将new_topic()修改为
def new_topic(request):
"""用户添加新主题"""
if request.method !='POST':
#未提交数据:创建一个新表单
form=TopicForm
else:
#POST提交的数据,对数据进行处理
form =TopicForm(request.POST)
if form.is_valid():
new_topic=form.save(commit=False) #修改主题保存到数据库
new_topic.owner=request.user #设置新主题的owner属性为当前用户
new_topic.save() #保存到数据库
return HttpResponseRedirect(reverse('learning_logs:topics'))
context={'form':form}
return render(request,'learning_logs/new_topic.html',context)
写在最后的作业:
1.在view.py中,核实当前主题关联到的用户为当前登录的用户。请将执行这种检查的代码放在一个名为check_topic_owner()的函数中,并在恰当的地方调用这个函数
打开F:\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)
2.保护页面new_entry:现在一个用户可在另一个用户的学习笔记中添加条目,防止发生这种事
打开F:\learning_log\learning_logs\views.py,将函数new_entry()修改为
def new_entry(request,topic_id):
"""用户添加特定新主题的新条目"""
topic=Topic.objects.get(id=topic_id)
#确认请求的主题属于当前用户
if topic.owner != request.user: #这里多加一个判断
raise Http404
if request.method !='POST':
#未提交数据,创建一个空表单
form=EntryForm()
else:
#POST提交的数据,对数据进行处理
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)