示例代码:
form
from django import forms
from django.conf import settings
from django.core.exceptions import ValidationError
from django.core.validators import RegexValidator
from django_redis import get_redis_connection
from utils.encrypt import md5
from utils import ytx
from web import models
class LoginForm(forms.Form):
role = forms.ChoiceField(
label="角色",
required=True,
choices=settings.NB_ROLES,
widget=forms.Select(attrs={"class": "form-control"})
)
username = forms.CharField(
label="用户名",
max_length=8,
widget=forms.TextInput(attrs={"class": "form-control", "placeholder": "用户名"})
)
"""以CharField举例,max_length参数传入,会在字段初始化时,将max_length校验添加self.validators,也可以直接通过validators参数直接传入其他校验类,校验类base类BaseValidator
@deconstructible
class MaxLengthValidator(BaseValidator):
message = ngettext_lazy(
'Ensure this value has at most %(limit_value)d character (it has %(show_value)d).',
'Ensure this value has at most %(limit_value)d characters (it has %(show_value)d).',
'limit_value')
code = 'max_length'
def compare(self, a, b): #a为传入,b为限制值,b=8为例,如果a>8会抛出异常,自定义时需确保符合条件是,compare返回false,否则返回为true
return a > b
def clean(self, x):
return len(x)
"""
password = forms.CharField(
label="密码",
widget=forms.PasswordInput(attrs={"class": "form-control", "placeholder": "密码"}, render_value=True) #render_value默认校验失败页面不渲染密码,为true可渲染
)
def clean_username(self):
if len(self.cleaned_data['username']) <3:
raise forms.ValidationError("用户名最少3个字符")
return self.cleaned_data['username']
def clean_password(self): # 单字段校验,按字段在类声明的顺序校验
if len(self.cleaned_data['password'])<5:
raise forms.ValidationError("密码最少5个字符")
return md5(self.cleaned_data["password"])
def clean(self): #整体校验
username = self.cleaned_data.get("username")
password = self.cleaned_data.get("password")
print(self.cleaned_data)
if username and password:
return self.cleaned_data
raise forms.ValidationError("用户名和密码不能为空")
class SmsLoginForm(forms.Form): #短信登录校验
role = forms.ChoiceField(
label="角色",
required=True,
choices=(("2", "客户"), ("1", "管理员")),
widget=forms.Select(attrs={"class": "form-control"})
)
mobile = forms.CharField(
label="手机号",
validators=[RegexValidator(r'^1[358]\d{9}$', '手机格式错误'), ],
widget=forms.TextInput(attrs={"class": "form-control", "placeholder": "手机号"})
)
code = forms.CharField(
label="短信验证码",
validators=[RegexValidator(r'^[0-9]{4}$', '验证码格式错误'), ],
widget=forms.TextInput(attrs={"class": "form-control", "placeholder": "短信验证码"})
)
def clean_code(self):
mobile = self.cleaned_data.get('mobile')
code = self.cleaned_data['code']
if not mobile:
return code
conn = get_redis_connection("default")
cache_code = conn.get(mobile)
if not cache_code:
raise ValidationError("短信验证码未发送或失效")
if code != cache_code.decode('utf-8'):
raise ValidationError("短信验证码未发送或失效")
return code
class MobileForm(forms.Form): #点击发送验证码,ajax发送校验,若成功发送短信验证码则通过校验
role = forms.ChoiceField(
label="角色",
required=True,
choices=(("2", "客户"), ("1", "管理员")),
widget=forms.Select(attrs={"class": "form-control"})
)
mobile = forms.CharField(
label="手机号",
required=True,
validators=[RegexValidator(r'^1[358]\d{9}$', '手机格式错误'), ]
)
def clean_mobile(self):
role = self.cleaned_data.get('role')
mobile = self.cleaned_data['mobile']
if not role:
return mobile
if role == "1":
exists = models.Administrator.objects.filter(active=1, mobile=mobile).exists()
else:
exists = models.Customer.objects.filter(active=1, mobile=mobile).exists()
if not exists:
raise ValidationError("手机号不存在")
# 2.发送短信 + 生成验证码
sms_code=ytx.get_code(4)
is_success = ytx.send_sms(mobile, sms_code)
if not is_success:
raise ValidationError("短信发送失败")
# 3.将手机号和验证码保存(以便于下次校验) redis -> 超时时间
conn = get_redis_connection("default")
conn.set(mobile, sms_code, ex=120)
return mobile
view.py代码
import random
from django.http import JsonResponse
from django.shortcuts import render, redirect
from django_redis import get_redis_connection
from web import models
from utils.encrypt import md5
from utils.reponse import BaseResponse
from web.forms.account import LoginForm, MobileForm, SmsLoginForm
from django.conf import settings
def login(request):
if request.method == "GET":
form = LoginForm()
return render(request, "login.html", {"form": form})
# 1.接收并获取数据(数据格式或是否为空验证 - Form组件 & ModelForm组件)
form = LoginForm(data=request.POST)
if not form.is_valid():
return render(request, "login.html", {"form": form})
# 2.去数据库校验 1管理员 2客户
data_dict = form.cleaned_data
role = data_dict.pop('role')
if role == "1":
user_object = models.Administrator.objects.filter(active=1).filter(**data_dict).first()
else:
user_object = models.Customer.objects.filter(active=1).filter(**data_dict).first()
# 2.1 校验失败
if not user_object:
form.add_error("username", "用户名或密码错误")
return render(request, "login.html", {'form': form})
# 2.2 校验成功,用户信息写入session+进入项目后台
mapping = {"1": "ADMIN", "2": "CUSTOMER"}
request.session[settings.NB_SESSION_KEY] = {'role': mapping[role], 'name': user_object.username,
'id': user_object.id}
return redirect(settings.LOGIN_HOME)
def sms_send(request):
""" 发送短信 """
res = BaseResponse()
# 校验数据合法性:手机号的格式 + 角色
form = MobileForm(data=request.POST)
if not form.is_valid():
res.detail = form.errors
return JsonResponse(res.dict, json_dumps_params={"ensure_ascii": False})
res.status = True
return JsonResponse(res.dict)
def sms_login(request):
if request.method == "GET":
form = SmsLoginForm()
return render(request, "sms_login.html", {'form': form})
res = BaseResponse()
# 1.手机格式校验
form = SmsLoginForm(data=request.POST)
if not form.is_valid():
res.detail = form.errors
return JsonResponse(res.dict)
role = form.cleaned_data['role']
mobile = form.cleaned_data['mobile']
# 3.登录成功 + 注册 (监测手机号是否存在)
# - 未注册,自动注册
# - 已注册,直接登录
if role == "1":
user_object = models.Administrator.objects.filter(active=1, mobile=mobile).first()
else:
user_object = models.Customer.objects.filter(active=1, mobile=mobile).first()
if not user_object:
res.detail = {"mobile": ["手机号不存在"]}
return JsonResponse(res.dict)
# 2.2 校验成功,用户信息写入session+进入项目后台
mapping = {"1": "ADMIN", "2": "CUSTOMER"}
request.session[settings.NB_SESSION_KEY] = {'role': mapping[role], 'name': user_object.username,
'id': user_object.id}
res.status = True
res.data = settings.LOGIN_HOME
return JsonResponse(res.dict)
html:
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="{% static 'plugins/bootstrap/css/bootstrap.css' %}">
<style>
.box {
width: 450px;
border: 1px solid #f0f0f0;
margin-left: auto;
margin-right: auto;
margin-top: 100px;
padding-left: 40px;
padding-right: 40px;
padding-bottom: 30px;
box-shadow: 5px 10px 10px rgb(0 0 0 / 5%);
}
</style>
</head>
<body>
<div class="box">
<h2 style="text-align: center;">用户登录</h2>
<form method="post">
{% csrf_token %}
{% for field in form %}
<div class="form-group" style="position: relative;margin-bottom: 25px">
<label>{{ field.label }}</label>
{{ field }}
<span style="color: red;position: absolute;">{{ field.errors.0 }}</span>
</div>
{% endfor %}
<button type="submit" class="btn btn-primary">登 录</button>
<a href='{% url 'sms_login' %}' style="float: right;">短信登录</a>
</form>
</div>
</body>
</html>
分页类
"""
v1版本
在视图函数:
def customer_list(request):
# 所有数据
queryset = models.Customer.objects.filter(active=1).select_related('level')
pager = Pagination(request, queryset)
context = {
"queryset": queryset[pager.start:pager.end],
"pager_string": obj.html()
}
return render(request, 'customer_list.html', context)
在页面上:
{% for row in queryset %}
{{row.id}}
{% endfor %}
<ul class="pagination">
{{ pager_string }}
</ul>
v2版本
在视图函数:
def customer_list(request):
# 所有数据
queryset = models.Customer.objects.filter(active=1).select_related('level')
pager = Pagination(request, queryset)
return render(request, 'customer_list.html', {"pager":pager})
在页面上:
{% for row in pager.queryset %}
{{row.id}}
{% endfor %}
<ul class="pagination">
{{ pager.html }}
</ul>
"""
import copy
from django.utils.safestring import mark_safe
class Pagination(object):
""" 分页 """
def __init__(self, request, query_set, per_page_count=10):
self.query_dict = copy.deepcopy(request.GET)
self.query_dict._mutable = True
self.query_set = query_set
total_count = query_set.count()
self.total_count = total_count
# 计算出总共有多少页面
self.total_page, div = divmod(total_count, per_page_count)
if div:
self.total_page += 1
page = request.GET.get('page')
if not page:
page = 1
else:
if not page.isdecimal():
page = 1
else:
page = int(page)
if page <= 0:
page = 1
else:
if page > self.total_page:
page = self.total_page
self.page = page
self.per_page_count = per_page_count
self.start = (page - 1) * per_page_count
self.start = 0 if self.start<0 else self.start
self.end = page * per_page_count
def html(self):
pager_list = []
if not self.total_page:
return ""
# 总页码小于11
if self.total_page <= 11:
start_page = 1
end_page = self.total_page
else:
# 总页码比较多
# 判断当前页 <=6: 1~11
if self.page <= 6:
start_page = 1
end_page = 11
else:
if (self.page + 5) > self.total_page:
start_page = self.total_page - 10
end_page = self.total_page
else:
start_page = self.page - 5
end_page = self.page + 5
self.query_dict.setlist('page', [1])
pager_list.append('<li><a href="?{}">首页</a></li>'.format(self.query_dict.urlencode()))
if self.page > 1:
self.query_dict.setlist('page', [self.page - 1])
pager_list.append('<li><a href="?{}">上一页</a></li>'.format(self.query_dict.urlencode()))
for i in range(start_page, end_page + 1):
self.query_dict.setlist('page', [i])
if i == self.page:
item = '<li class="active"><a href="?{}">{}</a></li>'.format(self.query_dict.urlencode(), i)
else:
item = '<li><a href="?{}">{}</a></li>'.format(self.query_dict.urlencode(), i)
pager_list.append(item)
if self.page < self.total_page:
self.query_dict.setlist('page', [self.page + 1])
pager_list.append('<li><a href="?{}">下一页</a></li>'.format(self.query_dict.urlencode()))
self.query_dict.setlist('page', [self.total_page])
pager_list.append('<li><a href="?{}">尾页</a></li>'.format(self.query_dict.urlencode()))
pager_list.append('<li class="disabled"><a>数据{}条{}页</a></li>'.format(self.total_count, self.total_page))
pager_string = mark_safe("".join(pager_list))
return pager_string
def queryset(self):
if self.total_count:
return self.query_set[self.start:self.end]
return self.query_set
标签:form,self,request,django,dict,使用,query,page
From: https://www.cnblogs.com/liuzhiyangz/p/18658542