【Django 网页Web开发】14. 实战项目:一些面向对象的代码结构优化(07)(保姆级图文)

时间:2022-02-13 01:16:30


欢迎关注 『Django 网页Web开发』 系列,持续更新中
欢迎关注 『Django 网页Web开发』 系列,持续更新中

1. bootstrap类

1.1 初始化时给ModelForm组件添加bootstrap样式的优化

  • 原先的代码,无论如何都是把原来组件的属性替换为了我们规定的属性
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 循环找到所有的插件,添加了class="form-control"
        for name, field in self.fields.items():
            # if name == "password":
            #     continue
            field.widget.attrs = {"class": "form-control", "placeholder": field.label}
  • 优化后的代码,在原有属性的基础上添加我们新增的属性
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
                }
  • 突然发现view.py已经有400+行的长度(虽然有不少是注释)
  • 但是我们还发现有不少冗余代码,我们在每个表的ModelForm中都定义了下面这个相同的方法,能不能把这个常用的方法也像我们分页组件一样集成封装到类中呢?

1.2 封装bootstrap类

【Django 网页Web开发】14. 实战项目:一些面向对象的代码结构优化(07)(保姆级图文)

  • bootstrap.py内容
from django import forms


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
                }

1.3 让其他调用modelForm的类继承我们的bootstrap类

  • 先把forms.ModelForm替换为BootStrapModelForm
    【Django 网页Web开发】14. 实战项目:一些面向对象的代码结构优化(07)(保姆级图文)
  • 然后导入我们写好的bootstrap类
    【Django 网页Web开发】14. 实战项目:一些面向对象的代码结构优化(07)(保姆级图文)
  • 删除掉原来我们在各个类中写好的 def __init__(self, *args, **kwargs):
  • 可以看到我们各个组件的样式仍然保留,并且以后我们新建moudleForm类只需继承bootstrap类即可实现对于所有组件样式的添加,方便快捷!

2. form类

把所有的表单类集中到一个类,放在一起写,从view.py中分离出来方便后期的管理维护。

2.1 封装form类

【Django 网页Web开发】14. 实战项目:一些面向对象的代码结构优化(07)(保姆级图文)
【Django 网页Web开发】14. 实战项目:一些面向对象的代码结构优化(07)(保姆级图文)

from app01 import models
from django.core.validators import RegexValidator
from django.core.exceptions import ValidationError
from django import forms
from app01.utils.bootstrap import BootStrapModelForm

# 新建一个StudyModelForm类
class StudyModelForm(BootStrapModelForm):
    # 一般错误检查是非空,如果要有其他检查比如最小长度3,需要像下面这样另外写(回到了form的那种)
    username = forms.CharField(min_length=3, label="用户名")

    # 创建子类,选择数据字段,给不同字段设置样式
    class Meta:
        model = models.TestForm  # 选择数据表,model表示读取数据表的指定字段
        # models = models.TestForm #选择数据表,models表示默认读取数据表的所有字段
        fields = ["username", "password"]  # 选择数据表的字段
        # widgets = {
        #     "username": forms.TextInput(attrs={"class": "form-control"}),
        #     "password": forms.PasswordInput(attrs={"class": "form-control"}),
        # }


class UserModelForm(BootStrapModelForm):
    name = forms.CharField(min_length=3, label="用户名")
    password = forms.CharField(min_length=6, label="密码")

    class Meta:
        model = models.UserInfo
        fields = ["name", "password", "age", 'account', 'create_time', "gender", "depart"]
        # widgets = {
        #     "name": forms.TextInput(attrs={"class": "form-control"}),
        #     "password": forms.PasswordInput(attrs={"class": "form-control"}),
        #     "age": forms.TextInput(attrs={"class": "form-control"}),
        # }


class PrettyModelForm(BootStrapModelForm):
    # # 数据校验:方式1 字段+正则
    # mobile = forms.CharField(
    #     label="手机号",
    #     #通过正则的方式直接判断
    #     validators=[RegexValidator(r'^1[3-9]\d{9}$', '字段+正则手机号格式错误'), ],#正则匹配首位数字1,第二位数字3-9,接下来9位数字
    # )

    # 数据校验:方式2 钩子方法
    def clean_mobile(self):
        # 当前编辑的哪一行的ID
        print(self.instance.pk)
        txt_mobile = self.cleaned_data["mobile"]  # 拿到了手机号码数据可以通过if等逻辑进行判断
        # if len(txt_mobile)!=11:
        #     raise ValidationError("钩子方法:手机号长度不对劲")
        exists = models.PrettyNum.objects.exclude(id=self.instance.pk).filter(mobile=txt_mobile).exists()
        if exists:
            raise ValidationError("钩子方法:手机号已存在")

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

    class Meta:
        model = models.PrettyNum
        fields = ["mobile", "price", "level", "status"]  # 选择展示的字段
        # fields="__all__"#显示所有字段
        # exclude=["id"]#不显示id字段

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

class PrettyEditModelForm(BootStrapModelForm):
    mobile = forms.CharField(disabled=True, label="手机号")  # 让手机号可以显示,但是不能修改

    class Meta:
        model = models.PrettyNum
        fields = ['mobile', 'price', 'level', 'status']


    # 数据校验:方式2 钩子方法
    def clean_mobile(self):

        print(self.instance.pk)  # 当前编辑的哪一行的ID
        txt_mobile = self.cleaned_data["mobile"]  # 拿到了手机号码数据可以通过if等逻辑进行判断
        # if len(txt_mobile)!=11:
        #     raise ValidationError("钩子方法:手机号长度不对劲")

        exists = models.PrettyNum.objects.exclude(id=self.instance.pk).filter(mobile=txt_mobile).exists()
        if exists:
            raise ValidationError("钩子方法:手机号已存在")

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

2.2 让view.py调用form.py中的类

from app01.utils.form import StudyModelForm,UserModelForm,PrettyModelForm,PrettyEditModelForm

3. view.py按功能拆分

3.1 view拆分结构

按照功能分为三类
【Django 网页Web开发】14. 实战项目:一些面向对象的代码结构优化(07)(保姆级图文)

3.2 把对应功能的代码迁移到对应py文件

注意移动后导包,把所需要的各种包导入好。

3.2.1 depart.py

from django.shortcuts import redirect, render
from app01 import models


def depart_list(request):
    """ 部门列表 """

    # 去数据库中获取所有的部门列表
    #  [对象,对象,对象]
    queryset = models.Department.objects.all()

    return render(request, 'depart_list.html', {'queryset': queryset})


def depart_add(request):
    """ 添加部门 """
    if request.method == "GET":
        return render(request, 'depart_add.html')

    # 获取用户POST提交过来的数据(title输入为空)
    title = request.POST.get("title")

    # 保存到数据库
    models.Department.objects.create(title=title)

    # 重定向回部门列表
    return redirect("/depart/list/")


def depart_delete(request):
    """ 删除部门 """
    # 获取ID http://127.0.0.1:8000/depart/delete/?nid=1
    nid = request.GET.get('nid')

    # 删除
    models.Department.objects.filter(id=nid).delete()

    # 重定向回部门列表
    return redirect("/depart/list/")


def depart_edit(request, nid):
    """ 修改部门 """
    if request.method == "GET":
        # 根据nid,获取他的数据 [obj,]
        row_object = models.Department.objects.filter(id=nid).first()
        return render(request, 'depart_edit.html', {"row_object": row_object})

    # 获取用户提交的标题
    title = request.POST.get("title")

    # 根据ID找到数据库中的数据并进行更新
    # models.Department.objects.filter(id=nid).update(title=title,其他=123)
    models.Department.objects.filter(id=nid).update(title=title)

    # 重定向回部门列表
    return redirect("/depart/list/")

3.2.2 pretty.py

from django.shortcuts import redirect, render
from app01 import models
from app01.utils.form import PrettyModelForm, PrettyEditModelForm
from app01.utils.pagination import Pagination


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

    ## 随机创建若干数据,写好后f5刷新一下列表生效后注释掉这些代码
    # for i in range(300):
    #     models.PrettyNum.objects.create(mobile=random.randint(13000000000,19000000000),price=random.randint(1,1000),level=random.randint(1,4),status=random.randint(1,2))

    # import copy
    # query_dict=copy.deepcopy(request.GET)#http://127.0.0.1:8000/pretty/list/?q=1&csdn=2023
    # print(query_dict.urlencode())#q=1&csdn=2023
    # query_dict.mutable=True#不修改这个参数就会报错提示无法修改
    # query_dict.setlist('page',[11])#q=1&csdn=2023&page=11 在原来的基础上增加了&page=11
    # print(query_dict.urlencode())#讲url打印出来


    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")  # -level表示按照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)




from django.core.exceptions import ValidationError  # 导入Django异常模块



def pretty_add(request):
    """ 添加靓号 """
    if request.method == "GET":
        form = PrettyModelForm()
        return render(request, 'pretty_add.html', {"form": form})  # 通过render将对象传入到HTML中。
    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.3 user.py

from django.shortcuts import redirect, render
from app01 import models
from app01.utils.form import UserModelForm
from app01.utils.pagination import Pagination

def user_list(request):
    """ 用户管理 """
    ## 随机创建若干数据,写好后f5刷新一下列表生效后注释掉这些代码
    # for i in range(300):
    #     models.UserInfo.objects.create(name="张龙分身{}".format(i),password="123456",age=1,account=1,gender=1,create_time="2023-03-15 10:00:17.000000", depart_id=1)

    # 获取所有用户列表 [obj,obj,obj]
    queryset = models.UserInfo.objects.all()

    page_object = Pagination(request, queryset, page_size=5)
    context = {
        "queryset": page_object.page_queryset,
        "page_string": page_object.html(),
    }
    return render(request, 'user_list.html', context)

    """
    # 用Python的语法获取数据
    for obj in queryset:
        print(obj.id, obj.name, obj.account, obj.create_time.strftime("%Y-%m-%d"), obj.gender, obj.get_gender_display(), obj.depart_id, obj.depart.title)
        # print(obj.name, obj.depart_id)
        # obj.depart_id  # 获取数据库中存储的那个字段值
        # obj.depart.title  # 根据id自动去关联的表中获取哪一行数据depart对象。
    """


def user_add(request):
    """ 添加用户(原始方式) """

    if request.method == "GET":
        context = {
            'gender_choices': models.UserInfo.gender_choices,
            "depart_list": models.Department.objects.all()
        }
        return render(request, 'user_add.html', context)

    # 获取用户提交的数据
    user = request.POST.get('user')
    pwd = request.POST.get('pwd')
    age = request.POST.get('age')
    account = request.POST.get('ac')
    ctime = request.POST.get('ctime')
    gender = request.POST.get('gd')
    depart_id = request.POST.get('dp')

    # 添加到数据库中
    models.UserInfo.objects.create(name=user, password=pwd, age=age,
                                   account=account, create_time=ctime,
                                   gender=gender, depart_id=depart_id)

    # 返回到用户列表页面
    return redirect("/user/list/")


# ################################# ModelForm 示例 #################################
from django import forms


def user_model_form_add(request):
    """ 添加用户(ModelForm版本)"""
    if request.method == "GET":
        form = UserModelForm()
        return render(request, 'user_model_form_add.html', {"form": form})

    # 用户POST提交数据,数据校验。
    form = UserModelForm(data=request.POST)
    if form.is_valid():
        # 如果数据合法,保存到数据库
        # {'name': '123', 'password': '123', 'age': 11, 'account': Decimal('0'), 'create_time': datetime.datetime(2011, 11, 11, 0, 0, tzinfo=<UTC>), 'gender': 1, 'depart': <Department: IT运维部门>}
        # print(form.cleaned_data)
        # models.UserInfo.objects.create(..)
        form.save()
        return redirect('/user/list/')

    # 校验失败(在页面上显示错误信息)
    return render(request, 'user_model_form_add.html', {"form": form})


def user_edit(request, nid):
    """ 编辑用户 """
    row_object = models.UserInfo.objects.filter(id=nid).first()  # 获取指定用户的那一行数据

    if request.method == "GET":
        # 根据ID去数据库获取要编辑的那一行数据(对象)
        form = UserModelForm(instance=row_object)
        # instance 数据表的某一行,ModelForm会自动把这一行数据填充到表单中,也就是修改数据时,一开始的输入框中填写好了原来修改前的值
        return render(request, 'user_edit.html', {'form': form})

    form = UserModelForm(data=request.POST, instance=row_object)
    if form.is_valid():  # 如果是合法的数据准备保存进数据库
        # 默认保存的是用户输入的所有数据,如果想要再用户输入以外增加一点值
        # form.instance.字段名 = 值
        form.save()
        return redirect('/user/list/')
    return render(request, 'user_edit.html', {"form": form})  # 如果数据不合法


def user_delete(request, nid):
    models.UserInfo.objects.filter(id=nid).first().delete()  # 一行delete,这个first可加可不加,看你的id是否唯一
    return redirect('/user/list/')

3.3 修改url.py中与view对应的路径

核心在于导入三个新类,然后把原来的view替换为对应的新类类名,然后把view删除掉。400+行的view按照功能化整为零。

from app01.views import depart
from app01.views import pretty
from app01.views import user
from django.urls import path

from app01 import views
from app01.views import depart
from app01.views import pretty
from app01.views import user

urlpatterns = [
    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/add/', user.user_add),  # 用户添加

    path('user/model/form/add/', user.user_model_form_add),  # 添加用户(ModelForm版本)
    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),

]


总结

大家喜欢的话,给个????,点个关注!给大家分享更多有趣好玩的Python 网页Web开发知识!

版权声明:

发现你走远了@mzh原创作品,转载必须标注原文链接

Copyright 2023 mzh

Crated:2023-3-1

欢迎关注 『Django 网页Web开发』 系列,持续更新中
欢迎关注 『Django 网页Web开发』 系列,持续更新中
『01. 安装配置Django』
『02. 创建并运行一个Django项目』
『03. 初识Django』
『04. 请求和响应,网页跳转重定向,实战简易表单模拟登陆』
『05. 数据库操作,实战用户管理』
『06. 报错:You have 26 unapplied migration(s). Your project may not work properly until you apply the migra』
『07. 模板语法』
『08. 实战项目:部门和员工管理系统(01)』
『09. 实战项目:员工编辑删除功能与靓号管理(02)』
『10. 实战项目:靓号搜索功能(03)』
『11. 实战项目:分页与页码跳转功能(04)』
『12. 实战项目:分页组件的封装 面向接口编程(05)』
『13. 实战项目:添加用户时的时间选择组件(06)』
『14. 实战项目:一些面向对象的代码结构优化(07)』
『15. 实战项目:管理员增删改查,md5密码和密码重置(08)』
『16. 实战项目:BootStrap类的进一步优化(09)』
『17. 实战项目:login业务涉及cookie、session、中间件(10)』
『18. 实战项目:登录时的验证码(11)』
『19. 实战项目:初识Ajax请求(12)』
『20. 实战项目:Ajax实战之订单管理与弹出对话框(13)』
『21. 实战项目:echart数据图表(14)』
『22. 实战项目:简单的文件上传(15)』
『23. 实战项目:Excel和form和moudleForm的文件上传(16)』
【更多内容敬请期待】