让用户拥有私有数据
1.使用Django提供的装饰器@login_required
限制访问
- 在settings.py的末尾,添加
LOGIN_URL = '/users/login/'
,这样,当限制访问时,将重定向到/users/login/ - 在learning_logs/views.py中,
- 导入
from django.contrib.auth.decorators import login_required
- 在需要限制访问的函数前一行添加
@login_required
这些函数是:topics, topic, new_topic, new_entry, login_required
- 导入
2.将数据关联到用户
现在所有的topic和entry都不属于某个特定用户。
我们修改模型topic,添加一个关联到用户的外键,然后对数据库迁移,最后在修改视图,只显示和当前用户关联的主题和条目
修改模型Topic
修改models.py,添加
from django.contrib.auth.models import User
然后在Topic类中添加属性owner,如下:
class Topic(models.Model):
"""A topic the user is learning about"""
text = models.CharField(max_length=200)
date_added = models.DateTimeField(auto_now_add=True)
owner = models.ForeignKey(
User, # note that it should be User, not 'User', or error may occur
on_delete=models.CASCADE,
)
def __str__(self):
"""Return a string representation of the model."""
return self.text
通过Django shell查看当前有哪些用户,并确定把数据关联到哪个用户
在终端使用命令:
python manage.py shell
这时会进入python交互环境一次输入下面行并回车
from django.contrib.auth.models import User
for user in User.objects.all():
print(user.username, user_id)
将会列出:
username id
栗子:
ll_admin 1
sarah 2
jane 3
记住要把数据关联到的用户的id
迁移数据库
运行python manage.py makemigrations learning_logs
会提示:1.设定默认的用户 2.退出,手动在models.py中添加默认值
这里选择1,然后再选择1,即设定ll_admin为默认关联。运行
python manage.py migrate
这时,数据库将迁移,所有的数据都属于ll_admin了
访问限制
错误:注意urls里面定义时要写为'topics/'
,后面的/
不要省略,否则在下面使用修饰器跳转的时候,会出现404错误,找不到url。如果写为'topics'
,那么访问localhost:8000/topics/
是404错误,找不到url,localhost:8000/topics
则正常。
另外,''
不需要写为'/'
1.只允许用户看到自己的topics
在views.py对函数topics()修改:
@login_required
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.限制url访问用户主题详情页
要限制例如localhost:port/topics/1/
的访问,修改views.py
- 导入:
from django.http import HttpResponseRedirect, Http404
- 创建新函数,检查当前用户是否有权限访问:
def check_topic_owner(request, topic):
"""ensure the topic requested belongs to the current user"""
if topic.owner != request.user:
raise Http404
- 在相应位置调用函数
@login_required
def topic(request, topic_id):
"""show one topic with its all entry"""
topic = Topic.objects.get(id=topic_id)
check_topic_owner(request, topic)
# minus sign indicates descending sort
entries = topic.entry_set.order_by('-date_added')
context = {'topic': topic, 'entries': entries}
return render(request, 'learning_logs/topic.html', context)
@login_required
def new_entry(request, topic_id):
"""add a new entry in a specific topic"""
topic = Topic.objects.get(id=topic_id)
check_topic_owner(request, topic)
if request.method != 'POST':
# no data submitted; create a new form
form = EntryForm()
else:
# data submitted through post; process data
form = EntryForm(data=request.POST)
if form.is_valid():
# create a new entry instance,and store it in new_entry,
# but not store it in database yet(commit=False)
new_entry = form.save(commit=False)
# add topic attr & set it
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)
@login_required
def edit_entry(request, entry_id):
"""edit an existing entry"""
entry = Entry.objects.get(id=entry_id)
topic = entry.topic
# ensure the entry to be edited belongs to the current user
check_topic_owner(request, topic)
if request.method != 'POST':
# first request; fill the form with old info
form = EntryForm(instance=entry)
else:
# POST request; process the data
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)
3.在新建新主题时,关联到当前登录的用户
在new_topic()函数中添加:
new_topic = form.save(commit=False)
new_topic.owner=request.user
new_topic.save()
添加后,即:
@login_required
def new_topic(request):
"""add new topic"""
if request.method != 'POST':
# didn't submit data: create a new form
form = TopicForm # TopicForm is imported from ./form.py
else:
# data submitted through post: process the data
form = TopicForm(request.POST)
if form.is_valid():
new_topic = form.save(commit=False)
new_topic.owner=request.user
new_topic.save()
# redirect user to topics page
return HttpResponseRedirect(reverse('learning_logs:topics'))
context = {'form': form}
return render(request, 'learning_logs/new_topic.html', context)
至此,已实现用户数据私有化和访问限制。