Django-分頁-form數據校驗

分頁

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()
    # )
相關文章
相關標籤/搜索