Django web开发(五)-靓号管理

前置文章:Django web开发(三)Django_django 个人网站开发-优快云博客

Django web 开发(四) - 员工管理系统(一)-优快云博客

使用的项目名称:PyCharmWork\WorkforceManager

该文章使用的数据库:person

1.创建新项目

步骤:Django web开发(三)Django_django 个人网站开发-优快云博客

数据库建设:然后终端生成

class PrettyNum(models.Model):
    """靓号管理"""
    # 定义字段及其属性
    mobile = models.CharField(max_length=11, verbose_name="手机号")
    price = models.DecimalField(max_digits=10, decimal_places=2,verbose_name="价格")
    level = models.IntegerField(
        choices=[
            (1, '1级'),
            (2, '2级'),
            (3, '3级'),
            (4, '4级')
        ],
        verbose_name="级别"
    )
    status = models.IntegerField(
        choices=[
            (1, '未占用'),
            (2, '已占用')
        ],
        verbose_name="状态"
    )

    def __str__(self):
        # 定义模型的字符串表示形式
        return f"{self.mobile} - {self.get_level_display()} - {self.get_status_display()}"

靓号列表

path('pretty/list/', views.pretty_list),

 由于已经弄了from app01 import models,所以后面调用都是models.xxx,ai的总不写models

order_by("-level")# order_by排序, 这里指以level倒序从高到低排
def pretty_list(request):
    # order_by排序, 这里指以level倒序从高到低排
    queryset = models.PrettyNum.objects.all().order_by("-level")  # 获取所有的靓号
    return render(request, 'pretty_list.html', {'queryset': queryset})

html参考之前的列表代码

添加:modelform、数据校验

modelform

利用modelform时,fields可以自定义某些字段、选取所有、排除部分字段

利用def __init__循环找到所有的插件,添加 "class": "form-control",使输入框变统一样式

注意def和Meta是同一级的

from django import forms
class PrettyModelForm(forms.ModelForm):
    class Meta:
        model = models.PrettyNum
        # fields = ['mobile', 'price', 'level', 'status']
        # exclude = ('level',)
        fields = "__all__"

    # 循环找到所有的插件,添加 "class": "form-control"
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for name, field in self.fields.items():
            # 可以排除指定的字段
            # if name == "password":
            #     continue
            # print(name, field)
            # form - control是样式,placeholder是输入框内的文字
            field.widget.attrs = {"class": "form-control","placeholder": field.label}

 view: 

def pretty_add(request):
    """靓号添加"""
    if request.method == 'GET':
        form = PrettyModelForm()
        return render(request, 'pretty_add.html', {'form': form})
    else:
        # 用户POST请求提交数据,需要进行数据校验
        form = PrettyModelForm(data=request.POST)
        if form.is_valid():
            # 直接保存至数据库
            form.save()
            return redirect('/pretty/list/')
        # 校验失败(在页面上显示错误信息)
        return render(request, 'pretty_add.html', {'form': form})

 数据校验

在views.py里的class里写

方法一:字段+正则(较简单)

在class Meta:前写

mobile = forms.CharField(
        label="手机号",
        validators=[RegexValidator(r'^1[3-9]\d{9}$', '手机号格式错误'), ],
    )

方法二:钩子方法

在def __init__(self, *args, **kwargs):后面写

# 数据校验方法2
    def clean_mobile(self):
        txt_mobile = self.cleaned_data["mobile"]
        if len(txt_mobile) != 11:
            # 验证不通过
            raise ValidationError("格式错误")
        # 验证通过 用户输入的值返回
        return txt_mobile

 两种方式位置如下:

class PrettyModelForm(forms.ModelForm):
    # 数据校验 方法1
    mobile = forms.CharField(
        label="手机号",
        validators=[RegexValidator(r'^1[3-9]\d{9}$', '手机号格式错误'), ],
    )
    class Meta:
        model = models.PrettyNum
        # fields = ['mobile', 'price', 'level', 'status']
        # exclude = ('level',)
        fields = "__all__"

    # 循环找到所有的插件,添加 "class": "form-control"
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for name, field in self.fields.items():
            # 可以排除指定的字段
            # if name == "password":
            #     continue
            # print(name, field)
            # form - control是样式,placeholder是输入框内的文字
            field.widget.attrs = {"class": "form-control", "placeholder": field.label}

    # # 数据校验方法2
    # def clean_mobile(self):
    #     txt_mobile = self.cleaned_data["mobile"]
    #     if len(txt_mobile) != 11:
    #         # 验证不通过
    #         raise ValidationError("格式错误")
    #     # 验证通过 用户输入的值返回
    #     return txt_mobile

编辑靓号

也要数据校验,调用之前的modelform就可以,也可以重新写限定只能修改哪几个input框,也可以修改modelform让某些字段出现input框但不可更改

代码就跟之前的编辑部分一样,省略了:Django web 开发(四) - 员工管理系统(一)-优快云博客

不允许数据重复

不允许手机号重复
-添加: 如果手机号已存在,提示"手机号已存在"
-编辑: 如果手机号除了当前手机号以外已存在,提示"手机号已存在"
添加和编辑的逻辑不太一样,编辑需要将它自己先排除然后再做判断

"添加"功能的手机号重复验证

修改modelform或者在数据库里给号码加上唯一性约束(没试)

只能用数据校验的方法2钩子方法 写里面

# 验证是否存在
exists_data = models.PrettyNum.objects.filter(mobile=txt_mobile).exists()
if exists_data:
    raise ValidationError("手机号已存在")
class PrettyModelForm(forms.ModelForm):
    # # 数据校验 方法1
    # mobile = forms.CharField(
    #     label="手机号",
    #     validators=[RegexValidator(r'^1[3-9]\d{9}$', '手机号格式错误'), ],
    # )
    class Meta:
        model = models.PrettyNum
        # fields = ['mobile', 'price', 'level', 'status']
        # exclude = ('level',)
        fields = "__all__"

    # 循环找到所有的插件,添加 "class": "form-control"
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for name, field in self.fields.items():
            # 可以排除指定的字段
            # if name == "password":
            #     continue
            # print(name, field)
            # form - control是样式,placeholder是输入框内的文字
            field.widget.attrs = {"class": "form-control", "placeholder": field.label}

    # 数据校验方法2
    def clean_mobile(self):
        txt_mobile = self.cleaned_data["mobile"]
        if len(txt_mobile) != 11:
            # 验证不通过
            raise ValidationError("格式错误")
        # 验证是否存在
        exists_data = models.PrettyNum.objects.filter(mobile=txt_mobile).exists()
        if exists_data:
            raise ValidationError("手机号已存在")

        # 验证通过 用户输入的值返回
        return txt_mobile

"编辑"功能的手机号重复验证

懒得写了,感觉用不到,要不就干脆禁止编辑手机号,或者参考人家这篇Django web 开发(四) - Django项目实践(五)-靓号管理_django靓号-优快云博客

删除(略)

查/模糊查询

修改pretty_list,这是列表展示的功能

gt:gather? than大于

PrettyNum.objects.filter(id=4)			# 等于4
PrettyNum.objects.filter(id__gt=4)		# 大于4
PrettyNum.objects.filter(id__gte=4)		# 大于等于4
PrettyNum.objects.filter(id__lt=4)		# 小于4
PrettyNum.objects.filter(id__lte=4)		# 小于等于4

PrettyNum.objects.filter(mobile__startswith="1999")		# 筛选出以"1999"开头的
PrettyNum.objects.filter(mobile__endswith="1999")		# 筛选出以"1999"结尾的
PrettyNum.objects.filter(mobile__contains="1999")		# 筛选出包含"1999"开头的

首先设置data_dict为空字典,当不传搜索参数时展示所有数据,传参后展示目的数据

filter(**data_dict)是条件筛选,没有条件就等于all

传入搜索参数后,搜索后并把这个值体现在前端的框框里

(红框为新增的)

def pretty_list(request):
    """靓号列表"""

    """实现搜索功能"""
    data_dict = {}
    # 不加后面的 "", 首次访问浏览器,搜索框中不会显示前端页面中的 placeholder="Search for..." 属性
    search_data = request.GET.get('q', "")
    if search_data:   #value为真,即传入了搜索参数
        # mobile_contains  表示筛选出字段mobile 包含 value数据的行
        data_dict["mobile__contains"] = search_data
    # 没传参就正常显示所有的
    """排序"""
    # order_by排序, 这里指以level倒序从高到低排
    # 获取经过上述搜索的目的靓号,filter(**data_dict)是条件筛选,没有条件就等于all
    queryset = models.PrettyNum.objects.filter(**data_dict).order_by("-level")
    return render(request, 'pretty_list.html', {'queryset': queryset,"search_data": search_data})

前端:

注意,input框要命名为q,接受传入的q,以及value="{{ search_data }}"加上后是使搜索后输入值不会清零

 {#    新建/搜索按钮#}
    <nav class="navbar">
        <div style="margin-bottom: 20px;" class="container-fluid">
            <a class="btn btn-success" href="/pretty/add/" target="_blank">
                新建靓号modelform
            </a>
            <form class="d-flex" role="search" method="get">
                {#value="{{ search_data }}"加上后是使搜索后输入值不会清零#}
                <input name="q" class="form-control me-2" type="search" placeholder="搜索靓号" value="{{ search_data }}" aria-label="Search">
                <button class="btn btn-outline-success" type="submit">go</button>
            </form>
        </div>
    </nav>

 分页

这里使用Django的paginator(分页)功能较为方便

但也可以自定义pagination使之更加方便

Django的paginator整体思路

  1. 获取数据:从数据库查询需要分页的数据。
  2. 创建分页器:使用Paginator类创建分页器实例。
  3. 获取当前页:根据请求中的页码参数获取当前页的对象列表。
  4. 渲染分页:在模板中使用分页器对象渲染分页链接。

1. 在视图中使用分页

from django.core.paginator import Paginator
from django.shortcuts import render

def my_view(request):
    object_list = MyModel.objects.all()  # 获取所有对象
    paginator = Paginator(object_list, 10)  # 每页显示10个对象

    # 获取当前页
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)

    return render(request, 'my_template.html', {'page_obj': page_obj})
  • request.GET.get('page'):从GET请求中获取名为page的查询参数,默认为None
  • page_obj:当前页的对象列表,是一个Page对象。
  • get_page()Paginator实例的方法,根据页码获取对应的页。get_page方法接受一个页码,并返回一个包含该页对象的Page对象。

和之前的排序搜索放一起

def pretty_list(request):
    """靓号列表"""

    """实现搜索功能"""
    data_dict = {}
    # 不加后面的 "", 首次访问浏览器,搜索框中不会显示前端页面中的 placeholder="Search for..." 属性
    search_data = request.GET.get('q', "")
    if search_data:  # value为真,即传入了搜索参数
        # mobile_contains  表示筛选出字段mobile 包含 value数据的行
        data_dict["mobile__contains"] = search_data
    # 没传参就正常显示所有的
    """排序"""
    # order_by排序, 这里指以level倒序从高到低排
    # 获取经过上述搜索的目的靓号,filter(**data_dict)是条件筛选,没有条件就等于all
    queryset = models.PrettyNum.objects.filter(**data_dict).order_by("-level")

    """分页"""
    paginator = Paginator(queryset, 7)  # 每页显示7个靓号

    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)

    return render(request, 'pretty_list.html', {"search_data": search_data, 'page_obj': page_obj})

2. 在模板中显示分页

原先的列表显示还是那样(注意变量名有没有变)

后面加一个{#分页导航#}

<div class="pagination">
    <span class="step-links">
        第一页/上一页
        <a href="?page=1">第一页</a>  
        {% if page_obj.has_previous %}              
            <a href="?page={{ page_obj.previous_page_number }}">上一页</a>        
        {% endif %}



        中间页码区
        <span class="current">
            页码 {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
        </span>



        下一页/最后一页
        {% if page_obj.has_next %}
            <a href="?page={{ page_obj.next_page_number }}">下一页</a>            
        {% endif %}
        <a href="?page={{ page_obj.paginator.num_pages }}">最后一页</a>
    </span>
</div>

传入的page_obj:当前页的对象列表

  • {% if page_obj.has_previous %}:检查是否有前一页。
  • {% if page_obj.has_next %}:检查是否有后一页。
  • page_obj.previous_page_number:前一页的页码。
  • page_obj.next_page_number:后一页的页码。
  • page_obj.number:当前页码。
  • page_obj.paginator:当前页的分页器对象,包含了分页的相关信息。
  • page_obj.paginator.num_pages:总页数。

  • ?page={{}} 是一个用于构建URL查询字符串的模板标签,其中 {{}} 是一个占位符,用于动态插入变量的值。
  • page_obj.paginator.page_range返回一个包含所有页码的列表。这个列表代表了分页器中所有可能的页码,可以用于在模板中生成分页链接。

下面是一个用了样式的分页,让只显示前后三页好像

{#分页导航#}
    <nav aria-label="Page navigation example">
        <ul class="pagination justify-content-center">
            <li class="page-item">
                <a class="page-link" href="?page=1" aria-label="First">第一页</a>
            </li>

            {% if page_obj.has_previous %}
                <li class="page-item">
                    <a class="page-link" href="?page={{ page_obj.previous_page_number }}"
                       aria-label="Previous">上一页</a>
                </li>
            {% endif %}

            {#循环所有页码  page...range 是一个包含所有页码的列表 #}
            {% for num in page_obj.paginator.page_range %}
                {# 检查当前页:检查当前遍历到的页码 num 是否等于当前页的页码 page_obj.number #}
                {% if page_obj.number == num %}
{#                  {#如果当前页码与遍历到的页码相同,生成一个带有 active 类的列表项,表示当前页。#}
{#                  {#这里使用 <span> 而不是 <a>,因为当前页不需要链接#}
                    <li class="page-item active" aria-current="page">
                        <span class="page-link">{{ num }}</span>
                    </li>
                {#检查页码是否在当前页码前后3页的范围内。|add:'-3' 和 |add:'3' 是Django模板过滤器,用于进行简单的算术运算。#}
                {% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
                    {#生成非当前页的HTML:如果页码在当前页前后3页的范围内,生成一个包含链接的列表项#}
                    <li class="page-item">
                        <a class="page-link" href="?page={{ num }}">{{ num }}</a>
                    </li>
                {% endif %}
            {% endfor %}

            {% if page_obj.has_next %}
                <li class="page-item">
                    <a class="page-link" href="?page={{ page_obj.next_page_number }}" aria-label="Next">下一页</a>
                </li>
            {% endif %}
            <li class="page-item">
                <a class="page-link" href="?page={{ page_obj.paginator.num_pages }}" aria-label="Last">最后一页</a>
            </li>
        </ul>
    </nav>

自定义paginyion

后面要用ajax

 在app01-utils文件夹(自建)下新建paginyion.py

bootsrap样式看它写的啥,li、a标签里有样式的就在标签里面加

分页组件

"""
自定义的分页组件

"""

from django.utils.safestring import mark_safe
import copy


class Pagination(object):
    def __init__(self, request, queryset, page_size=10, page_param="page", page_show=5):
        """
        request: 请求的对象
        queryset: 符合条件的数据(根据此数据进行分页处理)
        page_size: 每页显示多少条数据
        page_param: 获取在URL中传递的分页参数, 例如: /pretty/list/?page=21
        page_show: 页码显示前几页后几页
        """

        # 防止搜索出结果进行翻页时,URL参数没有了搜索参数
        query_dict = copy.deepcopy(request.GET)
        query_dict._mutable = True
        self.query_dict = query_dict

        self.page_param = page_param

        page = int(request.GET.get(page_param, 1))

        # 如果不是整数
        if type(page) != int:
            # 强制让页码为1
            page = 1

        self.page = page

        self.start = (page - 1) * page_size
        self.end = page * page_size

        # 每页展示的数据行数
        self.page_queryset = queryset[self.start:self.end]

        total_data_count = queryset.count()     # 数据行数
        total_page_count, div = divmod(total_data_count, page_size)
        if div:
            total_page_count += 1
        self.total_page_count = total_page_count    # 总页码数量
        self.page_show = page_show  # 当前页前后展示的页码数量
        self.request = request

    def html(self):
        # 如果总页码数量大于 11
        if self.total_page_count > self.page_show * 2 + 1:
            # 如果当前页面页码位置小于等于5
            if self.page <= 5:
                start_page = 1
                end_page = self.page_show * 2 + 2
            # 否则,当前页面页码位置大于5时
            else:
                # 防止页码超出范围
                if self.page >= self.total_page_count - self.page_show:
                    start_page = self.total_page_count - self.page_show * 2
                    end_page = self.total_page_count + 1
                else:
                    # 计算出当前页的前5页和后5页
                    start_page = self.page - self.page_show
                    end_page = self.page + self.page_show + 1

        else:
            start_page = 1
            end_page = self.total_page_count + 1

        ######## 创建页码 ########
        # 页码
        page_str_list = []

        # self.query_dict.setlist(self.page_param, [1])
        # page_str_list.append('<li><a href="?page={}">{}</a></li>'.format(self.query_dict.urlencode()))

        # 跳到首页
        self.query_dict.setlist(self.page_param, [1])
        self.head_page = ('<li class="page-item">'
                          '<a class="page-link" href="?{}" aria-label="Previous">'
                          '<span aria-hidden="true">首页</span></a></li>'
                          ).format(self.query_dict.urlencode())
        page_str_list.append(self.head_page)

        # 跳到上10页
        # 如果当前页面小于 11, 防止超过最小页数
        if self.page < self.page_show * 2 + 1:
            self.query_dict.setlist(self.page_param, [1])
            prev = ('<li class="page-item">'
                    '<a class="page-link" href="?{}">{}</a>'
                    '</li>'
                    ).format(
                self.query_dict.urlencode(), "<<")
            page_str_list.append(prev)
        else:
            self.query_dict.setlist(self.page_param, [self.page - 10])
            prev = ('<li class="page-item">'
                    '<a class="page-link" href="?{}">{}</a>'
                    '</li>').format(
                self.query_dict.urlencode(), "<<")
            page_str_list.append(prev)

        for i in range(start_page, end_page):
            # 如果是当前页,高亮显示页码颜色
            if self.page == i:
                self.query_dict.setlist(self.page_param, [i])
                ele = ('<li class="active page-item">'
                       '<a class="page-link" href="?{}">{}</a>'
                       '</li>').format(
                    self.query_dict.urlencode(), i)
            else:
                self.query_dict.setlist(self.page_param, [i])
                ele = ('<li class="page-item">'
                       '<a class="page-link" href="?{}">{}</a>'
                       '</li>').format(
                    self.query_dict.urlencode(), i)
            page_str_list.append(ele)

        # 跳到下10页
        # 如果当前页面页数 大于 最大页面数量减去(page_show*2+1),则直接跳到最后一页,防止超过最大页数
        if self.page >= self.total_page_count - self.page_show * 2 + 1:
            self.query_dict.setlist(self.page_param, [self.total_page_count])
            next = ('<li class="page-item">'
                    '<a class="page-link" href="?{}">{}</a>'
                    '</li>').format(
                self.query_dict.urlencode(), ">>")
            page_str_list.append(next)
        else:
            self.query_dict.setlist(self.page_param, [self.page + 10])
            next = ('<li class="page-item">'
                    '<a class="page-link" href="?page={}">{}</a>'
                    '</li>').format(
                self.query_dict.urlencode(), ">>")
            page_str_list.append(next)

        # 跳到尾页
        self.query_dict.setlist(self.page_param, [self.total_page_count])
        self.end_page = ('<li class="page-item">'
                         '<a class="page-link" href="?{}" aria-label="Next">'
                         '<span aria-hidden="true">尾页</span></a></li>'
                         ).format(self.query_dict.urlencode())
        page_str_list.append(self.end_page)

        self.page_string = mark_safe("".join(page_str_list))


    """
    视图文件:
    def pretty_list(request):
    
    data_dict = {}
    # 如果是空字典,表示获取所有
    # 不加后面的 "", 首次访问浏览器,搜索框中不会显示前端页面中的 placeholder="Search for..." 属性
    search_data = request.GET.get('query', "")
    if search_data:
        data_dict["mobile__contains"] = search_data 
    
    queryset = PrettyNum.objects.filter(**data_dict).order_by("-level")

    ### 引入封装的 Pagination 类并初始化
    # 初始化
    page_object = Pagination(request, queryset, page_size=10, page_param="page")
    page_queryset = page_object.page_queryset

    # 调用对象的html方法,生成页码
    page_object.html()

    page_string = page_object.page_string
    head_page = page_object.head_page
    end_page = page_object.end_page

    context = {
        "pretty_data": page_queryset,   # 分页的数据
        "search_data": search_data,     # 搜索的内容
        "page_string": page_string,     # 页码
        "head_page": head_page,         # 首页
        "end_page": end_page,           # 尾页
    }

    return render(request, "pretty_list.html", context)
    """

 在视图中:

def manager_list(request):
    queryset = models.Admin.objects.all()
    page_object = Pagination(request, queryset, page_size=2)

    page_object.html()

    context = {
        "queryset": page_object.page_queryset,
        "page_string": page_object.page_string,
    }

    return render(request, "manager_list.html", context)

html

{% for obj in queryset %}

...

<ul class="pagination">
    {{ page_string }}
</ul>

老师的分页

修改了样式

"""
自定义分页组件
"""
"""
使用方法

视图函数:
def Task_list(request)
    # 1.根据自己情况筛选数据(其他功能已经获取数据的话就不用多此一举了
    queryset = models.Task.objects.all()
    
    # 2.实例化分页对象
    page_object = Pagination(request,queryset)
    
    # 3.在原context里替换/添加这俩
    context = {
        "queryset": page_object.page_queryset, # 分完页的数据
        "page_string": page_object.html()      # 生成页码
    }
    return render(request,"task_list.html",context)
    
在html页面中:
注意for循环那一部分一般显示列表时就有了,就不用重复添加了,ur部分放表格下面
    {% for obj in queryset %}
        {{ obj.xx }}
    {% endfor %}
    
    <ul class="pagination">
        {{ page_string }}
    </ul>

"""

from django.utils.safestring import mark_safe
from django import forms


class Pagination(object):

    def __init__(self, request, queryset, page_size=2, page_param="page", plus=5):
        """
        :param request: 请求的对象
        :param queryset:查询的数据,符合条件的数据对这个进行分页处理
        :param page_size:每页显示多条数据
        :param page_param:在URL中传递获取分页的参数,列如:/etty/list/?page=12
        :param plus:显示当前页的,前、后几页(页码)
        """
        import copy
        query_dict = copy.deepcopy(request.GET)
        query_dict._mutable = True
        self.query_dict = query_dict
        self.page_param = page_param

        page = request.GET.get(page_param, "1")  # 把request获取前端get请求的方法,封装到page中,页码
        if page.isdecimal():  # 处理页码,判断页码是否是正常传入数字,而不是字符串
            page = int(page)
        else:
            page = 1  # 前端传入页码不规范,则默认为1
        self.page = page
        self.page_size = page_size
        # 计算分页页码,sql值
        self.start = (page - 1) * page_size
        self.end = page * page_size

        self.page_queryset = queryset[self.start: self.end]  # 分完页的数据

        # total_count = models.PrettyNum.objects.filter(**data_dict).order_by("-price").count()
        total_count = queryset.count()  # 数据总条数

        total_page_count, div = divmod(total_count, page_size)  # 总页码 = 数据总条数/每页显示数据条数

        if div:
            total_page_count += 1

        self.total_page_count = total_page_count
        self.plus = plus  # 显示前后页码条数

    def html(self):
        """
          页码、页码搜索
          """
        # 计算出,显示当前页的前5页、后5页
        if self.total_page_count <= 2 * self.plus + 1:
            # 数据库中的数据比较少,都没有达到11页。
            start_page = 1
            end_page = self.total_page_count
        else:
            # 数据库中的数据比较多 > 11页。

            # 当前页<5时(小极值)
            if self.page <= self.plus:
                start_page = 1
                end_page = 2 * self.plus + 1
            else:
                # 当前页 > 5
                # 当前页+5 > 总页面
                if (self.page + self.plus) > self.total_page_count:
                    start_page = self.total_page_count - 2 * self.plus
                    end_page = self.total_page_count
                else:
                    start_page = self.page - self.plus
                    end_page = self.page + self.plus



        # 页码
        page_str_list = []

        self.query_dict.setlist(self.page_param, [1])
        page_str_list.append('<li class="page-item">'
                             '<a class="page-link" href="?{}" aria-label="Previous">'
                             '<span aria-hidden="true">首页</span></a></li>'.format(self.query_dict.urlencode()))

        # 上一页
        if self.page > 1:
            self.query_dict.setlist(self.page_param, [self.page - 1])
            prev = ('<li class="page-item">'
                    '<a class="page-link" href="?{}">{}</a>'
                    '</li>'
                    ).format(
                self.query_dict.urlencode(), "<<")
        else:
            self.query_dict.setlist(self.page_param, [1])
            prev = ('<li class="page-item">'
                    '<a class="page-link" href="?{}">{}</a>'
                    '</li>'
                    ).format(
                self.query_dict.urlencode(), "<<")
        page_str_list.append(prev)

        # 页面
        for i in range(start_page, end_page + 1):
            self.query_dict.setlist(self.page_param, [i])
            if i == self.page:
                ele = ('<li class="active page-item">'
                       '<a class="page-link" href="?{}">{}</a>'
                       '</li>').format(self.query_dict.urlencode(), i)
            else:
                ele = ('<li class="page-item">'
                       '<a class="page-link" href="?{}">{}</a>'
                       '</li>').format(self.query_dict.urlencode(), i)
            page_str_list.append(ele)

        # 下一页
        if self.page < self.total_page_count:
            self.query_dict.setlist(self.page_param, [self.page + 1])
            prev = ('<li class="page-item">'
                    '<a class="page-link" href="?{}">{}</a>'
                    '</li>').format(
                self.query_dict.urlencode(), ">>")
        else:
            self.query_dict.setlist(self.page_param, [self.total_page_count])
            prev = ('<li class="page-item">'
                    '<a class="page-link" href="?page={}">{}</a>'
                    '</li>').format(
                self.query_dict.urlencode(), ">>")
        page_str_list.append(prev)

        # 尾页
        self.query_dict.setlist(self.page_param, [self.total_page_count])
        page_str_list.append(('<li class="page-item">'
                         '<a class="page-link" href="?{}" aria-label="Next">'
                         '<span aria-hidden="true">尾页</span></a></li>'
                         ).format(self.query_dict.urlencode()))

        search_string = """
                   <li>
                       <form style="float: left;margin-left: -1px" method="get">
                           <input name="page"
                                  style="position: relative;float:left;display: inline-block;width: 80px;border-radius: 0;"
                                  type="text" class="form-control" placeholder="页码">
                           <button style="border-radius: 0" class="btn btn-default" type="submit">跳转</button>
                       </form>
                   </li>
                   """

        page_str_list.append(search_string)
        page_string = mark_safe("".join(page_str_list))
        return page_string
未修改版(老师)
"""
自定义分页组件
"""
from django.utils.safestring import mark_safe
from django import forms


class Pagination(object):

    def __init__(self, request, queryset, page_size=10, page_param="page", plus=5):
        """
        :param request: 请求的对象
        :param queryset:查询的数据,符合条件的数据对这个进行分页处理
        :param page_size:每页显示多条数据
        :param page_param:在URL中传递获取分页的参数,列如:/etty/list/?page=12
        :param plus:显示当前页的,前、后几页(页码)
        """
        import copy
        query_dict = copy.deepcopy(request.GET)
        query_dict._mutable = True
        self.query_dict = query_dict
        self.page_param = page_param

        page = request.GET.get(page_param, "1")  # 把request获取前端get请求的方法,封装到page中,页码
        if page.isdecimal():  # 处理页码,判断页码是否是正常传入数字,而不是字符串
            page = int(page)
        else:
            page = 1  # 前端传入页码不规范,则默认为1
        self.page = page
        self.page_size = page_size
        # 计算分页页码,sql值
        self.start = (page - 1) * page_size
        self.end = page * page_size

        self.page_queryset = queryset[self.start: self.end]  # 分完页的数据

        # total_count = models.PrettyNum.objects.filter(**data_dict).order_by("-price").count()
        total_count = queryset.count()  # 数据总条数

        total_page_count, div = divmod(total_count, page_size)  # 总页码 = 数据总条数/每页显示数据条数

        if div:
            total_page_count += 1

        self.total_page_count = total_page_count
        self.plus = plus  # 显示前后页码条数

    def html(self):
        """
          页码、页码搜索
          """
        # 计算出,显示当前页的前5页、后5页
        if self.total_page_count <= 2 * self.plus + 1:
            # 数据库中的数据比较少,都没有达到11页。
            start_page = 1
            end_page = self.total_page_count
        else:
            # 数据库中的数据比较多 > 11页。

            # 当前页<5时(小极值)
            if self.page <= self.plus:
                start_page = 1
                end_page = 2 * self.plus + 1
            else:
                # 当前页 > 5
                # 当前页+5 > 总页面
                if (self.page + self.plus) > self.total_page_count:
                    start_page = self.total_page_count - 2 * self.plus
                    end_page = self.total_page_count
                else:
                    start_page = self.page - self.plus
                    end_page = self.page + self.plus

        # 页码
        page_str_list = []

        self.query_dict.setlist(self.page_param, [1])
        page_str_list.append('<li><a href="?{}">首页</a></li>'.format(self.query_dict.urlencode()))

        # 上一页
        if self.page > 1:
            self.query_dict.setlist(self.page_param, [self.page - 1])
            prev = '<li><a href="?{}">上一页</a></li>'.format(self.query_dict.urlencode())
        else:
            self.query_dict.setlist(self.page_param, [1])
            prev = '<li><a href="?{}">上一页</a></li>'.format(self.query_dict.urlencode())
        page_str_list.append(prev)

        # 页面
        for i in range(start_page, end_page + 1):
            self.query_dict.setlist(self.page_param, [i])
            if i == self.page:
                ele = '<li class="active"><a href="?{}">{}</a></li>'.format(self.query_dict.urlencode(), i)
            else:
                ele = '<li><a href="?{}">{}</a></li>'.format(self.query_dict.urlencode(), i)
            page_str_list.append(ele)

        # 下一页
        if self.page < self.total_page_count:
            self.query_dict.setlist(self.page_param, [self.page + 1])
            prev = '<li><a href="?{}">下一页</a></li>'.format(self.query_dict.urlencode())
        else:
            self.query_dict.setlist(self.page_param, [self.total_page_count])
            prev = '<li><a href="?{}">下一页</a></li>'.format(self.query_dict.urlencode())
        page_str_list.append(prev)

        # 尾页
        self.query_dict.setlist(self.page_param, [self.total_page_count])
        page_str_list.append('<li><a href="?{}">尾页</a></li>'.format(self.query_dict.urlencode()))

        search_string = """
                   <li>
                       <form style="float: left;margin-left: -1px" method="get">
                           <input name="page"
                                  style="position: relative;float:left;display: inline-block;width: 80px;border-radius: 0;"
                                  type="text" class="form-control" placeholder="页码">
                           <button style="border-radius: 0" class="btn btn-default" type="submit">跳转</button>
                       </form>
                   </li>
                   """

        page_str_list.append(search_string)
        page_string = mark_safe("".join(page_str_list))
        return page_string

 视图view文件

单分页
def manager_list(request):
    ### 引入封装的 Pagination 类并初始化
    # 初始化
    queryset = models.Admin.objects.all()
    page_object = Pagination(request, queryset, page_size=2)

    # 调用对象的html方法,生成页码
    page_object.html()

    context = {
        "queryset": page_object.page_queryset,# 分页的数据
        "page_string": page_object.page_string,# 页码
    }

    return render(request, "manager_list.html", context)
 搜索+分页
def pretty_list(request):

    """实现搜索功能"""
    data_dict = {}
    # 不加后面的 "", 首次访问浏览器,搜索框中不会显示前端页面中的 placeholder="Search for..." 属性
    search_data = request.GET.get('q', "")
    if search_data:  # value为真,即传入了搜索参数
        # mobile_contains  表示筛选出字段mobile 包含 value数据的行
        data_dict["mobile__contains"] = search_data
    # 没传参就正常显示所有的

    """排序"""
    # # order_by排序, 这里指以level倒序从高到低排
    # # 获取经过上述搜索的目的靓号,filter(**data_dict)是条件筛选,没有条件就等于all
    # queryset = models.PrettyNum.objects.filter(**data_dict).order_by("-level")

    # 根据搜索条件去库里获取
    queryset = models.PrettyNum.objects.filter(**data_dict)

    """分页"""
    ### 引入封装的 Pagination 类并初始化
    # 初始化
    page_object = Pagination(request, queryset, page_size=7)

    # 调用对象的html方法,生成页码
    page_object.html()

    context = {
        "queryset": page_object.page_queryset,  # 分页的数据
        "page_string": page_object.page_string,  # 页码
    }

    return render(request, 'pretty_list.html', context)
 HTML

注意这里表单传参写的是对应的不

    {#表格区域#}
    ...

    <!-- 分页导航 -->
    <ul class="pagination me-3">
        {{ page_string }}
    </ul>

    <!-- 页码输入框 -->
    <form class="d-flex" role="search" method="get">
        <input class="form-control me-2" type="text" placeholder="请输入页码" aria-label="页码" style="max-width: 300px;">
        <button class="btn btn-outline-success" type="submit">跳转</button>
    </form>

modelform优化

重新定义的init方法,批量设置

在field.widget.attrs设置样式

class UserModelForm(forms.ModelForm):
    class Meta:
        model = models.UserInfo
        fields = '__all__'      

    # 循环找到所有的插件,添加 "class": "form-control"和placeholder
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for name, field in self.fields.items():
            # 可以排除指定的字段
            if name == "password":
                continue
            print(name, field)
            field.widget.attrs = {
                "class": "form-control",
                "placeholder": field.label,
            }

将modelform弄成样式,init写模版里面,调用的再写class meta

新建app01-utils文件夹,内建bootstrap.py 

bootstrap.py 里的BootStrapModelForm模版
from django import forms

class BootStrapModelForm(forms.ModelForm):
    # 循环找到所有的插件,添加 "class": "form-control"
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 循环modelform中所有字段,给每个字段插件设置
        for name, field in self.fields.items():
            # # 可以排除指定的字段 # if name == "password": continue

            # 如果字段中有属性,保留原来的增加新的,没有属性再添加
            if field.widget.attrs:
                field.widget.attrs['class'] = 'form-control'
                field.widget.attrs['placeholder'] = field.label
            # 没有的就直接赋个字典
            field.widget.attrs = {
                "class": "form-control",
                "placeholder": field.label,
            }

调用:把原先的init删掉,调用BootStrapModelForm,其他照常

from app01.utils.bootstrap import BootStrapModelForm

class PrettyModelForm(BootStrapModelForm):
    # # 数据校验 方法1
    # mobile = forms.CharField(
    #     label="手机号",
    #     validators=[RegexValidator(r'^1[3-9]\d{9}$', '手机号格式错误'), ],
    # )
    class Meta:
        model = models.PrettyNum
        # fields = ['mobile', 'price', 'level', 'status']
        # exclude = ('level',)
        fields = "__all__"
    
    # 数据校验方法2
    def clean_mobile(self):
        ...

文件拆分

导入部分当然是会变的,但是它会自己提醒你改的

注意!!models不能拆(就是数据库表的那个)比较麻烦

form拆分

在app01/utilst目录下新建form.py文件,(也可以直接新建个form目录)

将views.py文件中的相关class移动到此文件中

view拆分

新建/app01/views目录
然后在其下依次新建user.py depart.py pretty.py...

将不同的视图分类放,注意要把原先的views文件删掉

修改urls

from django.contrib import admin
from django.urls import path
from employee_management.views import depart,user,pretty

urlpatterns = [
    path('admin/', admin.site.urls),

    path('depart/list/', depart.depart_list),
    path('depart/add/', depart.depart_add),
    path('depart/delete/', depart.depart_delete),
    path('depart/<int:nid>/edit/', depart.depart_edit),

    path('user/list/', user.user_list),
    path('user/model/form/add/', user.user_model_form_add),
    path('user/<int:nid>/edit/', user.user_edit),
    path('user/<int:nid>/delete/', user.user_delete),

    path('pretty/list/', pretty.pretty_list),
    path('pretty/add/', pretty.pretty_add),
    path('pretty/<int:nid>/edit/', pretty.pretty_edit),
    path('pretty/<int:nid>/delete/', pretty.pretty_delete),
]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值