Django从零搭建个人博客 | 使用allauth插件管理用户登录与注册
原文博客地址:http://www.eosones.com/
django-allauth是最受欢迎的管理用户登录与注册的第三方django安装包,可以大大简化我们用户注册,登录及账户管理,其核心功能包括用户注册、忘记密码、登录(微信,微博等第三方登录;邮箱验证)、登录后密码重置、邮箱发送密码重置链接、退出等。
安装与设置
运行cmd,打开虚拟环境
pip install django-allauth
安装好后设置myblog / settings.py,将allauth相关app加入到installed_app里去。对于第三方的providers,根据需要添加。[ 官网providers文档 ](https://django-allauth.readthedocs.io/en/latest/providers.html " 第三方providers")
installed_apps = [ ..., #django-allauth必须安装的app 'django.contrib.sites', 'allauth', 'allauth.account', 'allauth.socialaccount', #第三方账号相关,根据需求添加 'allauth.socialaccount.providers.weibo', 'allauth.socialaccount.providers.github', ]
同时还需要一些设置
# django-allauth相关设置 authentication_backends = ( # django admin所使用的用户登录与django-allauth无关 'django.contrib.auth.backends.modelbackend', # allauth 身份验证 'allauth.account.auth_backends.authenticationbackend', ) #app django.contrib.sites需要的设置 site_id = 1 # 指定要使用的登录方法(用户名、电子邮件地址两者之一) account_authentication_method = 'username_email' # 要求用户注册时必须填写email account_email_required = true
配置邮箱:allauth 在注册用户时,会给用户填写的邮箱发送一封激活邮件,在重置密码时也可通过邮箱进行重置。如果你没有邮件服务器,可以设置成自己的qq或163邮箱,localhost环境下一样可以使用。[ 如何获取邮箱授权码 ](https://mp.weixin.qq.com/s?__biz=mjm5otmyoda4nw==&mid=2247483732&idx=1&sn=b022e3c3b789c09ae1d856cd49ed0764&chksm=a73c616c904be87a84821da1a3f79d3d548da67c36a011ef1c914203694444c4f003b265520e&scene=21#wechat_redirect" 如何获取邮箱授权码 ")
# smtp 服务器地址 email_host = "smtp.qq.com" # 默认端口25,若请求超时可尝试465 email_port = 25 # 用户名 email_host_user = "374542101@qq.com" # 邮箱代理授权码(不是邮箱密码) email_host_password = "password" # 是否使用了ssl 或者tls(两者选其一) # email_use_tls = true email_use_ssl = true # 发送人 email_from = "374542101@qq.com" # # 默认显示的发送人,(邮箱地址必须与发送人一致),不设置的话django默认使用的webmaster@localhost default_from_email = "eosones 博客 <374542101@qq.com>"
修改时区
language_code = 'zh-hans' time_zone = 'asia/shanghai' use_i18n = true use_l10n = true use_tz = false
将 allauth 添加加到总项目的 urls.py 中
# myblog/urls.py from django.conf.urls import re_path,include urlpatterns = [ ..., #django-allauth插件 re_path(r'^accounts/', include('allauth.urls')), ]
django-allauth 常见设置选项
# 要求用户注册时必须填写email account_email_required = true # 注册中邮件验证方法: "强制(mandatory)"、 "可选(optional)" 或 "否(none)" 之一 (注册成功后,会发送一封验证邮件,用户必须验证邮箱后,才能登陆) account_email_verification (="optional") # 作用于第三方账号的注册 socialaccount_email_verification = 'optional' / 'mandatory' / 'none' # 邮件发送后的冷却时间(以秒为单位) account_email_confirmation_cooldown (=180) # 邮箱确认邮件的截止日期(天数) account_email_confirmation_expire_days (=3) # 指定要使用的登录方法(用户名、电子邮件地址或两者之一) account_authentication_method (="username" | "email" | "username_email") # 登录尝试失败的次数 account_login_attempts_limit (=5) # 从上次失败的登录尝试,用户被禁止尝试登录的持续时间 account_login_attempts_timeout (=300) # 更改为true,用户一旦确认他们的电子邮件地址,就会自动登录 account_login_on_email_confirmation (=false) # 更改或设置密码后是否自动退出 account_logout_on_password_change (=false) # 更改为true,用户将在重置密码后自动登录 account_login_on_password_reset (=false) # 控制会话的生命周期,可选项还有: "false" 和 "true" account_session_remember (=none) # 用户注册时是否需要输入邮箱两遍 account_signup_email_enter_twice (=false) # 用户注册时是否需要用户输入两遍密码 account_signup_password_enter_twice (=true) # 用户不能使用的用户名列表 account_username_blacklist (=[]) # 加强电子邮件地址的唯一性 account_unique_email (=true) # 用户名允许的最小长度的整数 account_username_min_length (=1) # 使用从社交账号提供者检索的字段(如用户名、邮件)来绕过注册表单 socialaccount_auto_signup (=true) # 设置登录后跳转链接 login_redirect_url (="/") # 设置退出登录后跳转链接 account_logout_redirect_url (="/") # 用户登出是否需要确认确认(true表示直接退出,不用确认;false表示需要确认) account_logout_on_get (=true)
测试效果
首先生成数据库
python manage.py makemigrations python manage.py migrate
登录 admin,将 example.com 改为我们博客的域名,在开发环境下,我们用127.0.0.1:8000,并设置好 site 名字(邮箱中显示)再退出登录。现在你就可以访问以下链接查看allauth的效果了。由于我们已经设置好了邮箱,所以涉及邮箱验证和密码重置部分都可以正常进行的。注册:http://127.0.0.1:8000/accounts/signup/
登录:http://127.0.0.1:8000/accounts/login/
django-allauth表单会自带验证,检查用户名和email是否已经注册,同时检查密码强度是否够以及用户输入的两次密码是不是一致。当注册成功后,用户会收到一封邮件来验证邮箱,如果account_email_verification = 'mandatory'
,用户必须通过邮箱验证后才能登陆。如果你不需要邮箱验证,只需要设置 account_email_verification = 'none'
就可以了。
1、内置的urls
/accounts/login/ #(url名account_login): 登录 /accounts/signup/ #(url名account_signup): 注册 /accounts/password/reset/ #(url名: account_reset_password) :重置密码 /accounts/logout/ #(url名account_logout): 退出登录 /accounts/password/set/ # (url名:account_set_password): 设置密码 /accounts/password/change/ #(url名: account_change_password): 改变密码(需登录) /accounts/email/ #(url名: account_email) 用户可以添加和移除email,并验证 /accounts/social/connections/ #(url名:socialaccount_connections): 管理第三方账户
扩展用户模型
django-allauth 并没有提供展示和修改用户资料的功能,也没有对用户资料进行扩展,所以我们需要自定义用户模型来进行扩展。
1、创建 app 及配置
由于 django-allauth 已经占用了 account 这个 app,所以我们可以创建一个叫 myaccount 的 app,并将其加入 settings.py 配置文件的 install_apps 中,同时把 url 也加入到项目 settings.py 中。
python manage.py startapp myaccount
# myblog/settings.py installed_apps = [ ..., 'myaccount', #django-allauth必须安装的app ..., ]
# myblog/urls.py from django.conf.urls import re_path,include urlpatterns = [ ..., #django-allauth插件 re_path(r'^accounts/', include('allauth.urls')), #django-allauth用户自定义信息扩展 re_path(r'^accounts/', include('myaccount.urls',namespace='accounts')), ]
因为我们希望用户在登录或注册成功后,自动跳转到个人信息页 "/accounts/profile/",所以在前面的配置中加入了如下代码
# myblog/settings.py login_redirect_url = "/accounts/profile/"
2、创建用户模型及表单
首先自定义的 user 模型继承了 abstractuser ,abstractuser 是 django 自带用户类,可扩展用户个人信息,abstractuser 模块下有:password、username、first_name、last_name、email、last_loginl、is_superuserl、is_staffl、is_activel、date_joined 字段,自定义用户user扩展了 nickname、link 及头像 avatar 字段,此处重写了user的 save() 方法以便上传的头像以用户名为文件夹分类。
# myaccount/models.py from django.db import models #from django.contrib.auth.models import user from django.contrib.auth.models import abstractuser #用pillow、django-imagekit模块设置图片,可以处理图片,生成指定大小的缩略图,前端显示src="{{ user.avatar.url }} from imagekit.models import processedimagefield from imagekit.processors import resizetofill #扩展django自带的user模型字 class user(abstractuser): nickname = models.charfield(max_length=30, blank=true, null=true, verbose_name='昵称') # 扩展用户个人网站字段 link = models.urlfield('个人网址', blank=true, help_text='提示:网址必须填写以http开头的完整形式') # 扩展用户头像字段,upload_to后必须是相对路径,上传路径已设置为media,因此upto不需要media/avatar,数据库中avatar/...,前端用avatar.url为media/avatar/... avatar = processedimagefield(upload_to='avatar',default='avatar/default.png',verbose_name='头像', processors=[resizetofill(100, 100)], # 处理后的图像大小 format='jpeg', # 处理后的图片格式 options={'quality': 95} # 处理后的图片质量 ) #重写user的save()方法保存上传的头像目录 def save(self, *args, **kwargs): # 当用户更改头像的时候,avatar.name = '文件名',其他情况下avatar.name = 'upload_to/文件名' if len(self.avatar.name.split('/')) == 1: self.avatar.name = self.username + '/' + self.avatar.name #调用父类的save()方法后,avatar.name就变成了'upload_to/用户名/文件名' super(user, self).save() # 定义网站管理后台表名 class meta: verbose_name = '用户信息' verbose_name_plural = verbose_name #指定模型的复数形式是什么,如果不指定django会自动在模型名称后加一个’s’ ordering = ['-id'] #admin后台显示名字关联到此表的字段的后天显示名字 def __str__(self): return self.username
为了让 django 能够识别自定义的用户模型,需要在 settings.py 中需配置auth_user_model='myaccount.user'
,注册的用户就会基于自定义user模型创建,并一同创建account中与自定义user关联的模型。
# myaccount/forms.py from django import forms from .models import user class profileform(forms.form): class meta: # 关联的数据库模型,这里是用户模型 model = user # 前端显示、可以修改的字段(admin中) fields = ['nickname''link', 'avatar']
3、创建视图并配置urls
我们需要创建2个urls和对应的视图来实现用户资料展示和用户资料编辑页面。
# myaccount/urls.py from django.conf.urls import re_path from . import views app_name = "myaccount" urlpatterns = [ re_path(r'^profile/$', views.profile, name='profile'), re_path(r'^profile/update/$', views.profile_update, name='profile_update'), ]
因为我们希望用户在登录或注册后自动跳转到/accounts/profile/, 需要在 settings.py 中需配置
login_redirect_url = '/accounts/profile/'
视图函数根据需求自定义,本博客前端用的是ajax请求修改网站link与头像avatar供参考
#myaccount/views.py from django.shortcuts import render from django.http import httpresponse from myaccount import models # create your views here. #auth中用户权限有关的类。auth可以设置每个用户的权限。 from django.contrib.auth.decorators import login_required from django.views.decorators.csrf import csrf_exempt # 使用login_required装饰器,用户只有登录了才能访问其用户资料 @login_required #个人信息 def profile(request): # auth_user_model 类型的对象,表示当前登录的用户。 user = request.user return render(request, 'account/profile.html', {'user': user}) import json import base64 @login_required # 使用login_required装饰器,用户只有登录了才能访问其用户资料 @csrf_exempt #取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。 def profile_update(request): #request.is_ajax(): #判断请求头中是否含有x-requested-with的值 if request.is_ajax(): key=request.post.get('key')#request.post.get('')不存在默认为空,request.post[]不存在报错 if key=='link': link=request.post['link'] username=request.post['username'] models.user.objects.filter(username=username).update(link=link) link=models.user.objects.filter(username=username).first().link linkjson={'link':link} return httpresponse(json.dumps(linkjson)) elif key=='avatar': username=request.post['username'] #用modelform可代替手动编写代码存储上传文件 user_profile=models.user.objects.filter(username=username).first() user_profile.avatar=request.files.get('avatar') user_profile.save() url=user_profile.avatar.url datajson={'url':url} return httpresponse(json.dumps(datajson))
4、设计前端模板
前端根据需求自定义设计,本博中客个人信息只允许更改头像与个人网站,参考请到github查看源码。
需要注意前后端的交互信息,通过view中传来的当前用户模型user,可通过django的模板语言显示用户名:{{ user.username }}
,用户邮箱:{{ user.link }}
、用户头像链接:{{ user.avatar.url }}
、以及用户邮箱:{{ user.emailaddress_set .0}}
(django-allauth在注册用户时创建的accounts表,关联自定义模型user,包含用户的邮箱信息及各种方法)、django-allauth判断邮箱是否验证:{% if user.emailaddress_set .0.verified %}
、django判断用户是否登录:{% if user.is_authenticated %}
等等。
美化页面模板
django-allauth自带的页面很简陋,我们需要进行美化。如果你是通过pip安装的django-allauth,模板位置一般在python安装位置或者虚拟环境下的blog_env\lib\site-packages中,找到\allauth\templates下的整个account文件夹,或者从github上([ allauth项目地址 ](https://github.com/pennersr/django-allauth/tree/master/allauth " allauth项目地址"))将allauth的/templates/accounts/文件夹整个拷贝到你的本地项目中的templates目录下,因为django-allauth总是会在templates/accounts/文件夹中寻找模板。
1、美化base.html
不管是注册,登录还是重置密码页面,html模板主要内容都是表单。我们将使用bootstrap迅速美化模板和表单。最快速的方式就是修改base.html(如果没有该文件,你需要创建一个),加入boostrap样式和js。
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="x-ua-compatible" content="ie=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>{% block head_title %} {% endblock %}</title> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" > </head> <body> <main> <div class="container"> {% block content %} {% endblock %} </div> </main> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0msbjdehialfmubbqp6a4qrprq5ovfw37prr3j5elqxss1yvqotnepnhvp9aj7xs" crossorigin="anonymous"></script> </body> </html>
我们以注册页面为例,教你如何美化 django-allauth 的表单。注册页面默认的 signup.html 代码如下,我们先不做任何修改。
{% extends "account/base.html" %} {% load i18n %} {% block head_title %}{% trans "signup" %}{% endblock %} {% block content %} <h1>{% trans "sign up" %}</h1> <p>{% blocktrans %}already have an account? then please <a href="{{ login_url }}">sign in</a>.{% endblocktrans %}</p> <form class="signup" id="signup_form" method="post" action="{% url 'account_signup' %}"> {% csrf_token %} {{ form.as_p }} {% if redirect_field_value %} <input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" /> {% endif %} <button type="submit">{% trans "sign up" %} »</button> </form> {% endblock %}
2、美化注册表单
一个标准的 boostrap 表单代码如下,每个输入字段 field 都是包围在div里的class="form-group"
,同时每个 input 的 css 都有 form-control 这个属性。而我们django的表单渲染 form.as_p 或则 form.as_table 显然满足不了我们的要求,因为我们没法将 css 类名加进去。
<form> <div class="form-group"> <label for="id_email">email address</label> <input type="email" class="form-control" id="id_email" name="email"> </div> <div class="form-group"> <label for="id_password">password</label> <input type="password" class="form-control" id="id_password" name="password"> </div> <button type="submit" class="btn btn-default">submit</button> </form>
当然可以使用自定义widge的属性来给各个字段添加css,或者直接使用django-crispy-forms表单,这两种相对耦合度较高,此处推荐使用插件django-widget-teaks,在前端模板中不仅可以为字段添加样式,还提供了强大的render_field方法,可以自定义某个字段的css和提示词placeholder。
进入cmd,打开虚拟环境
pip install django-widget-tweaks
安装成功后,需要把它加到 installed_app 中,这时在模板中{% load widget_tweaks %},你就可以给你想要的字段添加css了。以signup.html,我们给每个输入字段都加入了form-control属性。
{% extends "account/base.html" %} {% load i18n %} {% load widget_tweaks %} {% block head_title %}{% trans "signup" %}{% endblock %} {% block content %} <h1>{% trans "sign up" %}</h1> <p>{% blocktrans %}already have an account? then please <a href="{{ login_url }}">sign in</a>.{% endblocktrans %}</p> <form class="signup" id="signup_form" method="post" action="{% url 'account_signup' %}"> {% csrf_token %} {% for hidden in form.hidden_fields %} {{ hidden }} {% endfor %} {% for field in form.visible_fields %} <div class="form-group"> <label for="{{ field.id_for_label }}">{{ field.label }}</label> {{ field|add_class:'form-control' }} {% for error in field.errors %} <span class="help-block">{{ error }}</span> {% endfor %} </div> {% endfor %} {% if redirect_field_value %} <input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" /> {% endif %} <div class="form-group"> <button type="submit" class="btn btn-success"">{% trans "sign up" %}</button> </div> </form> {% endblock %}
根据页面自定义功能,美化表单后,添加到页面中。本博客设计如下图所示,参考前端代码请到 github 查看。(第三方登录方式添加到installed_app中后,便会出现在login模板中,第三方列表模板位置在插件包中的allauth\templates\socialaccount\snippets\provider_list.html 中,可进行自定义美化)。安照此方法,可依次将需要的模板进行美化。
3、修改邮件信息
注册修改密码的过程中,都会收到邮件信息,在我们复制到templates\account\mail文件中的txt文件即是我们邮件中的提示信息,根据需求自定义修改
第三方账号登录
1、github
1、首先在github中申请 oauth github oauth注册页面,要注意将回调地址callback url设置为 http://127.0.0.1:8000/accounts/github/login/callback/,设置完成后可在账号的 settings / developer settings / oauth apps 中查找更新,上线需要将127.0.0.1:8000
更新为我们的博客域名
2、进入admin后台,更新站点,将example.com
改为我们博客的域名,在开发环境下,我们用127.0.0.1:8000
,然后点击 social accounts 下的 social application,增加一个application,如下图所示
provider选github,这里的provider就是我们在installed_app里增加的第三方socialaccount.provider,client id 和 secret key 我们在github注册应用里获得了,将 sites 加入到右边 选中的 sites。
完成以上设置后,注销,然后回到登录页面,选中 github 登录,授权应用即可,成功登录后,邮箱里也会收到一份激活邮件,这是因为 django-allauth 会自动为我们添加一个本地账号,根据你的 social account 用户名和 email 。
2、微信
1、 首先注册微信开放平台账号,登录后在管理中心—网站应用—创建网站应用,填写网站相关信息进行申请,一般会在7个工作日内完成审核。
需注意的是,注册信息需要公章,目前没有发现个人注册的方法,卒。
参考: