day06 Django知识点
今日概要:
- Form和ModelForm组件【使用】【源码】
- 缓存【使用】
- ORM【使用】
- 其他:ContentTypes、Admin、权限、分页、信号等
1.Form和ModelForm组件
背景:某个公司后台管理项目。
-
垃圾
pythondef 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>
pythonclass 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 问题:关于样式
-
手动操作
pythonclass 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"}**
pythonclass 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"}
pythonform = 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类 + 定义字段
pythonclass LoginForm(forms.Form): user = forms.CharField(label="用户名", widget=forms.TextInput) pwd = forms.CharField(label="密码", widget=forms.TextInput)
-
视图
pythondef 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
-
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
pythonclass LoginForm(forms.ModelForm): mobile = forms.CharFiled(label="手机号") class Meta: model = models.UserInfo fileds = ["name","age", "mobile"]
-
视图使用
pythondef 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
pythonclass LoginForm(BootStrapForm, forms.Form): user = forms.CharField(label="用户名", widget=forms.TextInput) pwd = forms.CharField(label="密码", widget=forms.TextInput)
pythondef login(request): form = LoginForm(initial={"user": "武沛齐", "pwd": "123"}) return render(request, "login.html", {"form": form})
-
ModelForm
pythonclass 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
pythondef 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组件
pythondef 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组件
pythondef 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组件
pythondef 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组件
pythondef 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创建;
pythonclass 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进行指定。
pythonclass Info(object,metaclass=其他): city = "背景" def show(self): print("123")
pythonclass 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)