Django-pagination-form data verification

Page

view layer
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())
Template layer
{% for a in data %}
    <p>{<!-- -->{ a.addr }}</p>
{% endfor %}
{<!-- -->{ page_obj.page_html|safe }}
Custom paginator
class Pagination(object):
    def __init__(self, current_page, all_count, per_page_num=10, pager_count=11):
        """
        Encapsulate paging related data
        :param current_page: current page
        :param all_count: The total number of data in the database
        :param per_page_num: The number of data items displayed on each page
        :param pager_count: The maximum number of displayed page numbers

        usage:
        queryset = model.objects.all()
        page_obj = Pagination(current_page,all_count)
        page_data = queryset[page_obj.start:page_obj.end]
        To obtain data, use page_data instead of the original queryset.
        Get the front-end paging style using 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

        #Total page number
        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):
        # If the total page number < 11:
        if self.all_pager <= self.pager_count:
            pager_start = 1
            pager_end = self.all_pager + 1
        # Total pages > 11
        else:
            # If the current page <=, at most 11/2 page numbers will be displayed on the page
            if self.current_page <= self.pager_count_half:
                pager_start = 1
                pager_end = self.pager_count + 1

            #The current page is greater than 5
            else:
                # Turn the page number to the end
                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 = []
        #Add the previous nav and ul tags
        page_html_list.append('''
                    <nav aria-label='Page navigation>'
                    <ul class='pagination'>
                ''')
        first_page = '<li><a href="?page=%s">Homepage</a></li>' % (1)
        page_html_list.append(first_page)

        if self.current_page <= 1:
            prev_page = '<li class="disabled"><a href="#">Previous page</a></li>'
        else:
            prev_page = '<li><a href="?page=%s">Previous page</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="#">Next page</a></li>'
        else:
            next_page = '<li><a href="?page=%s">Next page</a></li>' % (self.current_page + 1,)
        page_html_list.append(next_page)

        last_page = '<li><a href="?page=%s">Last page</a></li>' % (self.all_pager,)
        page_html_list.append(last_page)
        #Add tag at the end
        page_html_list.append('''
                                           </nav>
                                           </ul>
                                       ''')
        return ''.join(page_html_list)

form form verification component

Due to the security of verification, the front end does not need verification, but the back end must verify

Custom component
from django import forms
from app01 import models

class myzx(forms.Form):
    username = forms.CharField(min_length=3, max_length=8, label='username',
                               error_messages={
                                   'min_length': 'Username cannot be less than three characters',
                                   'max_length': 'Username cannot be longer than eight characters',
                                   'required': 'Username cannot be empty',
                               }, widget=forms.widgets.TextInput(attrs={'class': 'form-control'})
                               )
    password = forms.CharField(min_length=3, max_length=8, label='password',
                               error_messages={
                                   'min_length': 'The password cannot be less than three characters',
                                   'max_length': 'Password cannot be larger than eight characters',
                                   'required': 'Password cannot be empty',
                               }, widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'})
                               )
    confirm_password = forms.CharField(min_length=3, max_length=8, label='Confirm password',
                                       error_messages={
                                           'min_length': 'Confirm password cannot be less than three digits',
                                           'max_length': 'The confirmation password cannot be larger than eight characters',
                                           'required': 'Confirm password cannot be empty',
                                       }, widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'})
                                       )
    email = forms.EmailField(
        label='mailbox',
        error_messages={
            'required': 'The mailbox cannot be empty',
            'invalid': 'The email format is incorrect'
        }, widget=forms.widgets.EmailInput(attrs={"class": 'form-control'})
    )
You can write the front-end form yourself or use the one provided by the component

obj is the component object defined by itself

<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="Submit">
</form>

However, when rendering this way, front-end verification will be added by default. However, adding it to the front-end is unsafe, so it is not used.

<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="Submit">
</form>

To add novalidate to the form, you can cancel the above function.

<form method="POST" novalidate>
Verify uploaded data
#Verify data and obtain verification result object
form_obj = myforms.MyRegForm(request.POST)

#Determine whether all verifications are successful
if form_obj.is_valid():
#Data submitted by users (fields and field values in dictionary form)
print(form_obj.cleaned_data)
else:
#The user submitted incorrect data (the error information is the error field and error description information with front-end style)
# is a dictionary, the reason why str is rewritten when printing information above
print(form_obj.errors)
Semi-completed version of small case

Front end

obj.errors.username.0, you can get the complete error description without front-end tags.

<form method="POST" novalidate>
    

{{ obj.username.label }}{{ obj.username }}{{ obj.errors.username.0 }}

{{ obj.password.label }}{{ obj.password }}{{ obj.errors.password.0 }}

{{ obj.confirm_password.label }}{{ obj.confirm_password }}{{ obj.errors.confirm_password.0 }}

{{ obj.email.label }}{{ obj.email }}{{ obj.errors.email.0 }}

Backend

Data submission can be implemented simply through this method. The content of the form is still there because obj has recorded the data.

In fact, all objects returned by the backend are obj objects, but the first one has no data, so it is mainly used for rendering the interface.

After the data is uploaded, the generated object contains data, so it will carry error information and be rendered to the front end. The two objs are different.

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 the data that has been verified successfully. Even if the data is wrong, it can be printed. Only the data that has passed the verification will be printed.
            print("Verification successful",obj.cleaned_data)
            return HttpResponse("Data verification successful")
        else:
            print("Verification failed",obj.errors)
            print(type(obj.errors))
            return render(request,'zx.html',locals())
forms data addition

When writing forms constraints, we can make the field names the same as those involved in models. In this case, the data dictionary of clean_data fully meets the requirements for submitting data.

#In this case, the data does not need to be taken out one by one, and the data can be submitted at once.
if obj.is_valid():
models.books.objects.create(**obj.cleaned_data)
forms data editing

If the editing interface requires the content of metadata, you can use the verification function and return the data to the front desk. Moreover, if the data is taken from the database, there will be no problem. The style of the front end is similar to that of add.

def edit_user(request,nid):
if request.method == 'GET':
\t\t#retrieve data
data = models.UserInfo.objects.filter(pk=nid).first()
#Pass to forms because it can automatically generate html
obj = UserForm({'username':data.username,'email':data.email})
return render(request,'edit_user.html',locals())
#else is a request to modify data
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 field list

https://www.cnblogs.com/xiaoyuanqujing/articles/11753466.html

Among them, weight is an important plug-in for generating front-end code.

Returns a radio button whose parameter is a number

zx = fields.ChoiceField(
choices = [(1,'money'),(2,'power')]
)
Get metadata dynamically

One

Refreshing the interface will execute these codes, which is equivalent to re-retrieving values from the database.

hobby = forms.IntegerField(
        label='hobby',
        widget=widgets.Select()
    )
    def __init__(self,*args,**kwargs):
        super(myzx,self).__init__(*args,**kwargs)
        print(models.Blog.objects.values_list('id','site_title'))
        #Note that this sentence must be written at the end, otherwise the value will be overwritten by super.
        self.fields['hobby'].widget.choices = models.Blog.objects.values_list('id','site_title')

Two

from django.forms.models import ModelChoiceField
    hobby2 = ModelChoiceField(
        label='Hobby 2',
        # is the displayed data part. If you want to specify the displayed content, you need to override the str method of models.
        queryset=models.Blog.objects.all(),
        #Just displays the value, which is used for uploading
        to_field_name='id'
    )
from front-end html to generate abbreviation-advanced

But it is not recommended, customization is weak

{<!-- -->{obj.as_p}}

<ul>
{<!-- -->{obj.as_ul}}
</ul>

<table>
{<!-- -->{obj.as_table}}
</table>
Front-end string to label
from django.utils safestring import mark_safe
txt = mark_safe(txt)
Hook function

Note that these functions must be written in the form class

Local hook function

Strengthen verification for some fields

def clean_username(self):
        username = self.cleaned_data.get('username')
        if '88' in username:
            self.add_error('username','The name cannot contain 88')
        return username

Global hook function

Use global hook functions for multiple field validation

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','The passwords are not equal')
        return self.cleaned_data
Regular and other form data submission
#
    # phone = forms.CharField(label='Mobile phone number',validators=[RegexValidator(r'^[0-9] + $', 'Please enter a number'), RegexValidator(r'^159[0-9] + $', 'The number must start with 159')])
    #
    #
    #
    # """The following are the knowledge points. You only need to organize them into your blog. When you need to use them, just copy them directly"""
    #
    # gender = forms.ChoiceField(
    # choices=((1, "Male"), (2, "Female"), (3, "Confidential")),
    # label="gender",
    # initial=3,
    # widget=widgets.RadioSelect()
    # )
    #
    #
    #
    #
    # hobby = forms.ChoiceField(
    # choices=((1, "Basketball"), (2, "Football"), (3, "Double Color Ball"),),
    # label="hobby",
    # initial=3,
    # widget=widgets.Select()
    # )
    #
    # hobby1 = forms.MultipleChoiceField(
    # choices=((1, "Basketball"), (2, "Football"), (3, "Double Color Ball"),),
    # label="hobby",
    # initial=[1, 3],
    # widget=widgets.SelectMultiple()
    # )
    #
    # keep = forms.ChoiceField(
    # label="Whether to remember the password",
    # initial="checked",
    # widget=forms.widgets.CheckboxInput()
    # )
    #
    # hobby2 = forms.MultipleChoiceField(
    # choices=((1, "Basketball"), (2, "Football"), (3, "Double Color Ball"),),
    # label="hobby",
    # initial=[1, 3],
    # widget=forms.widgets.CheckboxSelectMultiple()
    # )