Django自定义系列
目录模板层-自定义过滤器、标签、inclusion_tag
# 共有步骤
# 在settings中的INSTALLED_APPS添加当前app的名字
INSTALLED_APPS = ['app01',]
# 在文件夹app01中创建子文件夹templatetags
# 在templatetags新建任意.py文件
# 在该文件中导入所需名称
from django import template
register = template.Library()
自定义过滤器(最多两个参数)
@register.filter(name='sum_filter')
def my_sum(a1,a2):
return a1 + a2
自定义过滤器调用
{% load mytag %}
<p>{{ a1|sum_filter:a2 }}</p>
自定义标签(可以有多个参数)
@register.simple_tag(name='my_tag')
def index(a, b, c, d):
return f'{a}/{b}/{c}/{d}'
自定义标签调用
{% load mytag %}
<p>{% my_tag 'a' 'b' 'c' 'd' %}</p>
自定义inclusion_tag之书写inclusion_tag主代码
@register.inclusion_tag('left_menu.html')
def left(n):
data = [f'第{i}项' for i in range(n)]
return locals() #将data传递给left_menu.html 即 return {'data':data}
自定义inclusion_tag之定义渲染工具页面
# 新建'left_menu.html'
# 书写代码
'''
<ul>
{% for datum in data %}
<li>{{ datum }}</li>
{% endfor %}
</ul>
'''
自定义inclusion_tag调用
{% load mytag %}
{% left 9 %}
自定义模板
模板页面制作
# 新建模板文件
# 书写模板代码
'''
<div class="panel-body">
{% block var_content %}
<div class="jumbotron">
<h1>Hello, world!</h1>
<p>...</p>
<p><a class="btn btn-primary btn-lg" href="#" role="button">Learn more</a></p>
</div>
{% endblock %}
</div>
'''
实例页面调用
'''
{% extends 'home.html' %}
{% block var_content %}
<h1>注册页面</h1>
{% endblock %}
'''
# 一般情况下,模板页面应该至少有三块可以被修改的区域
'''
1.css区域
{% block css %}
{% endblock %}
2.html区域
{% block content %}
{% endblock %}
3.js区域
{% block js %}
{% endblock %}
'''
导入模板
# 即将模板页面模块化,然后实例页面直接使用语法将模板页面所有代码直接导入
{% include 'part.html' %}
自定义分页器
# 新建或进入utils文件夹
# 创建任意名称.py文件
在该文件内定义分页器类
class Pagination(object):
def __init__(self, current_page, all_count, per_page_num=2, pager_count=11):
"""
封装分页相关数据
:param current_page: 当前页
:param all_count: 数据库中的数据总条数
:param per_page_num: 每页显示的数据条数
:param pager_count: 最多显示的页码个数
"""
try:
current_page = int(current_page)
except Exception as e:
current_page = 1
if current_page < 1:
current_page = 1
self.current_page = current_page
self.all_count = all_count
self.per_page_num = per_page_num
# 总页码
all_pager, tmp = divmod(all_count, per_page_num)
if tmp:
all_pager += 1
self.all_pager = all_pager
self.pager_count = pager_count
self.pager_count_half = int((pager_count - 1) / 2)
@property
def start(self):
return (self.current_page - 1) * self.per_page_num
@property
def end(self):
return self.current_page * self.per_page_num
def page_html(self):
# 如果总页码 < 11个:
if self.all_pager <= self.pager_count:
pager_start = 1
pager_end = self.all_pager + 1
# 总页码 > 11
else:
# 当前页如果<=页面上最多显示11/2个页码
if self.current_page <= self.pager_count_half:
pager_start = 1
pager_end = self.pager_count + 1
# 当前页大于5
else:
# 页码翻到最后
if (self.current_page + self.pager_count_half) > self.all_pager:
pager_end = self.all_pager + 1
pager_start = self.all_pager - self.pager_count + 1
else:
pager_start = self.current_page - self.pager_count_half
pager_end = self.current_page + self.pager_count_half + 1
page_html_list = []
# 添加前面的nav和ul标签
page_html_list.append('''
<nav aria-label='Page navigation>'
<ul class='pagination'>
''')
first_page = '<li><a href="?page=%s">首页</a></li>' % (1)
page_html_list.append(first_page)
if self.current_page <= 1:
prev_page = '<li class="disabled"><a href="#">上一页</a></li>'
else:
prev_page = '<li><a href="?page=%s">上一页</a></li>' % (self.current_page - 1,)
page_html_list.append(prev_page)
for i in range(pager_start, pager_end):
if i == self.current_page:
temp = '<li class="active"><a href="?page=%s">%s</a></li>' % (i, i,)
else:
temp = '<li><a href="?page=%s">%s</a></li>' % (i, i,)
page_html_list.append(temp)
if self.current_page >= self.all_pager:
next_page = '<li class="disabled"><a href="#">下一页</a></li>'
else:
next_page = '<li><a href="?page=%s">下一页</a></li>' % (self.current_page + 1,)
page_html_list.append(next_page)
last_page = '<li><a href="?page=%s">尾页</a></li>' % (self.all_pager,)
page_html_list.append(last_page)
# 尾部添加标签
page_html_list.append('''
</nav>
</ul>
''')
return ''.join(page_html_list)
'''
def get_book(request):
book_list = models.Book.objects.all()
current_page = request.GET.get("page",1)
all_count = book_list.count()
page_obj = Pagination(current_page=current_page,all_count=all_count,per_page_num=10)
page_queryset = book_list[page_obj.start:page_obj.end]
return render(request,'booklist.html',locals())
'''
#
# <div class="container">
# <div class="row">
# <div class="col-md-8 col-md-offset-2">
# {% for book in page_queryset %}
# <p>{{ book.title }}</p>
# {% endfor %}
# {{ page_obj.page_html|safe }}
# </div>
# </div>
# </div>
#
在试图函数中导入类
from utils.mypage import Pagination
使用该类创建对象、使用对象属性截取数据列表,将数据列表返回
def get_book(request):
book_list = models.Book.objects.all()
current_page = request.GET.get("page",1)
all_count = book_list.count()
page_obj=Pagination(current_page=current_page,all_count=all_count,per_page_num=10)
page_queryset = book_list[page_obj.start:page_obj.end]
return render(request,'booklist.html',locals())
自定义forms组件
新建python文件
# 位置根据项目需要
在该文件中定义自己的forms类
from django import forms
from app01 import models
class MyRegForm(forms.Form):
username = forms.CharField(label='用户名',
min_length=3,
max_length=8,
error_messages={
'required': '用户名不能为空',
'min_length': '用户名最少3位',
'max_length': '用户名最大8位',
},
widget=forms.widgets.TextInput(attrs={
'class': 'form-control'
})
)
password = forms.CharField(label='密码',
min_length=6,
max_length=12,
error_messages={
'required': '密码不能为空',
'min_length': '密码最少6位',
'max_length': '密码最大12位',
},
widget=forms.widgets.PasswordInput(attrs={
'class': 'form-control'
})
)
confirm_password = forms.CharField(label='确认密码',
min_length=6,
max_length=12,
error_messages={
'required': '确认密码不能为空',
'min_length': '确认密码最少6位',
'max_length': '确认密码最大12位',
},
widget=forms.widgets.PasswordInput(attrs={
'class': 'form-control'
})
)
email = forms.EmailField(label='邮箱地址',
error_messages={
'required': '邮箱不能为空',
'invalid': '邮箱格式不正确'
},
widget=forms.widgets.EmailInput(attrs={
'class': 'form-control'
})
)
# label即在渲染时可用的标签说明,min_length、max_length即校验条件,error_messages即自定义错误提示信息,要注意对于特殊字段例如email的错误提示信息稍有不同,widget即定义标签具体属性
# 局部钩子:校验用户名是否已存在
def clean_username(self):
username = self.cleaned_data.get('username')
is_exist = models.UserInfo.objects.filter(username=username)
if is_exist:
self.add_error('username', '用户名已存在')
return username
# 全局钩子:校验两次密码是否一致
def clean(self):
password = self.cleaned_data.get('password')
confirm_password = self.cleaned_data.get('confirm_password')
if not password == confirm_password:
self.add_error('confirm_password', '两次输入的密码不一致')
return self.cleaned_data
forms组件其他参数
'''
label 标签名
error_messages 自定义错误提示
initial 默认值
required 是否必填
widget 设置input标签类型(password/select等),并且可以通过传参设置标签属性:
widget=forms.widgets.PasswordInput(attrs={'class':'formcontrol c1 c2','me':'george'})
RegexValidator
更多input标签类型的渲染:https://www.cnblogs.com/Dominic-Ji/p/9240365.html
'''
# RegexValidator校验
from django.core.validators import RegexValidator
email = forms.EmailField(label='邮箱',error_messages={'invalid':'邮箱格式不正确','required':'邮箱不能为空'})
# 仍然属于第一道校验,在钩子函数之前
forms组件使用
form_obj = MyRegForm(request.POST)
if form_obj.is_valid():
cleaned_data = form_obj.cleaned_data
cleaned_data.pop('confirm_password')
file_obj = request.FILES.get('avatar')
if file_obj:
cleaned_data['avatar'] = file_obj
models.UserInfo.objects.create_user(**cleaned_data)
back_dict['url'] = '/login/'
标签:count,系列,自定义,self,Django,current,pager,page
From: https://www.cnblogs.com/missfxy/p/16930675.html