2024--Django平台开发-Django知识点(六)

day06 Django知识点

今日概要:

  • Form和ModelForm组件【使用】【源码】
  • 缓存【使用】
  • ORM【使用】
  • 其他:ContentTypes、Admin、权限、分页、信号等

1.Form和ModelForm组件

背景:某个公司后台管理项目。

  • 垃圾

    python 复制代码
    def register(request):
        """ 用户注册 """
        # 1.获取提交数据
        mobile = request.POST.get("mobile")
        sms = request.POST.get("sms")
        name = request.POST.get("name")
        age = request.POST.get("age")
        email = request.POST.get("email")
        password = request.POST.get("password")
        
        # 2.校验判断(10行)
        # all([mobile,sms])
        # 正则表达式
        
        # 3.业务逻辑代码
  • 框架(内置+第三方表单验证组件)

    html 复制代码
    <form method="post">
        <input type="text" name="mobile1" />
        {{form.mobile1}}
        
        <input type="text" name="sms" />
        {{form.sms}}
        
        <input type="submit" value="提交" />
    </form>
    python 复制代码
    class MyForm(Form):
        mobile1 = forms.CharField(reg="\d{11}", required=True)
        sms = forms.CharField(required=True)
    
    def register(request):
        """ 用户注册 """
        if request.method == "GET":
            # form = MyForm(instance={"mobile1":"18766666666","sms":"999"})
            form = MyForm()
            return render(request, "xxxxx.html",{"form":form})
        
        # 1.获取提交数据
        form = MyForm(request.POST)
        if form.is_valid():
            print(form.cleared_data)
        else:
            print(form.errors)
            
        # 3.业务逻辑代码
        return render(request, "xxxxx.html",{"form":form})

关于组件:表单验证、自动生成HTML标签、数据初始化(新建按钮、编辑按钮)、保持原来的数据。

1.1 初识Form组件

基于注册为例来进行测试。

详细见示例:1-form组件.zip

1.2 错误信息

1.3 展示所有的字段

对象和可迭代对象。

1.4 问题:关于样式

  • 手动操作

    python 复制代码
    class RegisterForm(forms.Form):
        v1 = forms.CharField(
            label="手机号",
            required=True,
            # max_length=19,
            # min_length=6,
            initial="武沛齐",
            validators=[RegexValidator(r'^\d{11}$', "手机号格式错误"), ],
            widget=forms.TextInput(attrs={"class":"form-control"}) # <input type="text" class="form-control"/>
        )
        v2 = forms.CharField(
            label="备注",
            required=True,
            widget=forms.Textarea(attrs={"class":"form-control"}) # <textarea class="form-control"/></textarea>
        )
        ...
        ....
        .....
    html 复制代码
    {% for field in form %}
    	<p>{{ field.label }} {{ field }} {{ field.errors.0 }}  </p>
    {% endfor %}
  • 自动操作(找到每个字段 中的widget插件 ,再找到插件中的attrs属性,给他每个赋值**{"class":"form-control"}**

    python 复制代码
    class RegisterForm(forms.Form):
        v1 = forms.CharField(...,widget=forms.TextInput)
        v2 = forms.CharField(...,widget=forms.TextInput(attrs={"v1":"123"}))
        
        def __init__(self,*args,**kwargs):
            super().__init__(self,*args,**kwargs)
            for name,field in self.fields.items():
                if name == "v1":
                    continue 
                if field.widget.attrs:
                    field.widget.attrs.update({"class":"form-control"})
                else:
                	field.widget.attrs = {"class":"form-control"}
    python 复制代码
    form = RegisterForm()                   # __init__
    form = RegisterForm(data=request.POST)  # __init__

1.5 问题:通用父类

python 复制代码
class BootStrapForm(object):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for name, field in self.fields.items():
            field.widget.attrs = {"class": "form-control"}


class LoginForm(BootStrapForm, forms.Form):
    user = forms.CharField(label="用户名", widget=forms.TextInput)
    pwd = forms.CharField(label="密码", widget=forms.TextInput)


def login(request):
    form = LoginForm()
    return render(request, "login.html", {"form": form})
python 复制代码
class BootStrapForm(forms.Form):
    def __init__(self, *args, **kwargs):
        # 不是找父类
        # 根据类的mro(继承关系),去找上个类
        # super().__init__(*args, **kwargs)
        for name, field in self.fields.items():
            field.widget.attrs = {"class": "form-control"}

class LoginForm(BootStrapForm):
    user = forms.CharField(label="用户名", widget=forms.TextInput)
    pwd = forms.CharField(label="密码", widget=forms.TextInput)

def login(request):
    form = LoginForm()
    return render(request, "login.html", {"form": form})

1.6 答疑

类的内部继承关系,是继续c3算法。

python 复制代码
class A:
    pass

class B:
    pass

class C(B,A):
    pass

# [<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
print(C.mro())
复制代码
老师 假如我们通过继承BootStrapForm实现批量给field对象添加{'class': 'form-control'}属性,那还能添加判断是否存在属性,若存在则更新;不存在再进行添加吗

1.7 ModelForm

  • 使用Form

    • 创建Form类 + 定义字段

      python 复制代码
      class LoginForm(forms.Form):
          user = forms.CharField(label="用户名", widget=forms.TextInput)
          pwd = forms.CharField(label="密码", widget=forms.TextInput)
    • 视图

      python 复制代码
      def login(request):
          if request.method == "GET":
              form = LoginForm()
              return render(request, "login.html", {"form": form})
          form = LoginForm(data=request.POST)
          if not form.is_valid():
              # 校验失败
              return render(request, "login.html", {"form": form})
          print(form.cleaned_data)
          # ...
          return HttpRespon("OK")
    • 前端

      html 复制代码
      <form>
          {% for field in form %}
          <p>{{ field.label }} {{ field }} {{ field.errors.0 }}</p>
          {% endfor %}
      </form>
  • 使用ModelForm

    • models.py

      python 复制代码
      class UserInfo(models.Model):
          name = models.CharField(verbose_name="用户名", max_length=32)
          age = models.IntegerField(verbose_name="年龄")
          email = models.CharField(verbose_name="邮箱", max_length=128)
    • 创建ModelForm

      python 复制代码
      class LoginForm(forms.ModelForm):
          mobile = forms.CharFiled(label="手机号")
      	class Meta:
              model = models.UserInfo
              fileds = ["name","age", "mobile"]
    • 视图使用

      python 复制代码
      def login(request):
          form = LoginModelForm()
          return render(request, "login.html", {"form": form})
    • 页面

      html 复制代码
      <form>
          {% for field in form %}
          <p>{{ field.label }} {{ field }} {{ field.errors.0 }}</p>
          {% endfor %}
      </form>

    注意:

    • 后续进行增伤改查是基于数据库Models中的某个表,推荐使用:ModelForm;

    • 如果要进行表单校验是与数据库的表无关直接使用Form。

1.8 ModelForm两个好的地方

1.8.1 初始化数据

  • Form

    python 复制代码
    class LoginForm(BootStrapForm, forms.Form):
        user = forms.CharField(label="用户名", widget=forms.TextInput)
        pwd = forms.CharField(label="密码", widget=forms.TextInput)
    python 复制代码
    def login(request):
        form = LoginForm(initial={"user": "武沛齐", "pwd": "123"})
        return render(request, "login.html", {"form": form})
  • ModelForm

    python 复制代码
    class LoginModelForm(BootStrapForm, forms.ModelForm):
        mobile = forms.CharField(label="手机号", widget=forms.TextInput)
    
        class Meta:
            model = models.UserInfo
            fields = ["name", "age", "mobile"]
            widgets = {
                "age": forms.TextInput,
            }
            labels = {
                "age": "x2",
            }
    
        def clean_name(self):
            value = self.cleaned_data['name']
            # raise ValidationError("....")
            return value
    python 复制代码
    def login(request):
        user_object = models.UserInfo.objects.filter(id=1).first()
        form = LoginModelForm(instance=user_object, initial={"mobile": "武沛齐"})
        return render(request, "login.html", {"form": form})

1.8.2 新建数据

  • Form组件

    python 复制代码
    def login(request):
        if request.method == "GET":
        	form = LoginForm(initial={"user": "武沛齐", "pwd": "123"})
        	return render(request, "login.html", {"form": form})
        form = LoginForm(data=request.POST)
        if not form.is_valid():
            return render(request, "login.html", {"form": form})
        
        # form.cleaned_data
        # 手动读取字典,保存至数据库
        # models.UserInfo.objects.create(name=form.cleaned_data['xx'], pwd=form.cleaned_data['yy'])
        return HttpResponse("成功")
  • ModelForm组件

    python 复制代码
    def login(request):
        if request.method == "GET":
        	form = LoginForm()
        	return render(request, "login.html", {"form": form})
        
        form = LoginForm(data=request.POST)
        if not form.is_valid():
            return render(request, "login.html", {"form": form})
        
        form.save() # 自动将数据新增到数据库
        return HttpResponse("成功")

1.8.3 更新数据

  • Form组件

    python 复制代码
    def login(request):
        if request.method == "GET":
        	form = LoginForm(initial={"user": "武沛齐", "pwd": "123"})
        	return render(request, "login.html", {"form": form})
        form = LoginForm(data=request.POST)
        if not form.is_valid():
            return render(request, "login.html", {"form": form})
        
        # form.cleaned_data
        # 手动读取字典,保存至数据库
        # models.UserInfo.objects.create(name=form.cleaned_data['xx'], pwd=form.cleaned_data['yy'])
        # models.UserInfo.objects.filter(id=1).update(name=form.cleaned_data['xx'], pwd=form.cleaned_data['y'])
        return HttpResponse("成功")
  • ModelForm组件

    python 复制代码
    def login(request):
        if request.method == "GET":
        	form = LoginModelForm()
        	return render(request, "login.html", {"form": form})
        
        user_object = model.UserInfo.object.filter(id=1).first()
        form = LoginModelForm(data=request.POST, instance=user_object)
        if not form.is_valid():
            return render(request, "login.html", {"form": form})
        
        form.save() # 更新id=1
        return HttpResponse("成功")

1.9 案例

  • 用户登录【Form】
  • 用户管理:增改【ModelForm】

2.Form相关源码

2.1 前置知识点

1.模板渲染

python 复制代码
def login(request):
    
    # 1.打开login2.html文件读取内容 + 参数进行"替换" => 渲染  ==> 得到被替换完的字符串
    # 2.将字符串封装HttpReponse对象中,等待给用户返回。
	return render(request, 'login2.html', {"v1": "wupeiqi"})
python 复制代码
def render(request, template_name, context=None, content_type=None, status=None, using=None):
    content = loader.render_to_string(template_name, context, request, using=using)
    #    template = get_template(template_name, using=using)
    #    content = template.render(context, request)
    return HttpResponse(content, content_type, status)
python 复制代码
from django.shortcuts import HttpResponse
from django.template.loader import get_template


def v1(request):
    template = get_template("v1.html")
    text = template.render({"text": "张开"}, request)
    print(text)

    return HttpResponse("OK")

2.插件相关的类

python 复制代码
class Widget(metaclass=MediaDefiningClass):

    def __init__(self, attrs=None):
        self.attrs = {} if attrs is None else attrs.copy()

    def render(self, name, value, attrs=None, renderer=None):
        # name="user" value="zhangkai"  attrs=None   self.attrs={'class': "c1", "id": "xx1"}
        context = self.get_context(name, value, attrs)
        
        return self._render(self.template_name, context, renderer)
    
    def get_context(self, name, value, attrs):
        return {
            "widget": {
                "name": name, # "user"
                "value": self.format_value(value), # "zhangkai"
                "attrs": self.build_attrs(self.attrs, attrs), # {'class': "c1", "id": "xx1"}
                "template_name": self.template_name, # "django/forms/widgets/text.html"
                # "type":"text"
            },
        }

class Input(Widget):
    input_type = None  # Subclasses must define this.
    template_name = "django/forms/widgets/input.html"

    def __init__(self, attrs=None):
        if attrs is not None:
            attrs = attrs.copy()
            self.input_type = attrs.pop("type", self.input_type)
        super().__init__(attrs)


    def get_context(self, name, value, attrs):
        # {"widget":{"name":}   }
        context = super().get_context(name, value, attrs)
        context["widget"]["type"] = self.input_type
        return context
    
class TextInput(Input):
    input_type = "text"
    template_name = "django/forms/widgets/text.html"
    
    
class PasswordInput(Input):
    input_type = "password"
    template_name = "django/forms/widgets/password.html"

    def __init__(self, attrs=None, render_value=False):
        super().__init__(attrs)
        self.render_value = render_value

    def get_context(self, name, value, attrs):
        if not self.render_value:
            value = None
        return super().get_context(name, value, attrs)
python 复制代码
from django.shortcuts import HttpResponse
from django.template.loader import get_template

from django import forms


def v1(request):
    template = get_template("v1.html")
    text = template.render({"text": "张开"}, request)
    print(text)

    return HttpResponse("OK")


def v2(request):
    # 1.执行 TextInput的 __init__方法
    obj = forms.TextInput(attrs={'class': "c1", "id": "xx1"})
    data_string = obj.render(name="user", value="张开")
    print(data_string)  # <input type='text' name='user' value="张开" class="c1"  id="xx1" />

    obj2 = forms.PasswordInput(attrs={'class': "c2"}, render_value=True)
    data_string = obj2.render(name="user", value="张开")
    print(data_string)

    return HttpResponse("OK")

3.init和new

python 复制代码
class Foo(object):
    def __init__(self,name):
        self.name = name 

# 1. __new__ 去创建空对象 {}   -> 构造方法(创建对象)
# 2. __init__在对象中进行初始化 {"name":"武沛齐"}   -> 初始化方法
obj = Foo("武沛齐")
python 复制代码
class Foo(object):
    def __init__(self, name):
        print("init初始化", self)
        self.name = name

    def __new__(cls, *args, **kwargs):
        obj = super().__new__(cls)
        print("new创建对象", obj)
        return obj


instance = Foo("wupeiqi")
print("得到对象", instance)

4.元类

说两句:

  • 默认情况下,类都是由type创建;

    python 复制代码
    class Info(object):
        city = "背景"
    
        def show(self):
            print("123")
    
    # Info = type("Info", (object,), {"city": "背景", "show": lambda self: print(123)})
    
    obj = Info()
    print(obj.city)
    obj.show()
  • 想要由其他的东西创建类,就可以使用metaclass进行指定。

    python 复制代码
    class Info(object,metaclass=其他):
        city = "背景"
    
        def show(self):
            print("123")
    python 复制代码
    class MyType(type):
        pass
    
    
    class Info(object, metaclass=MyType):
        city = "背景"
    
        def show(self):
            print("123")

类是有type创建的,类又可以进行实例化,去创建对象。

python 复制代码
class MyType(type):
    # def __init__(self, *args, **kwargs):
    #     super().__init__(*args, **kwargs)

    def __new__(cls, *args, **kwargs):
        clazz = super().__new__(cls, *args, **kwargs)
        clazz.base_declare = [11, 22, 33]
        return clazz


class Info(object, metaclass=MyType):
    city = "背景"

    def show(self):
        print("123")

print(Info.base_declare)

5.isintance

判断某个对象是否是某个类或其子类创建的对象。

python 复制代码
class Foo(object):
    pass


class Info(object):
    pass


obj1 = Foo()
obj2 = Foo()

print(isinstance(obj1, Foo))
print(isinstance(obj2, Info))
python 复制代码
class Field(object):
    pass


class CharField(Field):
    pass


class EmailField(Field):
    pass


class ImageField(Field):
    pass


obj1 = CharField()
obj2 = EmailField()
obj3 = ImageField()

print(isinstance(obj1, Field))
print(isinstance(obj2, Field))
print(isinstance(obj3, Field))

功能:很多对象可以判断这些对象,都是我Field的子类创建的对象。

2.2 Form组件-定义类

python 复制代码
class DeclarativeFieldsMetaclass(MediaDefiningClass):
    """Collect Fields declared on the base classes."""

    def __new__(mcs, name, bases, attrs):
        # Collect fields from current class and remove them from attrs.
        attrs["declared_fields"] = {
            key: attrs.pop(key)
            for key, value in list(attrs.items())
            if isinstance(value, Field)
        }

        new_class = super().__new__(mcs, name, bases, attrs)

        # Walk through the MRO.
        declared_fields = {}
        for base in reversed(new_class.__mro__):
            # Collect fields from base class.
            if hasattr(base, "declared_fields"):
                declared_fields.update(base.declared_fields)

            # Field shadowing.
            for attr, value in base.__dict__.items():
                if value is None and attr in declared_fields:
                    declared_fields.pop(attr)

        new_class.base_fields = declared_fields
        new_class.declared_fields = declared_fields

        return new_class
python 复制代码
from django import forms

class Form(BaseForm, metaclass=DeclarativeFieldsMetaclass):
    pass

class LoginForm(forms.Form):
    username = forms.CharField(label="用户名", required=True, widget=forms.TextInput)
    pwd = forms.CharField(label="密码", required=True, widget=forms.PasswordInput)

LoginForm类其实是由DeclarativeFieldsMetaclass创建的【new】【init】。

2.3 Form组件-创建类的对象

python 复制代码
from django import forms

class LoginForm(forms.Form):
    username = forms.CharField(label="用户名", required=True, widget=forms.TextInput)
    pwd = forms.CharField(label="密码", required=True, widget=forms.PasswordInput)
python 复制代码
form = LoginForm() # __new__   __init__
python 复制代码
class BaseForm(RenderableFormMixin):
    field_order = None
    
    def __init__(self,data=None,files=None,auto_id="id_%s",prefix=None,initial=None,....,field_order=None,renderer=None):
        self.fields = copy.deepcopy(self.base_fields)
        self.order_fields(  self.field_order if field_order is None else field_order   )
        self.initial = initial or {}
        
        renderer = get_default_renderer()
        self.renderer = renderer
        
    def order_fields(self, field_order):

        if field_order is None:
            return
        fields = {}
        for key in field_order:
            try:
                fields[key] = self.fields.pop(key)
            except KeyError:  # ignore unknown fields
                pass
        fields.update(self.fields)  # add remaining fields in original order
        self.fields = fields

class Form(BaseForm, metaclass=DeclarativeFieldsMetaclass):
    pass


class LoginForm(forms.Form):
    username = forms.CharField(label="用户名", required=True, widget=forms.TextInput)
    pwd = forms.CharField(label="密码", required=True, widget=forms.PasswordInput)


form = LoginForm(initial={})

2.4 Form组件-对象.字段

python 复制代码
class LoginForm(forms.Form):
    username = forms.CharField(label="用户名", required=True, widget=forms.TextInput)
    pwd = forms.CharField(label="密码", required=True, widget=forms.PasswordInput)
python 复制代码
def v3(request):
    form = LoginForm()
    print(form['username'])  # form.username <input type="text" name="username" required id="id_username">
    
    return HttpResponse("OK")
python 复制代码
class Foo(object):

    def __getitem__(self, item):
        return 999


obj = Foo()

print(obj)
print(obj['xxxx'])
python 复制代码
class BoundField:
    "A Field plus data"

    def __init__(self, form, field, name):
        self.form = form    # Form对象
        self.field = field  #  forms.CharField(label="用户名", required=True, widget=forms.TextInput)
        self.name = name    # "username"
        self.html_name = form.add_prefix(name)
        self.html_initial_name = form.add_initial_prefix(name)
        self.html_initial_id = form.add_initial_prefix(self.auto_id)
        if self.field.label is None:
            self.label = pretty_name(name)
        else:
            self.label = self.field.label
        self.help_text = field.help_text or ""

    def __str__(self):
        """Render this field as an HTML widget."""
        return self.as_widget() # <input type="text" name="username" required id="id_username">


    def as_widget(self, widget=None, attrs=None, only_initial=False):

        # 插件对象
        widget = widget or self.field.widget
        
        if self.field.localize:
            widget.is_localized = True
        attrs = attrs or {}
        attrs = self.build_widget_attrs(attrs, widget)
        if self.auto_id and "id" not in widget.attrs:
            attrs.setdefault(
                "id", self.html_initial_id if only_initial else self.auto_id
            )
        if only_initial and self.html_initial_name in self.form.data:
            # Propagate the hidden initial value.
            value = self.form._widget_data_value(
                self.field.hidden_widget(),
                self.html_initial_name,
            )
        else:
            value = self.value()

        # 字符串= 插件forms.TextInput对象.render  《input name='?' class=".."/>
        return widget.render(
            name=self.html_initial_name if only_initial else self.html_name,
            value=value,
            attrs=attrs,
            renderer=self.form.renderer,
        )

2.5 Form组件-可迭代对象

python 复制代码
class MyForm(object):
    def __iter__(self):
        return iter([11, 22, 33, 44])


obj = MyForm()
for item in obj:
    print(item)
相关推荐
薛晓刚2 小时前
当MySQL的int不够用了
数据库
SelectDB技术团队3 小时前
Apache Doris 在菜鸟的大规模湖仓业务场景落地实践
数据库·数据仓库·数据分析·apache doris·菜鸟技术
再吃一根胡萝卜3 小时前
使用 squashmigrations 命令优化 Django 迁移文件
python·django
星空下的曙光3 小时前
mysql 命令语法操作篇 数据库约束有哪些 怎么使用
数据库·mysql
小楓12013 小时前
MySQL數據庫開發教學(一) 基本架構
数据库·后端·mysql
染落林间色3 小时前
达梦数据库-实时主备集群部署详解(附图文)手工搭建一主一备数据守护集群DW
数据库·sql
颜颜yan_4 小时前
企业级时序数据库选型指南:从传统架构向智能时序数据管理的转型之路
数据库·架构·时序数据库
lichenyang4534 小时前
管理项目服务器连接数据库
数据库·后端
沙振宇4 小时前
【数据库】通过‌phpMyAdmin‌管理Mysql数据
数据库·mysql
杨云龙UP5 小时前
CentOS Linux 7 (Core)上部署Oracle 11g、19C RAC详细图文教程
数据库·oracle