接上文 Python编程--Django入门:用户账户(一)https://developer.aliyun.com/article/1618616
2.2 登录页面
在目录learning_log/users/中,新建一个名为urls.py的文件,并在其中添加如下代码:
urls.py
"""为应用程序users定义URL模式"""
from django.conf.urls import url
from django.contrib.auth.views import login
from . import views
urlpatterns = [
# 登录页面
url(r'^login/$', login, {
'template_name': 'users/login.html'},
name='login'),
]
1. 模板login.html
用户请求登录页面时,Django使用其默认视图login。但我们依然需要为这个页面提供模板。为此,在目录learning_log/users/中,创建一个名为templates的目录,并在其中创建一个名为users的目录。将login.html模板存储到目录learning_log/users/templates/users/中:
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>login</title>
</head>
<body>
{
% 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 %}
</body>
</html>
2. 链接到登录页面
在base.html中添加到登录页面的链接,让所有页面都包含它。用户已登录时,我们不想显示这个链接,因此将它嵌套在一个{% if %}标签中。
base.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Base</title>
</head>
<body>
<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 %}
</body>
</html>
3. 使用登录页面
前面建立了一个用户账户,下面来登录一下,请访问http://localhost:8000/admin/,如果依然是以管理员身份登录的,请在页眉上找到注销链接并单击它。注销后,访问http://localhost:8000/users/login/
2.3 注销
- 注销URL
下面代码为注销定义了URL模式,该模式与URL http://localhost:8000/users/logout/匹配。修改后的users/urls.py如下:
urls.py
"""为应用程序users定义URL模式"""
from django.conf.urls import url
from django.contrib.auth.views import login
from . import views
urlpatterns = [
# 登录页面
url(r'^login/$', login, {
'template_name': 'users/login.html'},
name='login'),
# 注销
url(r'^logout/$', views.logout_view, name='logout'),
]
- 视图函数logout_view()
函数logout_view()很简单:只是导入Django函数logout(),并调用它,再重定向到主页。打开users/views.py,并输入下面的代码:
views.py
from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from django.contrib.auth import logout
# Create your views here.
def logout_view(request):
"""注销用户"""
logout(request)
return HttpResponseRedirect(reverse('learning_logs:index'))
- 链接到注销视图
添加一个注销链接。在base.html中添加这种链接,让每个页面都包含它;将它放在标签{% if user.is_authenticated %}中,使得仅当用户登录后才能看到它:
base.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Base</title>
</head>
<body>
<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 %}
</body>
</html>
用户登录后看到的主页,如下图所示:
2.4 注册页面
创建一个让新用户能够注册的页面。使用Django提供的表单UserCreationForm,编写自己的视图函数和模板。
1. 注册页面的URL模式
urls.py
"""为应用程序users定义URL模式"""
from django.conf.urls import url
from django.contrib.auth.views import login
from . import views
urlpatterns = [
# 登录页面
url(r'^login/$', login, {
'template_name': 'users/login.html'},
name='login'),
# 注销
url(r'^logout/$', views.logout_view, name='logout'),
# 注册页面
url(r'^regiester/$', views.register, name='register')
]
2. 视图函数register()
在users/views.py中添加如下代码:
views.py
from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from django.contrib.auth import login, logout, authenticate
from django.contrib.auth.forms import UserCreationForm
# Create your views here.
def logout_view(request):
"""注销用户"""
logout(request)
return HttpResponseRedirect(reverse('learning_logs:index'))
def register(request):
"""注册新用户"""
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. 注册模板**
注册页面的模板与登录页面的模板类似,务必保存到login.html所在目录中:
```js
register.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>register</title>
</head>
<body>
{
% 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 %}
</body>
</html>
4. 链接到注册页面
base.htm
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Base</title>
</head>
<body>
<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 %}
</body>
</html>
下面尝试一下注册新用户,如下图所示:
注册成功!
3. 让用户拥有自己的数据
创建一个系统,确定各项数据所属的用户,再限制对页面的访问,让用户只能使用自己的数据。
3.1 使用@login_required限制访问
Django提供了装饰器@login_required,能够轻松地实现这样的目标:对于某些页面,只允许已登录的用户访问。
1. 限制对topics页面的访问
每个主题都归特定用户所有,因此应只允许已登录的用户请求topics页面。为此,在learning_logs/views.py中添加如下代码:
views.py
from django.shortcuts import render
from .models import Topic, Entry
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from . forms import TopicForm, EntryForm
from django.contrib.auth.decorators import login_required # 添加代码
# Create your views here.
def index(request):
"""学习笔记的主页"""
return render(request, 'learning_logs/index.html')
@login_required # 添加代码
def topics(request):
"""显示所有的主题"""
topics = Topic.objects.order_by('date_added')
context = {
'topics':topics}
return render(request, 'learning_logs/topics.html', context)
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 new_topic(request):
"""添加新主题"""
if request.method != 'POST':
# 未提交数据:创建一个新表单
form = TopicForm()
else:
# POST提交的数据,对数据进行处理
form = TopicForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('learning_logs:topics'))
context = {
'form':form}
return render(request, 'learning_logs/new_topic.html', context)
def new_entry(request, topic_id):
"""在特定的主题中添加新条目"""
topic = Topic.objects.get(id=topic_id)
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)
def edit_entry(request, entry_id):
"""编辑既有条目"""
entry = Entry.objects.get(id=entry_id)
topic = entry.topic
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)
在settings.py末尾添加如下代码:
settings.py
"""
Django settings for learning_log project.
Generated by 'django-admin startproject' using Django 1.11.
For more information on this file, see
https://docs.djangoproject.com/en/1.11/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.11/ref/settings/
"""
import os
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = ')-lv47!$0c!j5-7th)l_-osv&ugkws7!6pv&+oe_0=p_xo(g@_'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# My app
'learning_logs',
'users',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'learning_log.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'learning_log.wsgi.application'
# Database
# https://docs.djangoproject.com/en/1.11/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
# Password validation
# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/1.11/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.11/howto/static-files/
STATIC_URL = '/static/'
"""
项目learning_log的Django设置
"""
# 我的设置
LOGIN_URL = '/users/login/'
要测试这个设置, 可注销并进入主页。然后,单击链接Topics,重定向到登录页面。使用自己的账户登录,再次单击主页中的Topics链接,看到topics页面。
2. 全面限制对项目“学习笔记”的访问
在项目“学习笔记”中,不限制对主页、注册页面和注销页面的访问,限制对其他所有页面的访问。
在learning_logs/views.py中,对除index()外对每个视图都应用了装饰器@login_required:
views.py
from django.shortcuts import render
from .models import Topic, Entry
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from . forms import TopicForm, EntryForm
from django.contrib.auth.decorators import login_required
# Create your views here.
def index(request):
"""学习笔记的主页"""
return render(request, 'learning_logs/index.html')
@login_required
def topics(request):
"""显示所有的主题"""
topics = Topic.objects.order_by('date_added')
context = {
'topics':topics}
return render(request, 'learning_logs/topics.html', context)
@login_required
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)
@login_required
def new_topic(request):
"""添加新主题"""
if request.method != 'POST':
# 未提交数据:创建一个新表单
form = TopicForm()
else:
# POST提交的数据,对数据进行处理
form = TopicForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('learning_logs:topics'))
context = {
'form':form}
return render(request, 'learning_logs/new_topic.html', context)
@login_required
def new_entry(request, topic_id):
"""在特定的主题中添加新条目"""
topic = Topic.objects.get(id=topic_id)
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)
@login_required
def edit_entry(request, entry_id):
"""编辑既有条目"""
entry = Entry.objects.get(id=entry_id)
topic = entry.topic
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)
如果输入URL http://localhost:8000/new_topic/,将重定向到登录页面。对于所有与私有用户数据相关的URL,都应限制对它们的访问。
3.2 将数据关联到用户
修改模型Topic,在其中添加一个关联到用户的外键。一定要对数据库进行迁移。然后必须对有些视图进行修改,使其只显示与当前登录的用户相关联的数据。
1. 修改模型Topic
对models.py的修改只涉及两行代码:
models.py
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Topic(models.Model):
"""用户学习的主题"""
text = models.CharField(max_length=200)
date_added = models.DateTimeField(auto_now_add=True)
owner = models.ForeignKey(User)
def __str__(self):
"""返回模型的字符串表示"""
return self.text
class Entry(models.Model):
"""学到的有关某个主题的具体知识"""
topic = models.ForeignKey(Topic, on_delete = models.CASCADE)
text = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
class Meta:
verbose_name_plural = 'entries'
def __str__(self):
"""返回模型的字符串表示"""
return self.text[:50] + '...'
2. 确定当前有哪些用户
当迁移数据库时,Django将对数据库进行修改,使其能够存储主题和用户之间的关联。为执行迁移,Django需要知道该将各个既有主题关联到哪个用户。最简单的办法是,将既有主题都关联到同一个用户,如超级用户。为此,需要知道该用户ID。查看已创建的所有用户ID,启动一个Django shell会话,执行如下命令:
(11_env) (base) liuxiaowei@MacBook-Air learning_log % python manage.py shell
Python 3.9.12 (v3.9.12:b28265d7e6, Mar 23 2022, 18:17:11)
[Clang 6.0 (clang-600.0.57)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from django.contrib.auth.models import User
>>> User.objects.all()
<QuerySet [<User: lxw_admin>, <User: bruce_lee>, <User: ll>]>
>>> for user in User.objects.all():
... print(user.username, user.id)
...
lxw_admin 1
bruce_lee 2
ll 3
3. 迁移数据库
知道用户ID后,就可以i迁移数据库了。
(11_env) (base) liuxiaowei@MacBook-Air learning_log % python manage.py makemigrations learning_logs
You are trying to add a non-nullable field 'owner' to topic without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
2) Quit, and let me add a default in models.py
Select an option: 1
Please enter the default value now, as valid Python
The datetime and django.utils.timezone modules are available, so you can do e.g. timezone.now
Type 'exit' to exit this prompt
>>> 1
Migrations for 'learning_logs':
learning_logs/migrations/0003_topic_owner.py
- Add field owner to topic
如上所示,将所有既有主题都关联到管理用户lxw_admin,输入了用户ID值1。
现在可以执行迁移了,在虚拟环境中执行如下命令:
(11_env) (base) liuxiaowei@MacBook-Air learning_log % python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, learning_logs, sessions
Running migrations:
Applying learning_logs.0003_topic_owner... OK
为验证迁移符合预期,可在shell会话中如下操作:
from learning_logs.models import Topic
for topic in Topic.objects.all(): ... print(topic, topic.owner) ... Chess lxw_admin Rock Climbing lxw_admin dlsd lxw_admin Opera lxw_admin Opera lxw_admin
3.3 只允许用户访问自己的主题
现在,不管你以哪个用户身份登录,都能看到所有主题。现在改变这种情况,只向用户显示属于自己的主题。
在views.py中,对函数topics()做如下修改:
views.py
from django.shortcuts import render
from .models import Topic, Entry
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from . forms import TopicForm, EntryForm
from django.contrib.auth.decorators import login_required
# Create your views here.
def index(request):
"""学习笔记的主页"""
return render(request, 'learning_logs/index.html')
@login_required
def topics(request):
"""显示所有的主题"""
topics = Topic.objects.filter(owner=request.user).order_by('date_added') # 添加代码
context = {
'topics':topics}
return render(request, 'learning_logs/topics.html', context)
@login_required
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)
@login_required
def new_topic(request):
"""添加新主题"""
if request.method != 'POST':
# 未提交数据:创建一个新表单
form = TopicForm()
else:
# POST提交的数据,对数据进行处理
form = TopicForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('learning_logs:topics'))
context = {
'form':form}
return render(request, 'learning_logs/new_topic.html', context)
@login_required
def new_entry(request, topic_id):
"""在特定的主题中添加新条目"""
topic = Topic.objects.get(id=topic_id)
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)
@login_required
def edit_entry(request, entry_id):
"""编辑既有条目"""
entry = Entry.objects.get(id=entry_id)
topic = entry.topic
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)
3.4 保护用户的主题
目前还没有限制对显示单个主题的页面的访问,要修复这种问题,在视图函数topic()获取请求的条目前执行检查:
views.py
from django.shortcuts import render
from .models import Topic, Entry
from django.http import HttpResponseRedirect, Http404 # 添加代码
from django.core.urlresolvers import reverse
from . forms import TopicForm, EntryForm
from django.contrib.auth.decorators import login_required
# Create your views here.
def index(request):
"""学习笔记的主页"""
return render(request, 'learning_logs/index.html')
@login_required
def topics(request):
"""显示所有的主题"""
topics = Topic.objects.filter(owner=request.user).order_by('date_added')
context = {
'topics':topics}
return render(request, 'learning_logs/topics.html', context)
@login_required
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)
@login_required
def new_topic(request):
"""添加新主题"""
if request.method != 'POST':
# 未提交数据:创建一个新表单
form = TopicForm()
else:
# POST提交的数据,对数据进行处理
form = TopicForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('learning_logs:topics'))
context = {
'form':form}
return render(request, 'learning_logs/new_topic.html', context)
@login_required
def new_entry(request, topic_id):
"""在特定的主题中添加新条目"""
topic = Topic.objects.get(id=topic_id)
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)
@login_required
def edit_entry(request, entry_id):
"""编辑既有条目"""
entry = Entry.objects.get(id=entry_id)
topic = entry.topic
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)
3.5 保护页面edit_entry
页面edit_entry的URL为http://localhost:8000/edit_entry/entry_id/,其中entry_id是一个数字。禁止用户通过输入类似前面的URL来访问其他用户的条目,命令如下:
views.py
from django.shortcuts import render
from .models import Topic, Entry
from django.http import HttpResponseRedirect, Http404
from django.core.urlresolvers import reverse
from . forms import TopicForm, EntryForm
from django.contrib.auth.decorators import login_required
# Create your views here.
def index(request):
"""学习笔记的主页"""
return render(request, 'learning_logs/index.html')
@login_required
def topics(request):
"""显示所有的主题"""
topics = Topic.objects.filter(owner=request.user).order_by('date_added')
context = {
'topics':topics}
return render(request, 'learning_logs/topics.html', context)
@login_required
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)
@login_required
def new_topic(request):
"""添加新主题"""
if request.method != 'POST':
# 未提交数据:创建一个新表单
form = TopicForm()
else:
# POST提交的数据,对数据进行处理
form = TopicForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('learning_logs:topics'))
context = {
'form':form}
return render(request, 'learning_logs/new_topic.html', context)
@login_required
def new_entry(request, topic_id):
"""在特定的主题中添加新条目"""
topic = Topic.objects.get(id=topic_id)
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)
@login_required
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)
3.6 将新主题关联到当前用户
修改views.py代码:
views.py
from django.shortcuts import render
from .models import Topic, Entry
from django.http import HttpResponseRedirect, Http404
from django.core.urlresolvers import reverse
from . forms import TopicForm, EntryForm
from django.contrib.auth.decorators import login_required
# Create your views here.
def index(request):
"""学习笔记的主页"""
return render(request, 'learning_logs/index.html')
@login_required
def topics(request):
"""显示所有的主题"""
topics = Topic.objects.filter(owner=request.user).order_by('date_added')
context = {
'topics':topics}
return render(request, 'learning_logs/topics.html', context)
@login_required
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)
@login_required
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
new_topic.save()
return HttpResponseRedirect(reverse('learning_logs:topics'))
context = {
'form':form}
return render(request, 'learning_logs/new_topic.html', context)
@login_required
def new_entry(request, topic_id):
"""在特定的主题中添加新条目"""
topic = Topic.objects.get(id=topic_id)
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)
@login_required
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)