django学习 -- 可以感受到最原始的django框架是前后端不分离的 -- part.1
1.请求和响应
- get post redirect
2.数据库操作
- mysql+pymsql
- ORM框架 -> 帮助我们处理sql语句 => pip install mysqlclient
创建修改删除数据中的表(不用写sql语句)
操作表中的数据
=> 创建数据库 django连接数据
PS. 需要在setting.py进行设置
3.让django帮助创建数据库表
- django会通过model中的类帮助生成sql创建表和字段
类名代表表明 属性代表列名
class UserInfo(models.Model):
name = models.CharField(max_length=32)
password = models.CharField(max_length=64)
4.执行命令
- 需要提前注册app -> 在setting.py中注册
python manage.py makemigrations
python manage.py migrate
5.需要注意
- 在已经有的model类中添加属性 可能会导致原来已经有的数据缺失新增加的列的数据
django给出了两个选择,一是在命令行中默认添加输入,二是在新增加的属性字段中增加default=
字段,代表给原来没有的缺失值赋值。例如:
age = models.CharField(defalut=18)
或者设置可以为空
age = models.CharField(null=True,blank=True)
6.通过django向表中插入数据
-
UserInfo.objects.create(name='cyanine',password="123456")
插入数据 需要类中的属性对应
a = UserInfo.objects.all()
获取所有数据 以列表返回,其中每一个元素都是一个对象 通过.属性
获取具体的数据a.name
,结合.filter()
可以进行筛选查询
.first()
获取获取到的第一个对象 -
删除数据
.delete()
可以添加filter
进行筛选 例如UserInfo.objects.filter(name='cyanine').delete()
删除所有name为cyanine的数据
使用.all()
选择全部UserInfo.objects.all().delete()
删除这张表中的所有数据 -
更新数据
UserInfo.objects.all().updata(password=123456)
更新所有的password为123456
还可以结合.filter()
进行筛选
7.django表单如果不写action 那么默认提交就是向当前页面发送一个post请求
8.django中的url命名能避免对url的硬编码,
- 例如修改一个url 的路径如果以前在html采用的是硬编码,直接写对应的会导致后面修改维护极为困难。
但是如果采用url命名空间,那么修改的url并不会直接影响到,django会通过url的命名访问到,而不是硬编码。{% url 'url_name' other_param%}
这个url_name 就是在urls.py文件中的path('url/example', views.function,name = url_name)
的name为url从的重命名,这样修改path对应的url,就不用在维护前端的页面了。
9.model添加约束 (数据库的约束)
- 例如员工表和部门表之间的关系,让员工表和部门表关联,通过
ForeignKry
方法中的to
和to_field
参数在django中设置。用途是可以方便对输入数据的合法性判断,例如员工不能属于一个不存在的部门,就可以很方便的进行判断。 - 在员工表中
department = models.ForeignKey(to = 'Department', to_field = 'id')
这就将员工表和部门表进行了关联,员工的部门只能属于Depatment中的一个;to
表示关联的表名,to_field
表明关联的表的一个列名字段。要注意的是,django在储存这样的字段时默认命名方式是关联表名_id
(例如这个就是depaetment_id
)。
于此对应,在获取的时候,如果直接通过字段/属性获取的话,例如obj.联表名_id
,获取到的时储存在这张表中的对应关联表的数字,而不是我们想要的具体指代,因此django规定了如果直接.联表名
就可以获取到关联表对应的那一行数据(封装为一个queryobj对象),然后就可以继续通过关联表内的属性进行查找。例如,部门表中一共有两个部门,字段为(id,部门名),内容为(1,主管部)(2,运行部),员工表关联 - 级联删除 置空null
现在设想一种情况,如果部门表中的一个部门取消掉,那么与之关联的员工应该如何处理呢?常用的就是两种操作:将他们一并删除(这就是级联删除);还有一种就是将他们设置为null。对应的这两种方式在django中需要这样设置:
department = models.ForeignKey(to = 'Department', to_field = 'id',on_delete=models.CASCADE)
级联删除
department = models.ForeignKey(to = 'Department', to_field = 'id',null=True,blank=True,on_delete=models.SET_NULL)
置空 需要注意的是 置空的前提就是这个字段可以为空null = True
这些都是django中的操作。
10.性别存储
- model的choice 与数据库无关 是django的特性 可以方便的进行固定的选择储存。例如男女,单独为男女添加一个char字段会较为浪费空间,因此使用1/2这样的数字代替,但是数字不易读,因此django设计出了
choice
参数。
gender_choice = (
(1,'男'),
(2,'女'),
) #注意是元组套元组
gender = models.SmallIntegerField(verbose_name='性别',choices = gender_choice) #verbose_name就是对列名(属性)的注解 可写可不写 写上为好
#SmallIntegerField是小整数字段
- 这样字段的获取:如果直接
obj.gender
获取的就是数据库中对应的数字,但是django封装了一个判断方法,可以很方便的帮我们判断,然后返回的是我们希望现实的字段:obj.get_gender_display()
。其中函数名字组成方式为get_属性名字/字段名字_display()
11.Form和ModelForm
- 11.1 form类 自动生成表单
#views.py
class MyForm(Form):
user = forms.CharField(widget=forms.Input)
password = forms.CharField(widget=forms.Input)
email = forms.CharField(widget=forms.Input)
def user_add(request):
form = MyForm() #实力化一个form表单类
return render(request,'user_add.html',{'form':form}
<!-- user_add.html -->
<form method='post'>
{% for i in form %}
{{ i }}
{% endfor %}
<!-- 或者也可以一个一个自己写出来 比如{{form.user}} {{form.password}} -->
</form>
- 11.2 ModelForm组件
- 实现数据库表单字段和前端form表单字段的自动生成
- 对连接表/外键限制自动生成选择框
- 定义models类中的
__str__
方法实现对连接表属性的直接展示 - 定义生成表单样式的属性
{{ obj.label }}
可以遍历出在modelform定义字段中的label
参数
接下来是具体的代码展示 有点太多了...
记得添加了路由!!!(这个就不展示在代码中了,)
#views.py
#根据staff表单生成modelform类
class staffMdoelForm(ModelForm):
class Meta:
model = Staff
fields = ['name','age','gender','phonenumber','create_time']
#添加员工
def staff_add(request):
form = staffMdoelForm() #实例化modelform类
return render(request,'staff_add.html',{
'form':form
})
<div style="width:50%;margin-left: 25%;margin-top: 25px;">
<div class="container" >
<form method="post">
<h2>添加新的员工信息</h2>
{% csrf_token %}
{% for field in form %}
<div class="mb-3">
<label class="form-label">{{field.label}}</label>
{{ field }}
</div>
{% endfor %}
<button type="submit" class="btn btn-primary">确认添加</button>
</form>
</div>
</div>
#连接表modelform处理(html不用做太多改变)
#在models.py中的从表添加__str__方法 让调用这个类的时候返回的不再是一个queryobject而是__str__定义好的返回值
class Staff(models.Model):
name = models.CharField(verbose_name='员工姓名',max_length=32)
......
def __str__(self):
return self.name
#在views.py中定义modelform类的时候 字段选择直接写定义的而不是在数据库表单中的字段
class userModelForm(ModelForm):
class Meta:
model = UserInfo #注 Userinfo表单中的identify是引用了Staff表单中的id作为外键
fields = ['name','password','identify']
12.重定向
from django.shortcuts import redirect
或者from django.http import HttpResponseRedirect
return一个重定向url的实例即可
13.前端url实现删除请求
- 通过前端发送一个带有删除目标信息的GET请求,然后后端获取删除即可,但是这个带有删除目标信息的url该如何组装呢?通过url的组成规律,添加
/?id=
信息传递,代码如下:
<a href="/login/manage/delete/?id={{user.0}}">删除</a>
#这其中的{{id.0}}通过django的模板语法动态赋予目标的id信息
对应处理函数(记得注册url)
def delete_user_info(request):
id = request.GET.get('id')
UserInfo.objects.filter(id = id).delete()
return HttpResponseRedirect('/login/manage/')
14.django的模板语法
- 其中最开始的
{% extends 'nav.html'%}
必须处于子页面的第一个加载位置,意味着如果前面有哪怕{% load static %}
也会报错。
15.django正则匹配url
- 这样就不用前端写带有get参数的url,后端也不需要get获取,而是直接作为一个解析好的参数传递给视图进行处理,二是直接及进行请求和解析。同时也要注意,在url中添加的正则顺序不影响在命名url中的参数顺序
- 具体如下:
#html中
<a href="{% url 'edit' user.0 %}">操作...</a>
#url中
path('login/manage/<int:id>/edit/',views.edit_user_info,name = 'edit')
#views中
def edit_user_info(request,id):
default_userinfo = UserInfo.objects.filter(id = id).first()
....
可以看到<int:id>
是在/edit/
之前的,但是在html的url中这个顺序不影响。同时在views中对应的函数可以直接接收到url中正则匹配到的参数,而不用再通过解析get请求获取。
16.在django的模板中,可以通过obj.get_联表名_display
获取到和后端get_联表名_display()
的效果,直接返回对照过后的结果而不是对应的关联id。
17.django的模板可以进行的额外操作:
{{number : add 1}}
就是python的+=1
操作,{{datetime | date :'Y-m-d}}
就是python中的strftime()
函数(要注意的是里面的格式不需要带%
)
18.modelform的字段校验函数
is_valid()
检验提交post请求中的form表单中的字段是否为空,具体的字段就是在modelform
中fields
列表定义的那些.- 同时还可以在modelforms类中进行字段校验 错误的信息会保存在用post请求实例化的modelform中。
class staffMdoelForm(ModelForm):
phonenumber = forms.CharField(label='电话号码',max_length=11,min_length=11)#进行的字段校验
#规定电话号码的长度为11位
#还可以通过validators参数进行正则筛选
class Meta:
model = Staff
fields = ['name','age','gender','phonenumber','create_time']
phonenumber = forms.CharField(label='电话号码',max_length=11,min_length=11)
#规定电话号码的长度为11位
#还可以通过validators参数进行正则筛选
19.调整返回的提示信息为汉语
- 通过修改setting.py文件中的语言项
#setting.py
# LANGUAGE_CODE = "en-us" 注释掉
LANGUAGE_CODE = "zh-hans" #添加
20.modelform中instance
参数
- 通过设置单条数据对表单进行填充,例如:
#views.py中的一个方法
default_userinfo = UserInfo.objects.filter(id = id).first() #根据id在数据库中获取对应的一条数据
userform = userModelForm(instance=default_userinfo) # 通过instance参数设定一个实例化的表单 让他在前端渲染的时候自动在value上显示从数据库中拿到的默认值
- 通过
instance
参数和data
参数可以实现数据库数据的更新
#在views.py中的某个函数
default_userinfo = UserInfo.objects.filter(id = id).first()
userform = userModelForm(data=request.POST,instance=default_userinfo)
if userform.is_valid():
userform.save()
return redirect('/login/manage/')
else:
return render(request,'edit_info.html',{
'userform': userform,
})
- 如果想在用户输入以外的字段进行更新,那么在modelform实例化之后通过
instacne
属性可以修改:
userform = userModelForm(data=request.POST,instance=default_userinfo)
# useform.instance.字段 = 值
21.django查询排序
obj.objects.all().order_by('属性名')
如果给属性名前面添加减号 代表逆向(高到低)排序
22.给原有的表中添加新的字段产生错误"django.core.exceptions.ValidationError" error
- 产生原因:大概率是因为追加新的字段设置默认值的时候产生的格式错误,例如datetime格式但是没有设置默认或者默认格式错误,造成这样的原因。
- 解决方法:重置所有的
migrations
- 操作:删除migrations文件夹下除了
__init__.py
文件以外所有的文件,然后重新执行数据库迁移命令:python manage.py makemigrations
,python manage.py migrate
- 如果还不成功可能是因为数据库中原本存在的数据导致,将数据库清库(所有表删除),然后在执行即可。
23.django报错'orderForm' object has no attribute 'get'
- 原因是在设置
input
标签的样式的时候重写的父类方法出错,参数多写了一个self
#错误源码
def __init__(self,*arg,**kwargs):
super().__init__(self,*arg,**kwargs)
for name, field in self.fields.items():
# print(name,field) #这个是展示 self.fields.items()可以直接拿到定义在Meta中的fields字段
field.widget.attrs = {'class' : 'form-control'} #为生成的表单input赋予css属性
- 解决方法 : 去掉
super().__init__(self,*arg,**kwargs)
这一行中的self即可,正确写法:
super().__init__(*arg,**kwargs)
- 探究一下为什么
super
不需要self
作为方法的第一个参数:
因为super()
是一个类 reference -- 感觉好多...暂时搁置一下...😖
24.关闭浏览器校验
在form表单添加novalidate
<form method="post" novalidate >
25.关于models中null和black字段
- 需要同时开启,但是数据库更推荐默认值为空值,因此设置
default=None
而不是null
。
如果设置blank=True
但是不开启null=True
,那么在插入的时候,如果传回来的数据为空,插入会报错不能为null字段...总之还是很迷惑的报错....但是解决方法还是最好设置两个都为True并且设置默认字段为None
。如果为null
,那么在数据传入到前端的时候会默认输出null或者none,而不是将那片区域置空,对于前端的用户输入逻辑不太友好。
26.modelforms便捷写法
- 在添加fields的时候,可以用
__all__
一次性获取全部,exclude = [ 排除的字段 ]
排除掉不要的字段。
class orderForm(ModelForm):
class Meta():
model = Orderform
fields = "__all__" #注意要引号
# exclude = ['字段1','字段二', .... ]
27.后端表单正则校验
- 在modelforms类中声明字段,然后通过validators参数设置正则表达式:
from django.core.validators import RegexValidator #需要导入正则类
class exampleModelForms(forms.ModelForm):
moblie = forms.CharField(
label = '手机号码',
validactors = [RegexValidator(r'^1[3-9]\d{9}$','手机号格式错误')]
#校验失败返回后面的提示信息而不是默认的了~
)
28.钩子方法进行字段校验
- 详细的
- 这里摘列出常用的代码结果
class exampleModelForms(forms.ModelForm):
def clean_字段名(self): #这个需要在一个modelform类中 这个函数名modelform会自动生成对应的方法
pass
name = self.cleaned_data.get('name')
if name=='admin':
raise ValidationError('admin是超级管理员,不能注册!')#这个错误会直接扔进该字段的错误类别中:name.errors
return self.cleaned_data.get('name')
29.规定modelform中不可编辑的部分
在modelform中字段中设置参数disabled= True
即可,这样在前端页面渲染出来的这一条字段是不可以更改的。
30.通过modelform判断要添加的数据是否重复
order_edit_form = orderEditForm().filter(id=你要查询的).exist()
返回True/False
这个方法需要添加在modelform中的钩子方法中。- 排除自己以外的是否存在重复?(主要是在修改数据的时候)
通过exclude
排除自己后判断:order_edit_form = orderEditForm().exclude(id='自己的id' ).filter(id=你要查询的).exist()
返回True/False
总结 编辑和添加的不同
31.查询(根据某个字的一部分进行)
filter()
还支持传入字典:
order_edit_form = orderEditForm().filter(id=你要查询的,other=你要查询的)
#等于
query_dict = { 'id' : 要查询的, 'other' : 要查询的 }
order_edit_form = orderEditForm().filter(**query_dict)
#需要注意传入字典的时候需要两个**
PS. 通常我们再变量前加一个星号(*)表示这个变量是元组/列表,加两个星号表示这个参数是字典
32.问题记录:modelform不能更新一行数据的部分字段
- 解决方法
这里的解决方法很多 包括自定义钩子函数对post数据进行清晰、定义一个工厂函数处理每次不同的字段等,不过都太高端了,部分概念我还没有理解清楚😭 - 因此我打算采取最简单的 -- 一个字段一个字段的去
update
😳。 或者采用dict的模式,处理不变的字段和更新后的字段 组合成为一个更新后的字典然后通过modelform保存.. - 最后发现是我实例化出错了的问题....(真诚的眼瞎😭)
row_object = Orderform.objects.filter(id = id).first() #注意这里实例化的是一个form类 之前错误的原因是这里也写成了一个modelform类 这就导致下面instance的时候会报错 而且默认不更新的前端数据实际上是会传递回来的 作为表单的默认值
order_edit_form = orderEditForm(data=request.POST,instance=row_object)
#这里实例化的是一个modelforms类
33.django的条件查询
除了固定的等于(=
)查询外,还可以通过给字段/属性添加下划线的方式规定范围查询
- 数字方面:gt、gte、lt、lte:大于、大于等于、小于、小于等于。
list = BookInfo.objects.filter(id__gt=3)
代表id大于3的数据
PS. 不等于可以通过exclude
过滤 - 字符串方面:startswith、endswith:以指定值开头或结尾;contains:是否包含。
list = BookInfo.objects.filter(btitle__endswith='部')
查询是否数据中btitle字段以‘部’这个字结尾的一行数据。 - 日期查询: year、month、day、week_day、hour、minute、second:对日期时间类型的属性进行运算。
list = BookInfo.objects.filter(bpub_date__year=1980)
查询1980年发表的图书
list = BookInfo.objects.filter(bpub_date__gt=date(1990,1,1))
查询1980年1月1日后发表的图书。 - 还有很多查询: 例如比较同一行数据两个字段之间的关系(如阅读数量>=评论数量)、与或非查询、聚合等... 具体参考reference或者官网
PS. 1. filter
可以连续使用 :list=BookInfo.objects.filter(bread__gt=20).filter(id__lt=3)
2. filter
可以传入字典
34.设置get默认值
request.GET.get('page', '1')
获取get请求,如果get没有附带page参数,那么默认是1.
-
- 学习视频
- 1.请求和响应
- 2.数据库操作
- 3.让django帮助创建数据库表
- 4.执行命令
- 5.需要注意
- 6.通过django向表中插入数据
- 7.django表单如果不写action 那么默认提交就是向当前页面发送一个post请求
- 8.django中的url命名能避免对url的硬编码,
- 9.model添加约束 (数据库的约束)
- 10.性别存储
- 11.Form和ModelForm
- 12.重定向
- 13.前端url实现删除请求
- 14.django的模板语法
- 15.django正则匹配url
- 16.在django的模板中,可以通过
obj.get_联表名_display
获取到和后端get_联表名_display()
的效果,直接返回对照过后的结果而不是对应的关联id。 - 17.django的模板可以进行的额外操作:
- 18.modelform的字段校验函数
- 19.调整返回的提示信息为汉语
- 20.modelform中
instance
参数 - 21.django查询排序
- 22.给原有的表中添加新的字段产生错误
"django.core.exceptions.ValidationError" error
- 23.django报错
'orderForm' object has no attribute 'get'
- 24.关闭浏览器校验
- 25.关于models中null和black字段
- 26.modelforms便捷写法
- 27.后端表单正则校验
- 28.钩子方法进行字段校验
- 29.规定modelform中不可编辑的部分
- 30.通过modelform判断要添加的数据是否重复
- 31.查询(根据某个字的一部分进行)
- 32.问题记录:modelform不能更新一行数据的部分字段
- 33.django的条件查询
- 34.设置get默认值
- 学习视频