分頁
view層
def fenye(request): all_data = models.AuthorDetail.objects.all() current_page = request.GET.get('page',1) count = all_data.count() page_obj = Pagination(current_page=current_page,all_count=count) data = all_data[page_obj.start:page_obj.end] return render(request,'fenye.html',locals())
模板層
{% for a in data %} <p>{{ a.addr }}</p> {% endfor %} {{ page_obj.page_html|safe }}
自定義分頁器
class Pagination(object): def __init__(self, current_page, all_count, per_page_num=10, pager_count=11): """ 封裝分頁相關數據 :param current_page: 當前頁 :param all_count: 數據庫中的數據總條數 :param per_page_num: 每頁顯示的數據條數 :param pager_count: 最多顯示的頁碼個數 用法: queryset = model.objects.all() page_obj = Pagination(current_page,all_count) page_data = queryset[page_obj.start:page_obj.end] 獲取數據用page_data而再也不使用原始的queryset 獲取前端分頁樣式用page_obj.page_html """ 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)
form表單校驗組件
因爲校驗的安全性,前端能夠沒有校驗,可是後端必須校驗html
自定義組件
from django import forms from app01 import models class myzx(forms.Form): username = forms.CharField(min_length=3, max_length=8, label='用戶名', error_messages={ 'min_length': '用戶名不能少於三位', 'max_length': '用戶名不能大於八位', 'required': '用戶名不能爲空', }, widget=forms.widgets.TextInput(attrs={'class': 'form-control'}) ) password = forms.CharField(min_length=3, max_length=8, label='密碼', error_messages={ 'min_length': '密碼不能少於三位', 'max_length': '密碼不能大於八位', 'required': '密碼不能爲空', }, widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'}) ) confirm_password = forms.CharField(min_length=3, max_length=8, label='確認密碼', error_messages={ 'min_length': '確認密碼不能少於三位', 'max_length': '確認密碼不能大於八位', 'required': '確認密碼不能爲空', }, widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'}) ) email = forms.EmailField( label='郵箱', error_messages={ 'required': '郵箱不能爲空', 'invalid': '郵箱格式不正確' }, widget=forms.widgets.EmailInput(attrs={"class": 'form-control'}) )
前端表單能夠本身寫,也可使用組件提供的
obj爲本身定義的組件對象前端
<form method="POST"> <p>{{ obj.username }}</p> <p>{{ obj.confirm_password }}</p> <p>{{ obj.confirm_password }}</p> <p>{{ obj.email }}</p> <input type="submit" value="提交"> </form>
可是這樣渲染,會默認加上前端的校驗,可是加在前端是不安全的,因此不採用數據庫
<form method="POST"> <p><input type="text" name="username" class="form-control" maxlength="8" minlength="3" required="" id="id_username"></p> <p><input type="password" name="confirm_password" class="form-control" maxlength="8" minlength="3" required="" id="id_confirm_password"></p> <p><input type="password" name="confirm_password" class="form-control" maxlength="8" minlength="3" required="" id="id_confirm_password"></p> <p><input type="email" name="email" class="form-control" required="" id="id_email"></p> <input type="submit" value="提交"> </form>
要在form表單上加上novalidate,能夠取消上面的功能django
<form method="POST" novalidate>
校驗上傳的數據
#驗證數據,獲取驗證結果對象 form_obj = myforms.MyRegForm(request.POST) #判斷是否所有驗證成功 if form_obj.is_valid(): #用戶提交的數據(字典形式的字段和字段值) print(form_obj.cleaned_data) else: #用戶提交錯誤的數據(錯誤信息爲帶前端樣式的錯誤字段和錯誤描述信息) #是一個字典,上面的打印信息時重寫了str的緣由 print(form_obj.errors)
半完成版小案例
前端後端
obj.errors.username.0,才能拿到不帶前端標籤,完整的錯誤描述安全
<form method="POST" novalidate> <p>{{ obj.username.label }}{{ obj.username }}{{ obj.errors.username.0 }}</p> <p>{{ obj.password.label }}{{ obj.password }}{{ obj.errors.password.0 }}</p> <p>{{ obj.confirm_password.label }}{{ obj.confirm_password }}{{ obj.errors.confirm_password.0 }}</p> <p>{{ obj.email.label }}{{ obj.email }}{{ obj.errors.email.0 }}</p> <input type="submit" value="提交"> </form>
後端app
能夠經過這個簡便的實現數據提交,form的內容還在,由於obj記錄下來數據了函數
其實後端返回的都是obj對象,只是最開始的那個是沒有數據的,因此主要起渲染界面用ui
將數據傳上去後,生成的那個對象是帶數據的,因此會攜帶錯誤信息並渲染到前端,兩個obj是不一樣的url
def text(request): if request.method == 'GET': obj = myforms.myzx() return render(request,'zx.html',locals()) else: obj = myforms.myzx(request.POST) if obj.is_valid(): #打印驗證成功的數據,即便數據有錯也能打印,只打印驗證經過的 print("驗證成功",obj.cleaned_data) return HttpResponse("數據校驗成功") else: print("驗證失敗",obj.errors) print(type(obj.errors)) return render(request,'zx.html',locals())
forms數據添加
在寫forms約束的時候咱們能夠把字段名和models裏面涉及的同樣,這樣的話,clean_data的數據字典就徹底符合提交數據的要求了
#這樣的話,數據就不用一條一條的取出來了,能夠一次性提交數據 if obj.is_valid(): models.books.objects.create(**obj.cleaned_data)
forms數據編輯
編輯界面須要元數據的內容,那麼就可使用校驗功能,而後把數據返回前臺,並且數據是從數據庫拿去的數據是不會有問題的,前端的樣式和add差很少
def edit_user(request,nid): if request.method == 'GET': #獲取數據 data = models.UserInfo.objects.filter(pk=nid).first() #傳給forms,由於它能夠自動生成html obj = UserForm({'username':data.username,'email':data.email}) return render(request,'edit_user.html',locals()) #else爲修改數據的請求 else: obj = UserForm(request.POST) if obj.is_valid(): models.UserInfo.objects.filter(pk=id).update(**obj.cleaned_data) return redirect('/users/') else: return render(request,'edit_user.html')
form字段大全
https://www.cnblogs.com/xiaoyuanqujing/articles/11753466.html
其中weight是生成前端代碼的重要插件
返回參數爲數字的單選框
zx = fields.ChoiceField( choices = [(1,'錢'),(2,'權')] )
動態獲取元數據
一
刷新界面會執行這些代碼,至關於從新去數據庫取值
hobby = forms.IntegerField( label='愛好', widget=widgets.Select() ) def __init__(self,*args,**kwargs): super(myzx,self).__init__(*args,**kwargs) print(models.Blog.objects.values_list('id','site_title')) #注意這句要寫後面,不然會被super覆蓋掉值 self.fields['hobby'].widget.choices = models.Blog.objects.values_list('id','site_title')
二
from django.forms.models import ModelChoiceField hobby2 = ModelChoiceField( label='愛好2', #是顯示的數據部分,想要指定顯示內容須要去重寫models的str方法 queryset=models.Blog.objects.all(), #只是顯示value值,上傳是使用的 to_field_name='id' )
from前端html生成簡寫-高級
可是不推薦,自定製比較弱
{{obj.as_p}} <ul> {{obj.as_ul}} </ul> <table> {{obj.as_table}} </table>
前端字符串轉標籤
from django.utils safestring import mark_safe txt = mark_safe(txt)
鉤子函數
注意這些函數都要寫在form類中
局部鉤子函數
給部分字段增強校驗
def clean_username(self): username = self.cleaned_data.get('username') if '88' in username: self.add_error('username','名字不能包含88') return username
全局鉤子函數
針對多個字段校驗使用全局鉤子函數
def clean(self): password = self.cleaned_data.get('password') re_password = self.cleaned_data.get('re_password') if not password == re_password: self.add_error('re_password','密碼不相等啊') return self.cleaned_data
正則和其餘表單數據提交
# # phone = forms.CharField(label='手機號',validators=[RegexValidator(r'^[0-9]+$', '請輸入數字'), RegexValidator(r'^159[0-9]+$', '數字必須以159開頭')]) # # # # """下面的是瞭解知識點 你只須要整理到你的博客中 到時候須要用 直接來拷貝便可""" # # gender = forms.ChoiceField( # choices=((1, "男"), (2, "女"), (3, "保密")), # label="性別", # initial=3, # widget=widgets.RadioSelect() # ) # # # # # hobby = forms.ChoiceField( # choices=((1, "籃球"), (2, "足球"), (3, "雙色球"),), # label="愛好", # initial=3, # widget=widgets.Select() # ) # # hobby1 = forms.MultipleChoiceField( # choices=((1, "籃球"), (2, "足球"), (3, "雙色球"),), # label="愛好", # initial=[1, 3], # widget=widgets.SelectMultiple() # ) # # keep = forms.ChoiceField( # label="是否記住密碼", # initial="checked", # widget=forms.widgets.CheckboxInput() # ) # # hobby2 = forms.MultipleChoiceField( # choices=((1, "籃球"), (2, "足球"), (3, "雙色球"),), # label="愛好", # initial=[1, 3], # widget=forms.widgets.CheckboxSelectMultiple() # )