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}/w0obha2h00'
自定義標簽調用
{% 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標簽類型的渲染:http://www.rzrgm.cn/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/'
浙公網安備 33010602011771號