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)
相关推荐
Elastic 中国社区官方博客2 分钟前
Elasticsearch:Retrievers 介绍
大数据·数据库·人工智能·elasticsearch·搜索引擎·ai·全文检索
蓝桉柒717 分钟前
安装数据库客户端工具
数据库
南城花随雪。44 分钟前
Redis(非关系型数据库)详细介绍
数据库·redis·nosql
冰红茶兑滴水1 小时前
MySQL 内置函数
数据库·mysql
鸿·蒙1 小时前
【PTA】【数据库】【SQL命令】编程题2
数据库·sql·pta
J.P.August1 小时前
Oracle RAC 环境下数据文件误建在本地目录的处理过程
数据库·oracle
对酒当歌丶人生几何1 小时前
Mybatis控制台打印SQL执行信息(执行方法、执行SQL、执行时间)
java·数据库·sql·mybatis
codists2 小时前
《Django 5 By Example》阅读笔记:p339-p358
python·django
LightOfNight2 小时前
Redis设计与实现第14章 -- 服务器 总结(命令执行器 serverCron函数 初始化)
服务器·数据库·redis·分布式·后端·缓存·中间件
代码中の快捷键2 小时前
MySQL数据库存储引擎的数据结构
数据结构·数据库·mysql