Django入门3

19.2.4 注册页面

下面来创建一个让新用户能够注册的页面。我们将使用 Django 提供的表单 UserCreationForm,但编写自己的视图函数和模板。

1.注册页面的 URL 模式

# learning_log/users/urls.py

--snip--
urlpatterns = [
    --snip--
    # 注册
    url(r'^register/$', views.register, name='register'),

]

2.视图函数 registerer()

#users/views.py

from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.views import login
from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.contrib.auth import logout, authenticate

def logout_view(request):
--snip--
def register(request):
    """注册新用户"""
    # 如果不是 POST 请求,就先创建一个 UserCreationForm实例
    # UserCreationForm:默认表单
    if request.method != 'POST':
        # 显示空的注册表单
        form = UserCreationForm()
    else:
        # 处理填写好的表单
        form = UserCreationForm(data=request.POST)

        if form.is_valid():
            # 如果提交的数据有效,我们调用表单的 save(),将用户名和密码的散列值保存到数据库。
            # 方法 save() 返回新创建的用户对象,我们将其存储到 new_user 中。
            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)
  • 1.函数 login() 和函数 authenticate()可以让用户注册成功后自动登录。

  • 2.在注册的时候,如果用户提交的注册表单数据有效,调用方法 save() 用户名和密码的散列值保存到数据库,并返回新创建的用户对象,存储到 new_user中。

  • 3.自动登录过程中,调用 authenticate()并把实参 new_user.username和密码(因为表单有效,两个密码相同,所以我们使用第一个密码'password1')传给它。

  • 4.方法 authenticate() 返回一个通过身份验证的用户对象,我们将其保存在 authenticate_user中。接下来调用函数 login(),并把对象 request 和 authenticate_user 传给他。

  • 5.最后,我们将重定向到主页,其页眉显示一个问候语,让用户知道注册成功了。

3.注册模板

rehister.html

{% extends "learning_logs/base.html" %}

{% block content %}

  
{% csrf_token %} {{ form.as_p }}
{% endblock content %} {#as_p,让 Django 在表单中正确的显示所有的字段,包括错误信息。#}

4.链接到注册页面

Learning Log - Topics {% if user.is_authenticated %} Hello, {{ user.username }}. log out {% else %} log in {% endif %}

{% block content %}{% endblock %}

现在,已登录的用户看到的是个性化的问候语和注销链接,未登录的用户看到的是注册链接和登录链接。尝试使用注册页面创建几个用户各不同的用户账号,接下来我们将对一些用户进行限制,仅让已登录的用户访问它们,我们还将确保每个主题属于特定的用户。

19.3 让用户拥有自己的数据

19.3.1 使用 @login_required 限制访问

1.限制对 topics 页面的访问

#learning_logs/views.py

--snip--
from django.contrib.auth.decorators import login_required
--snip--

# 使用 @login_required 限制访问。
# 加上装饰器( @login_required )之后,python会在运行 topics()的代码前先运行 login_required()的代码。
# login_required()会检查用户是否已登录,仅当用户已登录时,django才运行topics()。
# 如果未登录,就重定向到登录页面。 为实现重定向,需要修改 setting.py。
@login_required
def topics(request):
    --snip--

修改 setting.py

# 我的设置
# 现在,如果为登录的用户请求装饰器 @login_required 的保护页面, Django 将重定向到 setting.py 中 LOGIN_URL 指定的 URL。
LOGIN_URL = '/users/login/'

2.全面限制对项目的访问

现在,我们不限制对主页、注册、注销页面的访问,而限制对其他所有页面的访问。

在 learning_logs/views.py 中,除了index()意外,每个视图都加上 @login_required。

--snip--
@login_required
def topics(request):
    --snip--

@login_required
def topic(request, topic_id):
    --snip--

@login_required
def new_topic(request):
    --snip--

@login_required
def new_entry(request, topic_id):
    --snip--

@login_required
def edit_entry(request, entry_id):
    --snip--

19.3.2 将数据关联到用户

1.修改模型Topic

修改 learning_logs/models.py

from django.db import models
from django.contrib.auth.models import User

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):
        --snip--

我们首先导入了 django.contrib.auth.models import User ,然后在 Topic 中添加了字段 owner,它建立到模型 User 的外键关系。

2.确定有哪些用户

我们迁移数据库时,Django 将对数据库进行修改,使其能够存储主题和用户之间的关联。为执行迁移,Django 需要知道该将各个既有主题关联到那个账户。最简单的方法是,将主题都关联到一个账户。

下面先查看已创建的索引账户的ID。

启动一个 Django shell 会话

(11_env) C:\learning_log>python manage.py shell

我们遍历用户列表,打印每位用户的用户名和 ID。Django 询问要将既有主题关联懂啊哪个账户时,我们将指定其中的一个 ID 值。

3.迁移数据库

  • 1.数据迁移

知道 ID 后就可以迁移数据库了。

  • 2.应用数据迁移
  • 3.验证结果

19.3.3 只允许用户访问自己的主题

当前不管哪个用户登录,都能看到所有主题,现在我们让用户只能看到自己的主题。

修改 learning_logs/views.py

#--snip--
@login_required
def topics(request):
    '''显示所有主题'''
    # 用户登录后,request 对象会有一个 user属性,其存储了有关该用户的所有信息。
    # filter() 用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表。
    # 在这里我们用这个函数从数据库中只获取 owner 属性为当前用户的 Topic 对象。
    topics = Topic.objects.filter(owner=request.user).order_by('date_added')
    context = {'topics': topics}
    return render(request, 'learning_logs/topics.html', context)
#--snip--

19.3.4 保护用户的主题

在此之前,已登录的用户可输入 URL http://127.0.0.1:8000/topics/1/来访问显示相应主题的页面。

为修复这种问题,我们在视图函数 topic() 获取请求的条目前执行检查。

from django.shortcuts import render

from django.http import HttpResponseRedirect, Http404

from django.core.urlresolvers import reverse
#--snip--
@login_required
def topic(request, topic_id):
    '''显示单个主题以其所有条目'''
    topic = Topic.objects.get(id=topic_id)
    # 确认请求的主题属于当前用户
    if topic.name != request.user:
        raise Http404

    entries = topic.entry_set.order_by('-date_added')
    context = {'topics': topics, 'entries': entries}
    return render(request, 'learning_logs/topic.html', context
#--snip--

19.3.5 保护页面 edit_entry

@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':
       --snip--

渲染网页前检查该主题是否属于当前登录的用户,如果不是,则 raise Http404 。

19.3.6 将新主题关联到当前用户

#--snip--
@login_required
def new_topic(request):
    '''添加新主题'''
    # 确定 GET or POST,如果不为 Post,返回一个空表单。
    if request.method != 'POST':
        # 未提交数据:创建一个新表单
        form = TopicForm()
    else:
        # POST提交的数据,对数据进行处理,数据在 request.POST 中。
        form = TopicForm(request.POST)
        # 检查是否填写了所有必不可少的字段。(是否有效)
        if form.is_valid():
            # form.save()
            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)
#--snip--

首先调用 form.save(commit=False) 是为了我们先修改新主题,再将其保存到数据库中(暂时不保存到数据库)。接下来将新主题的 owner 属性设置为当前用户后,对刚定义的主题实例调用 save(),最后在保存提交到数据库中。

你可能感兴趣的:(Django入门3)