三用django2.0来开发会员注册登录
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了三用django2.0来开发会员注册登录相关的知识,希望对你有一定的参考价值。
github地址:https://gitee.com/ccnv07/django_example
本章主要讲如何实现会员的前台注册登录, 会涉及到以下模块
- 简单的路由设置
- 简单的模板操作
- 视图以及session的操作
- 比较复杂的表单
- ajax请求以及json返回资源
使用的还是上一节的model即可
实现注册功能
# account/forms.py
class AccountForm(forms.ModelForm):
# ... 忽略代码
def get_first_error(self):
# 获取所有错误转换成的json格式
errors = self.errors.get_json_data()
if errors:
for key, message_dicts in errors.items():
# 存在错误则返回第一个错误信息, 返回string
return message_dicts[0].get(‘message‘)
return None
创建注册表单
RegisterForm 会继承AccountForm
# account/forms.py
class RegisterForm(AccountForm):
# 设置场景是新增用户
# 这个不是django默认的, 是我自己加的, 作用是用来不同场景下的实现不同的自定义规则
scene = ‘insert‘
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 因为前端框架使用的是bootstrap, 所以需要给所有的表单元素添加class名称
# 同样的, 添加别的属性也可以使用
self.字段名.widget.attrs.update({‘html属性名‘, ‘html属性值‘})实现
for _field in self.fields:
self.fields[_field].widget.attrs.update({‘class‘: ‘form-control‘})
# 因为在基类中设置的password字段是非必填项, 而在注册的时候是必填的, 所以设置password的required属性为True
# 同时我们也不需要status字段, 所以设置为False
self.fields[‘password‘].required = True
self.fields[‘status‘].required = False
class Meta(AccountForm.Meta):
# 使用自定义的Form, 就必须指定fields or exclude属性, 否则报错
# 只指定表单中药用到的字段
fields = (‘account‘, ‘password‘, ‘email‘, ‘phone‘)
# 新增一个rep_password字段, 让用户输入两次密码, 防止出错
rep_password = forms.CharField(
label=‘重复密码‘,
required=True,
error_messages={‘required‘: ‘请再次输入密码‘},
widget=forms.PasswordInput())
def clean_rep_password(self):
# 验证两次输入的密码是否一致
# 因为在clean_password方法中, 已经加密了cleaned_data[‘password‘], 所以这里只能取data[‘password‘]
if self.data[‘password‘] != self.cleaned_data[‘rep_password‘]:
raise ValidationError(‘两次输入的密码不一致‘)
return self.cleaned_data[‘rep_password‘]
创建用户模块注册的路由
先在account目录中创建一个urls.py文件
然后在cms.urls中加载account中的urls.py文件
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path(‘admin/‘, admin.site.urls),
# include方法参数是urls文件的加载地址, 名字可以自己指定
path(‘account/‘, include(‘account.urls‘))
]
然后再account.urls.py中创建登录路由
# account/urls.py
from django.urls import path
from . import views
urlpatterns = [
# 访问的url路径是http://xxx/account/register
# 把请求转发给register方法
# 这个路由的名称是account-register
path(‘register/‘, views.register, name=‘account-register‘),
]
注册的具体逻辑
基本流程:
- 把数据放入form表单中
- 验证表单
- 将表单中的数据保存到数据库
- 成功/失败都返回指定资源
# account/views.py
from django.views.decorators.http import require_http_methods
from .forms import RegisterForm
from cms.utils import return_json
# 指定可以请求的方式
@require_http_methods([‘GET‘, ‘POST‘])
def register(request):
if request.method == ‘POST‘:
# 把所有POST的数据都放入表单中
form = RegisterForm(request.POST)
# 验证表单中的数据是否正确
if form.is_valid():
# 将数据保存到数据库
form.save()
# 操作成功, 将数据返回给浏览器
return return_json(url=reverse(‘account-index‘))
else:
# 验证失败, 从form中获取到第一个错误信息, 返回给浏览器
return return_json(code=1, message=form.get_first_error())
else:
form = RegisterForm()
return render(request, ‘account/register.html‘, {‘form‘: form})
在这个方法中加载了一个return_json的方法, 具体代码:
# cms/utils.py
from django.http import JsonResponse
def return_json(code = 0, message = ‘success‘, data = [], url=‘‘):
return JsonResponse({
‘code‘: code,
‘url‘: url,
‘message‘: message,
})
这个代码的意思是返回一个Json的资源给浏览器解析
插播一个关于模板的配置
django默认的模板目录在模块/templates中
比如account模块的模板目录就是在account/templates
而在一般的开发过程中会把所有模板放在一起, 所以需要修改配置文件, 指定模板目录的路径到根目录下。
# cms/settings.py
TEMPLATES = [
{
‘BACKEND‘: ‘django.template.backends.django.DjangoTemplates‘,
‘DIRS‘: [
# 将templates目录放在根目录, 也就是cms/templates中
os.path.join(BASE_DIR, ‘templates‘),
],
‘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‘,
],
},
},
]
而且静态资源(css,js,fonts,img)文件一般也放在根目录下
还是在cms/settings.py中增加配置
STATIC_URL = ‘/static/‘ # 指定静态文件的访问url前缀
STATICFILES_DIRS = (‘static‘, ) # 指定静态文件的目录地址
这样模板和静态资源的新路径就成了cms/templates, cms/static
样式文件使用的是bootstrap. 大家可以提前下载, 并且提前放入static文件中
然后目录就变为以下这样
cms/
templates/
static/
css/
fonts/
js/
创建注册表单模板
在templates中创建layout.html 框架文件
layout.html中包含的是所有模板共用的地方, 并且通过block标签占位符来占位, 别的模板可以继承layout.html, 然后修改block标签的占位符中的内容, 可以大幅度减少代码量
# templates/layout.html
<!-- 加载static模板, 作用是为了使用 {% static ‘filepath‘%} 来加载静态资源-->
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<!-- block名称为title的占位符-->
<title>{% block title %} {% endblock %}</title>
<!-- 完全的文件地址是static/css/bootstrap.min.css-->
<link rel="stylesheet" href="{% static ‘css/bootstrap.min.css‘%}">
</head>
<body>
{% block body %} {% endblock %}
</body>
<script src="{% static ‘js/jquery.min.js‘ %}"></script>
<script src="{% static ‘js/bootstrap.min.js‘ %}"></script>
<script src="{% static ‘js/layer/layer.js‘ %}"></script>
<script src="{% static ‘js/utils.js‘ %}"></script>
</html>
注册模板文件,templates/account/register.html
<!-- 继承layout.html-->
{% extends ‘layout.html‘ %}
<!-- 将占位符名称为title中的内容改为【注册】-->
{% block title %} 注册 {% endblock %}
{% block body %}
<div class="container">
<div class="row" style="width:500px">
<!-- url ‘路由的名称, 就是urls中的name‘-->
<form action="{% url ‘account-register‘%}" method="post" onsubmit="return post(this)">
{% csrf_token %}
<div class="form-group">
<label for="{{ form.account.id_for_label}}">{{ form.account.label}}</label> {{ form.account}}
</div>
<div class="form-group">
<label for="{{ form.password.id_for_label}}">{{ form.password.label}}</label> {{ form.password}}
</div>
<div class="form-group">
<label for="{{ form.rep_password.id_for_label}}">{{ form.rep_password.label}}</label> {{ form.rep_password}}
</div>
<div class="form-group">
<label for="{{ form.email.id_for_label}}">{{ form.email.label}}</label> {{ form.email}}
</div>
<div class="form-group">
<label for="{{ form.phone.id_for_label}}">{{ form.phone.label}}</label> {{ form.phone}}
</div>
<input type="submit" value="提交" class="btn btn-success">
</form>
</div>
</div>
{% endblock %}
关于form的重点说明
form.字段名是访问到字段
form.字段名.id_for_label, 是返回字段的id
form.字段名.label, 是label名称
form.字段名 会直接返回表单元素的html
比如form.account就会变成<input type="password" name="password" maxlength="12" minlength="6" class="form-control" required id="id_password" />
代码中return post(this)
的js function代码如下
# static/js/utils.js
function post(form) {
$.ajax({
url: $(form).attr(‘action‘),
method: ‘POST‘,
dataType: ‘json‘,
data: $(form).serialize(),
success: function(data) {
if (data.code == 0) {
layer.msg(‘操作成功‘);
window.location.href = data.url;
} else {
layer.msg(data.message);
}
}
})
return false;
}
启动开发服务器并测试
python manager.py runserver
实现登录方法
实现登录的方法和注册的流程是一样的, 可以自己尝试实现以下, 如果有难度可以对照我的代码
# account/forms.py
class LoginForm(AccountForm):
scene = ‘login‘
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for _field in self.fields:
self.fields[_field].widget.attrs.update({‘class‘: ‘form-control‘})
# 设置密码为必须输入项
self.fields[‘password‘].required = True
self.fields[‘email‘].required = False
self.fields[‘phone‘].required = False
self.fields[‘status‘].required = False
class Meta(AccountForm.Meta):
# 使用自定义的Form, 就必须指定fields or exclude属性, 否则报错
fields = (‘account‘, ‘password‘)
# account/views.py
from django.shortcuts import render
from django.urls import reverse
from django.views.decorators.http import require_http_methods
from django.shortcuts import redirect
from .forms import RegisterForm, LoginForm
from .utils import authenticate, login_required
from cms.utils import return_json
from functools import wraps
@login_required(login_url=‘/account/login/‘)
def index(request):
return render(request, template_name=‘account/index.html‘)
@require_http_methods([‘GET‘, ‘POST‘])
def login(request):
if request.method == ‘POST‘:
form = LoginForm(request.POST)
if form.is_valid():
user = authenticate(
request,
account=form.cleaned_data[‘account‘],
password=form.cleaned_data[‘password‘])
if user is not None:
return return_json(url=reverse(‘account-index‘))
else:
return return_json(code=1, message=‘账号或密码不正确‘)
else:
return return_json(code=1, message=form.get_first_error())
else:
form = LoginForm()
return render(request, ‘account/login.html‘, {‘form‘: form})
# account/utils.py
from .models import Account
from django.contrib.auth.hashers import check_password
from django.shortcuts import redirect
from functools import wraps
def authenticate(request, account, password):
try:
user = Account.objects.get(account=account)
except Account.DoesNotExist:
return None
if not check_password(password, user.password):
return None
request.session[‘user_id‘] = user.id
request.session[‘account‘] = user.password
return user
def login_required(func=None, login_url=‘‘):
def wrapper(func):
@wraps(func)
def _func(request, *arg, **kwargs):
if request.session.get(‘user_id‘):
return func(request, *arg, **kwargs)
else:
return redirect(login_url)
return _func
return wrapper
request.session就是一个session对象, 可以用来保存用户登录后的信息, 使用方法和dict完全一样。
以上是关于三用django2.0来开发会员注册登录的主要内容,如果未能解决你的问题,请参考以下文章