第四章Django by example

创建一个社交网站

重点:

  • 使用认证(authentication)框架
  • 创建用户注册视图(views)
  • 通过一个定制的profile模型(model)扩展User模型(model)
  • 使用python-social-auth添加社交认证

开始社交网站项目

django-admin startproject bookmarks#创建项目文件夹
cd bookmarks
django-admin startapp account
#settings文件installed_apps中添加account应用

注意!!! 要把INSTALLED_APPS 的‘account’,放在'django.contrib.admin'前面,否则会优先寻找内置admin应用的account。

使用认证框架

Django拥有一个内置的认证(authentication)框架用来操作用户认证(authentication),会话(sessions),权限(permissions)以及用户组。这个认证(authentication)系统包含了一些普通用户的操作视图(views),例如:登录,登出,修改密码以及重置密码。

这个认证(authentication)框架位于django.contrib.auth,被其他Django的contrib包调用。
当你使用startproject命令创建一个新的Django项目,认证(authentication)框架已经在你的项目设置中默认包含。它是由django.contrib.auth应用和你的项目设置中的MIDDLEWARE_CLASSES中的两个中间件类组成,如下:

AuthenticationMiddleware:使用会话(sessions)将用户和请求(requests)进行关联
SessionMiddleware:通过请求(requests)操作当前会话(sessions)
中间件就是一个在请求和响应阶段带有全局执行方法的类。

这个认证(authentication)系统还包含了以下模型(models):

  • User:一个包含了基础字段的用户模型(model);这个模型(model)的主要字段有:username, password, email, first_name, last_name, is_active。
  • Group:一个组模型(model)用来分类用户
  • Permission:执行特定操作的标识
    这个框架还包含默认的认证(authentication)视图(views)和表单(forms)

创建一个log-in视图(view)

1.通过提交的表单(form)获取username和password
2.通过存储在数据库中的数据对用户进行认证
3.检查用户是否可用
4.登录用户到网站中并且开始一个认证(authentication)会话(session)
先创建一个表单

from django import forms #导入表单文件夹
class LoginForm(forms.Form):#继承表单类
    username = forms.CharField(max_length=200)#username为字符串字段
    password = forms.CharField(widget=forms.PasswordInput)# password为字符串字段,控件为PasswordInput
#这个表单(form)被用来通过数据库认证用户。请注意,我们使用PasswordInput控件来渲染HTMLinput元素,包含type="password"属性

创建视图

from django.contrib.auth import authenticate, login
from django.http import HttpResponse
from django.shortcuts import render

from .forms import LoginForm


def user_login(request):
    if request.method == "POST":
        form = LoginForm(request.POST)
        if form.is_valid():
            cd = form.cleaned_data
            username = cd['username']
            password = cd['password']
            user = authenticate(username=username, password=password)  # 对过数据库对这个用户进行认证,成功返回user对象,失败返回None
            if user is not None:
                if user.is_active:  # 用is_active属性来检查用户是否可用
                    login(request, user)  # login()将用户设置到当前的会话(session)中。
                    return HttpResponse("登陆成功")
                else:
                    return HttpResponse("用户被禁止登陆")
            else:
                return HttpResponse("用户不存在")
    else:
        form = LoginForm()
    return render(request, 'account/login.html', {'form': form})

创建url模式

from django.conf.urls import url

from . import views

urlpatterns = [
    url('^login$', views.user_login, name="login"),
]
from django.conf.urls import url,include
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^account/',include('account.urls')),
]

创建html文件
结构

    templates/
        account/
            login.html
        base.html

base.html文件

{% load staticfiles %}    
<!DOCTYPE html>    
<html>    
    <head>      
        <title>{% block title %}{% endblock %}</title>      
        <link href="{% static "css/base.css" %}" rel="stylesheet">    
    </head>    
    <body>      
        <div id="header">        
            <span class="logo">Bookmarks</span>      
        </div>      
        <div id="content">        
            {% block content %}        
            {% endblock %}      
        </div>    
    </body>    
</html>

login.html文件

{% extends "base.html" %}
{% block title %}Log-in{% endblock %}
{% block content %}
    <h1>Log-in</h1>
    <p>Please, use the following form to log-in:</p>
    <form action="." method="post">
        {{ form.as_p }}
        {% csrf_token %}
        <p><input type="submit" value="Log-in"></p>
    </form>
{% endblock %}


使用Django认证(authentication)视图(views)

Django在认证(authentication)框架中包含了一些开箱即用的表单(forms)和视图(views)。你之前创建的登录视图(view)是一个非常好的练习用来理解Django中的用户认证(authentication)过程。无论如何,你可以在大部分的案例中使用默认的Django认证(authentication)视图(views)。
Django提供以下视图(views)来处理认证(authentication):

  • login:操作表单(form)中的登录然后登录一个用户

  • logout:登出一个用户

  • logout_then_login:登出一个用户然后重定向这个用户到登录页面

  • Django提供以下视图(views)来操作密码修改:

  • password_change:操作一个表单(form)来修改用户密码

  • password_change_done:当用户成功修改他的密码后提供一个成功提示页面
    Django还包含了以下视图(views)允许用户重置他们的密码:

  • password_reset:允许用户重置他的密码。它会生成一条带有一个token的一次性使用链接然后发送到用户的邮箱中。

  • password_reset_done:告知用户已经发送了一封可以用来重置密码的邮件到他的邮箱中。

  • password_reset_complete:当用户重置完成他的密码后提供一个成功提示页面。
    当你创建一个带有用户账号的网站时,以上的视图(views)可以帮你节省很多时间。你可以覆盖这些视图(views)使用的默认值,例如需要渲染的模板位置或者视图(view)需要使用到的表单(form)。
    更多信息
    (https://docs.djangoproject.com/en/1.8/topics/auth/default/#module-django.contrib.auth.views)

登录和登出视图(views)

from django.conf.urls import url
from . import views
from django.contrib.auth.views import login,logout,logout_then_login  # 导入django自带的视图函数

urlpatterns = [
    # url('^login/$', views.user_login, name="login"),
    url('^login/$',login,name='login'),
    url('^logout/$', logout, name='logout'),
    url('^logout_then_login/$', logout_then_login, name='logout_then_login'),
]

在account应用中的template目录下创建一个新的目录命名为registration。这个路径是Django认证(authentication)视图(view)期望你的认证(authentication)模块(template)默认的存放路径。在这个新目录中创建一个新的文件,命名为login.htm

{% extends "base.html" %}
{% block title %}Log-in{% endblock %}
{% block content %}
  <h1>Log-in</h1>
  {% if form.errors %}
    <p>
      Your username and password didn't match.
      Please try again.
    </p>
  {% else %}
    <p>Please, use the following form to log-in:</p>
  {% endif %}
  <div class="login-form">
    <form action="{% url 'login' %}" method="post">
      {{ form.as_p }}
      {% csrf_token %}
      <input type="hidden" name="next" value="{{ next }}" />#隐藏标签,参数next
      <p><input type="submit" value="Log-in"></p>
    </form>
  </div>
 {% endblock %}

备注:在任何页面中,只要有登陆的<a>标签,比如<a href="{% url 'login' %}?next={{request.path}}",此时,url符合login urls匹配,交由login视图函数处理,同时传给视图函数next参数,login视图函数中,通过 redirect_to = request.POST.get('next', request.GET.get('next', ''))从get中或者post中获得next参数值。
一开始是GET方式,渲染表单,同时在form中添加了一个隐藏的input标签提供next参数,之后提供POST方式,同样交由login视图函数来处理,此时,从post中获得next参数,然后redirect(redirect_to)重定向到next这个页面!!!

我们添加了一个隐藏的HTML<input>元素来提交叫做next的变量值。当你在请求(request)中传递一个next参数(举个例子:http://127.0.0.1:8000/account/login/?next=/account/),这个变量是登录视图(view)首个设置的参数。
next参数必须是一个URL。当这个参数被给予的时候,Django登录视图(view)将会在用户登录完成后重定向到给予的URL。

logged_out.html

{% extends "base.html" %}
{% block title %}Logged out{% endblock %}
{% block content %}
  <h1>Logged out</h1>
  <p>You have been successfully logged out. You can <a href="{% url "login" %}">log-in again</a>.</p>
{% endblock %}

设置主页dashboard.html及base.html

<div id="header">
<span class="logo">Bookmarks</span>
{% if request.user.is_authenticated %}
     <ul class="menu">
      <li {% if section == "dashboard" %}class="selected"{% endif %}>
        <a href="{% url "dashboard" %}">My dashboard</a>
      </li>
      <li {% if section == "images" %}class="selected"{% endif %}>
        <a href="#">Images</a>
      </li>
      <li {% if section == "people" %}class="selected"{% endif %}>
        <a href="#">People</a>
       </li>
      </ul>
     {% endif %}
     <span class="user">
       {% if request.user.is_authenticated %}#如果已经登陆
         Hello {{ request.user.first_name }},#显示登陆名
         <a href="{% url "logout" %}">Logout</a>#显示登出连接
       {% else %}#用户未登陆
         <a href="{% url "login" %}">Log-in</a>#显示登陆连接
       {% endif %}
    </span>
</div>
{% extends "base.html" %}
{% block title %}Dashboard{% endblock %}
{% block content %}
  <h1>Dashboard</h1>
  <p>Welcome to your dashboard.</p>
{% endblock %}
urlpatterns = [
    # ...
    url(r'^$', views.dashboard, name='dashboard'),
]

settings中设置

from django.core.urlresolvers import reverse_lazy
LOGIN_REDIRECT_URL = reverse_lazy('dashboard')#告诉Django用户登录成功后如果contrib.auth.views.login视图(view)没有获取到next参数将会默认重定向到哪个UR
LOGIN_URL = reverse_lazy('login')#重定向用户登录的URL(例如:使用login_required装饰器(decorator))
LOGOUT_URL = reverse_lazy('logout')#重定向用户登出的URL。

我们使用reverse_lazy()来通过它们的名字动态构建URL。reverse_lazy()方法就像reverse()所做的一样reverses URLs,但是你可以通过使用这种方式在你项目的URL配置被读取之前进行reverse URLs。


修改密码视图(views)

urlpatterns设置

# change password urls
url(r'^password-change/$',
   'django.contrib.auth.views.password_change',
   name='password_change'),
url(r'^password-change/done/$',
   'django.contrib.auth.views.password_change_done',
   name='password_change_done'),

password_change_form.html是django自带的视图使用的html文件名

{% extends "base.html" %}
{% block title %}Change you password{% endblock %}
{% block content %}
  <h1>Change you password</h1>
  <p>Use the form below to change your password.</p>
  <form action="." method="post">
    {{ form.as_p }}
    <p><input type="submit" value="Change"></p>
    {% csrf_token %}
  </form>
{% endblock %}

password_change_done.html

{% extends "base.html" %}
{% block title %}Password changed{% endblock %}
{% block content %}
  <h1>Password changed</h1>
  <p>Your password has been successfully changed.</p>
 {% endblock %}

重置密码视图(views)

使用django.contrib.auth.views中的
password_reset,
password_reset_done,
password_reset_confirm,
password_reset_complete

# restore password urls
 url(r'^password-reset/$',
    'django.contrib.auth.views.password_reset',
    name='password_reset'),
 url(r'^password-reset/done/$',
     'django.contrib.auth.views.password_reset_done',
     name='password_reset_done'),
  url(r'^password-reset/confirm/(?P<uidb64>[-\w]+)/(?P<token>[-\w]+)/$',
       'django.contrib.auth.views.password_reset_confirm',
     name='password_reset_confirm'),
 url(r'^password-reset/complete/$',
     'django.contrib.auth.views.password_reset_complete',
      name='password_reset_complete'),

先编辑password_reset默认的2个html文件,template_name='registration/password_reset_form.html', email_template_name='registration/password_reset_email.html'

password_reset_form.html(视图函数会处理此html,同时,发送邮件以及reverse生成password_reset_done的url,生成url后由password_reset_done函数来处理)

{% extends "base.html" %}
{% block title %}Reset your password{% endblock %}
{% block content %}
  <h1>Forgotten your password?</h1>
  <p>Enter your e-mail address to obtain a new password.</p>
  <form action="." method="post">
    {{ form.as_p }} #邮件输入表单
    <p><input type="submit" value="Send e-mail"></p>
    {% csrf_token %}
  </form>
{% endblock %}

password_reset_email.html

Someone asked for password reset for email {{ email }}. Follow the link below:
{{ protocol }}://{{ domain }}{% url "password_reset_confirm" uidb64=uid token=token %}
Your username, in case you've forgotten: {{ user.get_username }}

password_reset_done.html

{% extends "base.html" %}
{% block title %}Reset your password{% endblock %}
{% block content %}
  <h1>Reset your password</h1>
  <p>We've emailed you instructions for setting your password.</p>
  <p>If you don't receive an email, please make sure you've entered the address you registered with.</p>
{% endblock %}

从收到邮件的连接url进入password_reset_confirm的html

{% extends "base.html" %}
{% block title %}Reset your password{% endblock %}
{% block content %}
  <h1>Reset your password</h1>
  {% if validlink %}
    <p>Please enter your new password twice:</p>
    <form action="." method="post">
      {{ form.as_p }}
      {% csrf_token %}
      <p><input type="submit" value="Change my password" /></p>
    </form>
  {% else %}
    <p>The password reset link was invalid, possibly because it has already been used. Please request a new password reset.</p>
  {% endif %}
{% endblock %}

修改完密码后的password_reset_complete.html

{% extends "base.html" %}
{% block title %}Password reset{% endblock %}
{% block content %}
  <h1>Password set</h1>
  <p>Your password has been set. You can <a href="{% url "login" %}">log in now</a></p>
{% endblock %}

以上完成了重置密码的过程,别忘了在login中添加连接以及settings中设置发送邮件相关配置(第二章中记录)

学习源于夜夜月翻译的django by example

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,761评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,953评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,998评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,248评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,130评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,145评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,550评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,236评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,510评论 1 291
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,601评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,376评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,247评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,613评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,911评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,191评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,532评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,739评论 2 335

推荐阅读更多精彩内容