美文网首页
Django系列10-员工管理系统实战--靓号管理

Django系列10-员工管理系统实战--靓号管理

作者: 只是甲 | 来源:发表于2022-09-14 10:07 被阅读0次

    一. 靓号管理:表结构设计

    我们先设计一下靓号管理后台的表结构,如下图所示:


    image.png

    根据表结构的需求,在models.py中创建类(由类生成数据库中的表)。

    class PrettyNum(models.Model):
        """ 靓号表 """
        mobile = models.CharField(verbose_name="手机号", max_length=11)
        # 想要允许为空 null=True, blank=True
        price = models.IntegerField(verbose_name="价格", default=0)
    
        level_choices = (
            (1, "1级"),
            (2, "2级"),
            (3, "3级"),
            (4, "4级"),
        )
        level = models.SmallIntegerField(verbose_name="级别", choices=level_choices, default=1)
    
        status_choices = (
            (1, "已占用"),
            (2, "未使用")
        )
        status = models.SmallIntegerField(verbose_name="状态", choices=status_choices, default=2)
    

    Django命令生成库表

    python manage.py makemigrations 
    python manage.py migrate
    

    二. URL调整

    新增对应的 增删改查对应的URL,如下图:


    image.png

    三.后端功能实现

    3.1 增删改查逻辑实现

    主要的增删改查的逻辑都写在views.py里面

    views.py

    # ################################# 靓号管理 #################################
    from app01.utils.pagination import Pagination
    from django.core.validators import RegexValidator
    from django.core.exceptions import ValidationError
    
    def pretty_list(request):
        """ 靓号列表 """
    
        data_dict = {}
        search_data = request.GET.get('q', "")
        if search_data:
            data_dict["mobile__contains"] = search_data
    
        queryset = models.PrettyNum.objects.filter(**data_dict).order_by("-level")
    
        page_object = Pagination(request, queryset)
    
        context = {
            "search_data": search_data,
    
            "queryset": page_object.page_queryset,  # 分完页的数据
            "page_string": page_object.html()  # 页码
        }
        return render(request, 'pretty_list.html', context)
    
    
    class BootStrapModelForm(forms.ModelForm):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            # 循环ModelForm中的所有字段,给每个字段的插件设置
            for name, field in self.fields.items():
                # 字段中有属性,保留原来的属性,没有属性,才增加。
                if field.widget.attrs:
                    field.widget.attrs["class"] = "form-control"
                    field.widget.attrs["placeholder"] = field.label
                else:
                    field.widget.attrs = {
                        "class": "form-control",
                        "placeholder": field.label
                    }
    
    
    class PrettyModelForm(BootStrapModelForm):
        # 验证:方式1
        mobile = forms.CharField(
            label="手机号",
            validators=[RegexValidator(r'^1[3-9]\d{9}$', '手机号格式错误'), ],
        )
    
        class Meta:
            model = models.PrettyNum
            # fields = "__all__"
            # exclude = ['level']
            fields = ["mobile", 'price', 'level', 'status']
    
        # 验证:方式2
        def clean_mobile(self):
            txt_mobile = self.cleaned_data["mobile"]
    
            exists = models.PrettyNum.objects.filter(mobile=txt_mobile).exists()
            if exists:
                raise ValidationError("手机号已存在")
    
            # 验证通过,用户输入的值返回
            return txt_mobile
    
    
    class PrettyEditModelForm(BootStrapModelForm):
        # mobile = forms.CharField(disabled=True, label="手机号")
        mobile = forms.CharField(
            label="手机号",
            validators=[RegexValidator(r'^1[3-9]\d{9}$', '手机号格式错误'), ],
        )
    
        class Meta:
            model = models.PrettyNum
            fields = ['mobile', 'price', 'level', 'status']
    
        # 验证:方式2
        def clean_mobile(self):
            # 当前编辑的哪一行的ID
            # print(self.instance.pk)
            txt_mobile = self.cleaned_data["mobile"]
            exists = models.PrettyNum.objects.exclude(id=self.instance.pk).filter(mobile=txt_mobile).exists()
            if exists:
                raise ValidationError("手机号已存在")
    
            # 验证通过,用户输入的值返回
            return txt_mobile
    
    def pretty_add(request):
        """ 添加靓号 """
        if request.method == "GET":
            form = PrettyModelForm()
            return render(request, 'pretty_add.html', {"form": form})
        form = PrettyModelForm(data=request.POST)
        if form.is_valid():
            form.save()
            return redirect('/pretty/list/')
        return render(request, 'pretty_add.html', {"form": form})
    
    def pretty_edit(request, nid):
        """ 编辑靓号 """
        row_object = models.PrettyNum.objects.filter(id=nid).first()
    
        if request.method == "GET":
            form = PrettyEditModelForm(instance=row_object)
            return render(request, 'pretty_edit.html', {"form": form})
    
        form = PrettyEditModelForm(data=request.POST, instance=row_object)
        if form.is_valid():
            form.save()
            return redirect('/pretty/list/')
    
        return render(request, 'pretty_edit.html', {"form": form})
    
    
    def pretty_delete(request, nid):
        models.PrettyNum.objects.filter(id=nid).delete()
        return redirect('/pretty/list/')
    

    3.2 分页逻辑实现

    因为靓号一般比较多,此时我们列表页面需要分页进行展示

    一般我们在app01目录下增加一个utils(工具类)目录,然后在目录下新增一个 pagination.py ,用于写分页逻辑

    """
    自定义的分页组件,以后如果想要使用这个分页组件,你需要做如下几件事:
    
    在视图函数中:
        def pretty_list(request):
    
            # 1.根据自己的情况去筛选自己的数据
            queryset = models.PrettyNum.objects.all()
    
            # 2.实例化分页对象
            page_object = Pagination(request, queryset)
    
            context = {
                "queryset": page_object.page_queryset,  # 分完页的数据
                "page_string": page_object.html()       # 生成页码
            }
            return render(request, 'pretty_list.html', context)
    
    在HTML页面中
    
        {% for obj in queryset %}
            {{obj.xx}}
        {% endfor %}
    
        <ul class="pagination">
            {{ page_string }}
        </ul>
    
    """
    
    from django.utils.safestring import mark_safe
    
    
    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: 显示当前页的 前或后几页(页码)
            """
    
            from django.http.request import QueryDict
            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")
    
            if page.isdecimal():
                page = int(page)
            else:
                page = 1
    
            self.page = page
            self.page_size = page_size
    
            self.start = (page - 1) * page_size
            self.end = page * page_size
    
            self.page_queryset = queryset[self.start:self.end]
    
            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
    

    四. 前端页面

    4.1 靓号列表

    pretty_list.html

    {% extends 'layout.html' %}
    
    {% block content %}
        <div class="container">
            <div style="margin-bottom: 10px" class="clearfix">
                <a class="btn btn-success" href="/pretty/add/">
                    <span class="glyphicon glyphicon-plus-sign" aria-hidden="true"></span>
                    新建靓号
                </a>
    
                <div style="float: right;width: 300px;">
                    <form method="get">
                        <div class="input-group">
                            <input type="text" name="q" class="form-control" placeholder="Search for..."
                                   value="{{ search_data }}">
                            <span class="input-group-btn">
                            <button class="btn btn-default" type="submit">
                                <span class="glyphicon glyphicon-search" aria-hidden="true"></span>
                            </button>
                          </span>
                        </div>
                    </form>
                </div>
    
            </div>
            <div class="panel panel-default">
                <!-- Default panel contents -->
                <div class="panel-heading">
                    <span class="glyphicon glyphicon-th-list" aria-hidden="true"></span>
                    靓号列表
                </div>
    
                <!-- Table -->
                <table class="table table-bordered">
                    <thead>
                    <tr>
                        <th>ID</th>
                        <th>号码</th>
                        <th>价格</th>
                        <th>级别</th>
                        <th>状态</th>
                        <th>操作</th>
                    </tr>
                    </thead>
                    <tbody>
                    {% for obj in queryset %}
                        <tr>
                            <th>{{ obj.id }}</th>
                            <td>{{ obj.mobile }}</td>
                            <td>{{ obj.price }}</td>
                            <td>{{ obj.get_level_display }}</td>
                            <td>{{ obj.get_status_display }}</td>
                            <td>
                                <a class="btn btn-primary btn-xs" href="/pretty/{{ obj.id }}/edit/">编辑</a>
                                <a class="btn btn-danger btn-xs" href="/pretty/{{ obj.id }}/delete/">删除</a>
                            </td>
                        </tr>
                    {% endfor %}
    
                    </tbody>
                </table>
            </div>
            <div class="clearfix">
                <ul class="pagination">
                    {{ page_string }}
                </ul>
    
            </div>
    
        </div>
    {% endblock %}
    

    4.2 靓号新增

    pretty_add.html

    {% extends 'layout.html' %}
    
    
    {% block content %}
    
        <div class="container">
            <div class="panel panel-default">
                <div class="panel-heading">
                    <h3 class="panel-title"> 新建靓号 </h3>
                </div>
                <div class="panel-body">
                    <form method="post" novalidate>
                        {% csrf_token %}
    
                        {% for field in form %}
                            <div class="form-group">
                                <label>{{ field.label }}</label>
                                {{ field }}
                                <span style="color: red;">{{ field.errors.0 }}</span>
                            </div>
                        {% endfor %}
    
                        <button type="submit" class="btn btn-primary">提 交</button>
                    </form>
                </div>
            </div>
        </div>
    
    {% endblock %}
    

    4.3 靓号修改

    pretty_edit.html

    {% extends 'layout.html' %}
    
    {% block content %}
        <div class="container">
            <div class="panel panel-default">
                <div class="panel-heading">
                    <h3 class="panel-title"> 编辑靓号 </h3>
                </div>
                <div class="panel-body">
                    <form method="post" novalidate>
                        {% csrf_token %}
    
                        {% for field in form %}
                            <div class="form-group">
                                <label>{{ field.label }}</label>
                                {{ field }}
                                <span style="color: red;">{{ field.errors.0 }}</span>
                            </div>
                        {% endfor %}
    
                        <button type="submit" class="btn btn-primary">提 交</button>
                    </form>
                </div>
            </div>
        </div>
    {% endblock %}
    

    五. 测试

    简单的增删改查此处就不再验证了,我们来验证下分页的效果

    MySQL 8.0开始支持with语句递归,此处我们直接使用with递归来造测试数据

    insert into app01_prettynum(mobile, price, level, status)
    with RECURSIVE c(n) as
     (select 1   union all select n + 1 from c where n < 400)
    select 13600000001 + n ,
           ceil(100*rand()),
           mod(n,4) + 1,
           mod(n,2) + 1
      from c;
    

    首先进入到首页:

    image.png

    选择指定页面:

    image.png

    尾页

    image.png

    参考:

    1. https://www.bilibili.com/video/BV1NL41157ph

    相关文章

      网友评论

          本文标题:Django系列10-员工管理系统实战--靓号管理

          本文链接:https://www.haomeiwen.com/subject/xiljgrtx.html