标签:form required fan ... cap const oracl lam uri
目录
db first 先连接数据库 -> ...
code first 先创建类 -> sqlachemy、Django、大多数都是
ORM:Object Relational Mapping(关系对象映射)
类名 ->> 数据库中的表名
类属性 ->> 数据库里的字段
类实例 ->> 数据库表里的一行数据
obj.name..... ->> 类实例对象的属性
Django orm的优势:Django的orm操作本质上会根据对接的数据库引擎,翻译成对应的sql语句;所有使用Django开发的项目无需关心程序底层使用的是MySQL、Oracle、sqlite....,如果数据库迁移,只需要更换Django的数据库引擎即可
QuerySet特点:
可迭代的
可切片
惰性计算:等于一个生成器,.objects.all()或者.filter()等都只是返回了一个QuerySet的查询结果集对象,它并不会马上执行sql,而是当调用QuerySet的时候才执行。
缓存机制:每一次数据库查询结果QuerySet都会对应一块缓存,再次使用该QuerySet时,不会发生新的SQL操作
这样减小了频繁操作数据库给数据库带来的压力
但是有时候取出来的数据量太大会撑爆缓存,可以使用迭代器解决这个问题:
models.Publish.objects.all().iterator()
/app/models.py
from django.db import models
# 表名为app01_userinfo
class UserInfo(models.Model):
# 自动创建id列,自增,主键
# 列名,字符串类型,指定长度
username = models.CharField(max_length=32)
password = models.CharField(max_length=64)
email = models.EmailField(max_length=19)
类的字段和参数详见字段和参数
/./settings.py
INSTALLED_APPS = [
...,
‘app01‘,
]
python manage.py makemigrations -> 生成表结构的缓存
python manage.py migrate -> 创建表结构
/./settings.py -> DATABASES
********** 注意 ***********
Django默认使用MySQLdb模块链接MySQL
主动修改为pymysql,在project同名文件夹下的__init__文件中添加如下代码即可:
import pymysql
pymysql.install_as_MySQLdb()
/app/views.py
from app01 import models
def orm(request):
# 直接传入参数
models.UserInfo.objects.create(username=‘root‘,password=‘123‘)
# 传入字典
dic = {‘username‘: ‘eric‘, ‘password‘: ‘666‘}
models.UserInfo.objects.create(**dic)
# 另一种增加方式
obj = models.UserInfo(username=‘alex‘,password=‘123‘)
obj.save()
result = models.UserInfo.objects.all()
result = models.UserInfo.objects.filter(user=‘root‘,psd=‘123‘) -> filter传入字典也可 **dic
=> QuerySet, Django的一种列表, [], 内部元素是.obj => [obj(id,username),obj]
# 转化为字典输出
.all().values(‘id‘,‘caption‘) -> [{‘id:1,‘username‘:‘alex‘},{},{}]
# 转化为tuple输出
.all().values_list(‘id‘,‘caption‘) -> [(1,‘alex‘),(),()]
# 取第一个obj
.filter(xxx).first() -> 不存在返回None
=> 用get取单条数据,如果不存在,直接报错
=> models.UserInfo.objects.get(id=nid)
# 计数
.filter(name=‘seven‘).count()
# 切片
.all()[10:20]
.all()[::2]
.all()[6] # 索引
# 去重
.distinct()
# 排序
.filter(name=‘seven‘).order_by(‘id‘) -> asc
.filter(name=‘seven‘).order_by(‘-id‘) -> desc
models.UserInfo.objects.filter(username="alex").delete()
models.UserInfo.objects.filter(id=3).update(password="69") # 可添加**kwargs形式
# 或者先查找对象再修改保存
obj = models.tb.objects.get(id=1)
obj.c1 = ‘111‘
obj.save() # 修改单条数据
# 大于小于
.filter(id__gt=1) -> > 1
.filter(id=1) -> = 1
.filter(id__lt=1) -> < 1
.filter(id__lte=1) -> <= 1
.filter(id__gte=1) -> >= 1
.exclude(id__gt=1) -> != 1 exclude 除了...与filter相反
.filter(id__gt=1, id__lt=10) -> 1< x <10
# 范围range
.filter(id__range=[1,3]) -> [1~3] bettwen + and
# 范围in
.filter(id__in=[1,2,3]) -> in [1,2,3]
.exclude(id__in=[1,2,3]) -> in [1,2,3]
# 是否为空
.filter(name__isnull=True)
# 包含、开头、结尾 __startswith, istartswith, endswith, iendswith
.filter(name__contains="ven")
.filter(name__icontains="ven") # i 忽略大小写
# regex正则匹配,iregex 不区分大小写
.get(title__regex=r‘^(An?|The) +‘)
.get(title__iregex=r‘^(an?|the) +‘)
# date
.filter(pub_date__date=datetime.date(2005, 1, 1))
.filter(pub_date__date__gt=datetime.date(2005, 1, 1))
# year、month、day、week_day
.filter(pub_date__year=2005)
.filter(pub_date__year__gte=2005)
# hour、minute、second
.filter(timestamp__hour=23)
.filter(time__hour=5)
.filter(timestamp__hour__gte=12)
F模块,用于获取对象中的某一字段(列)的值,并且对其进行操作;
from django.db.models import F # 首先导入F模块
models.Book.objects.all().update(price=F(‘price‘)+1) # 每一本书的价格上调1块钱
Q模块,用于构造复杂的查询条件,使用逻辑关系(&与、|或、~非)组合进行多条件查询;
虽然filter中可以使用 , 隔开表示关系与,但没法表示或非的关系
from django.db.models import Q # 导入Q模块
# 方式一:
.filter( Q(id__gt=10) ) ->
.filter( Q(id=8) | Q(id__gt=10) ) -> or
.filter( Q( Q(id=8) | Q(id__gt=10) ) & Q(caption=‘root‘) ) -> and, or
# 方式二:
# 可以组合嵌套
# q1里面的条件都是or的关系
q1 = Q()
q1.connector = ‘OR‘
q1.children.append((‘id‘, 1))
q1.children.append((‘id‘, 10))
q1.children.append((‘id‘, 9))
# q2里面的条件都是or的关系
q2 = Q()
q2.connector = ‘OR‘
q2.children.append((‘c1‘, 1))
q2.children.append((‘c1‘, 10))
q2.children.append((‘c1‘, 9))
# con通过and的条件把q1和q2联系到一块
con = Q()
con.add(q1, ‘AND‘)
con.add(q2, ‘AND‘)
models.tb.objects.filter(con)
实例:查询作者姓名中包含 方/少/伟/3字,书名不包含伟,并且出版社地址以山西开头的书
book=models.Book.objects.filter(
Q(
Q(author__name__contains=‘方‘) |
Q(author__name__contains=‘少‘) |
Q(author__name__contains=‘伟‘) |
Q(title__icontains=‘伟‘)
) &
Q(publish__addr__contains=‘山西‘)
).values(‘title‘)
注意:Q查询和非Q查询混合使用,非Q查询一定要放在Q查询后面
extra方法
对不同的数据库引擎可能存在移植问题(因为你在显式的书写SQL语句),尽量避免使用extra
a.映射
- select={‘new_id‘:select count(1) from app01_usertype where id>%s‘}
- select_params=[1,]
# 例:
models.UserInfo.objects.all().extra(
select={
‘n‘:"select count(1) from app01_utype WHERE id=%s or id=%s",
‘m‘:"select count(1) from app01_uinfo WHERE id=%s or id=%s",
},
select_params=[1,2,3,4]
)
b.条件
- where=["foo=‘a‘ OR bar = ‘a‘", "baz = ‘%s‘"],
- params=[‘Lennon‘,]
c.表
- tables=["app01_usertype"]
d.排序
- order_by = [‘-id‘]
# 例1:
models.UserInfo.objects.extra(
select={‘new_id‘:select count(1) from app01_usertype where id>%s‘},
select_params=[1,],
where=[‘age>%s‘],
params=[18,],
order_by=[‘-age‘],
tables=["app01_usertype‘]
)
-> 相当于:
‘‘‘
select
app01_userinfo.id,
(select count(1) from app01_usertype where id>1) as new_id
from
app01_userinfo,
app01_usertype
where
app01_userinfo.age>18
order by
app01_userinfo.age desc
‘‘‘
# 例2:
current_user = models.UserInfo.objects.filter(username=username).first() # 当前用户
1、models.Article.objects.all() # 查出每一篇文章
2、models.Article.objects.all().filter(user=current_user) # 查出当前用户的所有文章
3、models.Article.objects.all().filter(user=current_user).extra(select={"filter_create_date":"strftime(‘%%Y/%%m‘,create_time)"}).values_list("filter_create_date")
# 查出当前用户的所有文章的create_time,并且只取出年份和月份
执行原生SQL的三种方式
1.使用extra方法
结果集修改器,一种提供额外查询参数的机制
依赖model模型
2.使用raw方法
执行原始sql并返回模型
依赖model多用于查询
book = Book.objects.raw("select * from hello_book")
for item in book:
print(item.title)
3.使用cursor游标
不依赖model
from django.db import connection, connections
cursor = connection.cursor()
# 或cursor = connections[‘default‘].cursor()
# 其中‘default‘是django数据库配置的default,也可取别的值
cursor.execute("""SELECT * from auth_user where id = %s""", [1])
row = cursor.fetchone()
AutoField(Field) -> 自定义自增列(必须加primary_key=True)
IntegerField(Field) -> 整数列
BooleanField(Field) -> 布尔
GenericIPAddressField(Field) -> IP验证(仅限django admin)
URLField(CharField) -> url验证(仅限django admin)
# Django里有很多的字段类型在数据库中都是Char类型,只是用于django admin便于区分
更多详见:武沛齐的博客 - Django
null -> db中是否可以为空
default=‘‘ -> 默认值
primary_key -> 是否主键
db_column -> 列名
db_index -> 是否可索引
unique -> 是否可唯一索引
unique_for_date -> 【日期】部分是否可索引
unique_for_month -> 【月】部分是否可索引
unique_for_year -> 【年】部分是否可索引
auto_now_add -> 创建时,自动生成时间
auto_now -> 更新时,自动更新为当前时间
# update方式不生效,先获取再更改才生效
ctime = models.DateTimeField(auto_now_add=True)
UserGroup.objects.filter(id=1).update(caption=‘CEO‘) -> 不生效
obj = UserGroup.objects.filter(id=1).first()
obj.caption = "CEO" -> 生效,自动更新更改时间
obj.save()
# django admin中才生效的字段
blank -> django admin是否可以为空
verbose_name=‘‘ -> django admin显示字段中文
editable -> django admin是否可以被编辑
help_text -> django admin帮助提示
choices=[] -> django admin中显示下拉框
# 可避免连表查询,提高效率,一般用于基本不变的选项
user_type_choices = (
(1, ‘超级用户‘),
(2, ‘普通用户‘),
(3, ‘普普通用户‘),
)
user_type_id = models.IntegerField(choices=user_type_choices,default=1)
error_messages -> 自定义错误信息(字典类型)
# 字典的键:null, blank, invalid, invalid_choice, unique, unique_for_date
# 例:error_messages = {‘null‘: "不能为空", ‘invalid‘: ‘格式错误‘}
validators -> django form ,自定义错误信息(列表类型)
# 例:
from django.core.validators import RegexValidator
from django.core.validators import EmailValidator,URLValidator,DecimalValidator, MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator
error_messages={
‘c1‘: ‘优先错信息1‘,
‘c2‘: ‘优先错信息2‘,
‘c3‘: ‘优先错信息3‘,
},
validators=[
RegexValidator(regex=‘root_\d+‘, message=‘错误了‘, code=‘c1‘),
RegexValidator(regex=‘root_112233\d+‘, message=‘又错误了‘, code=‘c2‘),
EmailValidator(message=‘又错误了‘, code=‘c3‘), ]
更多错误信息的使用方法参考武沛齐 - FORM
创建 Django admin用户: python manage.py createsuperuser
class UserInfo(models.Model):
...
class Meta:
# 定义数据库中生成的表名称 默认 app名称 + 下划线 + 类名
db_table = "table_name"
# 联合索引
index_together = [("pub_date", "deadline"),]
# 联合唯一索引,一旦三者都相同,则会被Django拒绝创建。
可以同时设置多组约束。为了方便,对于只有一组约束的情况下,可以简单地使用一维元素
unique_together = (("driver", "restaurant"),)
# admin后台中显示的表名称
verbose_name = ‘用户信息‘
# verbose_name加s,复数形式,不指定自动加s
verbose_name_plural =
# 默认排序
ordering=[‘-order_date‘] # 按订单降序排列,-表示降序,不加升序,加?表示随机
ordering=[‘-pub_date‘,‘author‘] # 以pub_date为降序,再以author升序排列
更多:https://docs.djangoproject.com/en/1.10/ref/models/options/
触发Model中的验证和错误提示有两种方式:
a. Django Admin中的错误信息会优先根据Admin内部的ModelForm错误信息提示,如果都成功,才来检查Model的字段并显示指定错误信息
b. 调用Model对象的 clean_fields 方法,如:
# models.py
class UserInfo(models.Model):
username = models.CharField(max_length=32)
email = models.EmailField(error_messages={‘invalid‘: ‘格式错了.‘})
# views.py
def index(request):
obj = models.UserInfo(username=‘11234‘, email=‘uu‘)
try:
print(obj.clean_fields())
except Exception as e:
print(e)
return HttpResponse(‘ok‘)
# Model的clean方法是一个钩子,可用于定制操作,如:上述的异常处理。
Admin中修改错误提示
# admin.py
from django.contrib import admin
from model_club import models
from django import forms
class UserInfoForm(forms.ModelForm):
username = forms.CharField(error_messages={‘required‘: ‘用户名不能为空.‘})
email = forms.EmailField(error_messages={‘invalid‘: ‘邮箱格式错误.‘})
age = forms.IntegerField(initial=1, error_messages={‘required‘: ‘请输入数值.‘, ‘invalid‘: ‘年龄必须为数值.‘})
class Meta:
model = models.UserInfo
# fields = (‘username‘,)
fields = "__all__"
class UserInfoAdmin(admin.ModelAdmin):
form = UserInfoForm
admin.site.register(models.UserInfo, UserInfoAdmin)
当一张表中创建一行数据时,有一个单选的下拉框(可以被重复选择)
创建表结构时关联外键
user_group = models.ForeignKey("UserGroup",to_field=‘uid‘) ->> obj(UserGroup)
# 自动创建user_group_id列,存的是数字(关联主键)
添加数据时关联id或对象
方式一:创建数据时添加id关联
models.UserInfo.object.create(name=‘root‘, user_group_id=1)
方式二:查询obj对象进行关联
user_group = models.UserGroup.objects.filter(id=1).first()
由原来的2张表,变成一张表!
# 例:回复评论
class Comment(models.Model):
news_id = models.IntegerField() -> 新闻ID
content = models.CharField(max_length=32) -> 评论内容
user = models.CharField(max_length=32) -> 评论者
reply = models.ForeignKey(‘Comment‘,null=True,blank=True,related_name=‘xxxx‘) -> 回复ID
# 注意:回复的id必须是已经存在的评论的id
在某表中创建一行数据是,有一个可以多选的下拉框
两种创建方式
以下两种创建方式建议都用,自动创建的只能关联两个表,自定义的可以不断关联
方式一:自定义关系表
可以直接操作第三张表,但无法通过字段跨表查询,查询麻烦
class UserInfo(models.Model):
...
class UserGroup(models.Model):
...
# 创建中间表
class UserInfoToUserGroup(models.Model):
user_info_obj = models.ForeignKey(to=‘UserInfo‘,to_field=‘nid‘)
group_obj = models.ForeignKey(to=‘UserGroup‘,to_field=‘id‘)
# 添加关联数据:
UserInfoToApp.objects.create(user_info_obj_id=1,group_obj_id=2)
方式二:Django自动创建关系表
可以使用字段跨表查询,但无法直接操作第三张表
class UserInfo(models.Model):
...
# ManyToManyField字段
class UserGroup(models.Model):
user_info = models.ManyToManyField("UserInfo")
方式三:既自定义第三张关系表 也使用ManyToManyField字段(杂交类型)
既可以使用字段跨表查询,也可以直接操作第3张关系表
注意:obj.m.all() 只有查询和清空方法
# 例:博主粉丝关系
class UserInfo(AbstractUser):
...
fans = models.ManyToManyField(to=‘UserInfo‘,
through=‘UserFans‘, -> 指定关系表表名
through_fields=(‘user‘, ‘follower‘)) -> 指定关系表字段
class UserFans(models.Model):
...
user = models.ForeignKey(to=‘UserInfo‘, to_field=‘nid‘, related_name=‘users‘)
follower = models.ForeignKey(to=‘UserInfo‘, to_field=‘nid‘, related_name=‘followers‘)
class Meta:
unique_together = [(‘user‘, ‘follower‘),]
(由原来的3张表,变成只有2张表)
把两张表通过 choices 字段合并为一张表
使用ManyToManyField字段
1、查询第三张关系表前面那一列:obj.m
2、查询第三张关系表后面那一列:obj.userinfo_set
class Userinfo(models.Model):
sex=((1,‘男‘),(2,‘女‘))
gender=models.IntegerField(choices=sex)
m=models.ManyToManyField(‘Userinfo‘)
# 通过男士查询女生
boy_obj=models.Userinfo.objects.filter(id=4).first()
res=boy_obj.m.all()
# 通过女士查询男生
girl_obj=models.Userinfo.objects.filter(id=4).first()
res=girl_obj.userinfo_set.all()
在某表中创建一行数据时,有一个单选的下拉框(下拉框中的内容被用过一次就消失了)
例如:原有含10列数据的一张表保存相关信息,经过一段时间之后,10列无法满足需求,需要为原来的表再添加5列数据
r = models.OneToOneField(...)
# 1. 一对一其实就是 一对多 + 唯一索引
# 2. 当两个类之间有继承关系时,默认会创建一个一对一字段
# 如下会在A表中额外增加一个 c_ptr_id 列且唯一:
class C(models.Model):
nid = models.AutoField(primary_key=True)
part = models.CharField(max_length=12)
class A(C):
id = models.AutoField(primary_key=True)
code = models.CharField(max_length=1)
一对多ForeignKey()
to -> 要关联的表名
to_field=‘uid‘, -> 要关联的字段,不写默认关联主键
on_delete=None, -> 删除关联表中的数据时,当前表与其关联的行的行为
- models.CASCADE -> 与之关联的也删除
- models.DO_NOTHING -> 引发错误IntegrityError
- models.PROTECT -> 引发错误ProtectedError
- models.SET_NULL -> 与之关联的值设为null(前提FK字段可为空)
- models.SET_DEFAULT -> 与之关联的值设为默认值(前提FK字段有默认值)
- models.SET -> 与之关联的值设为指定值
# 有两种指定方法
a. 设置为指定值:models.SET(值)
b. 设置为可执行对象的返回值,如:models.SET(func)
def func():
return 10
class MyModel(models.Model):
user = models.ForeignKey(...,on_delete=models.SET(func))
related_name=None, -> 反向操作时,使用的字段名,用于替换【表名_set】
如: obj.表名_set.all()
related_query_name=None, -> 反向操作时,使用的连接前缀,用于替换【表名】
如: ...filter(表名__字段名=1).values(‘表名__字段名‘)
limit_choices_to=None, -> 在Admin或ModelForm中显示关联数据时,提供的条件:
- limit_choices_to={‘nid__gt‘: 5}
- limit_choices_to=lambda : {‘nid__gt‘: 5}
from django.db.models import Q
- limit_choices_to=Q(nid__gt=10)
- limit_choices_to=Q(nid=8) | Q(nid__gt=10)
- limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption=‘root‘)
db_constraint=True -> 是否在数据库中创建外键约束
parent_link=False -> 在Admin中是否显示关联数据
多对多ManyToManyField()
symmetrical=None, -> 仅用于多对多自关联时,指定内部是否创建反向操作的字段
=> 做如下操作时,不同的symmetrical会有不同的可选字段
models.BB.objects.filter(...)
=> 可选字段有:code, id, m1
class BB(models.Model):
code = models.CharField(max_length=12)
m1 = models.ManyToManyField(‘self‘,symmetrical=True)
=> 可选字段有: code, id, m1, bb
class BB(models.Model):
code = models.CharField(max_length=12)
m1 = models.ManyToManyField(‘self‘,symmetrical=False)
through=None, -> 自定义第三张表时,用于指定关系表
through_fields=None, -> 自定义第三张表时,用于指定关系表中哪些字段做多对多关系表
db_constraint=True, -> 是否在数据库中创建外键约束
db_table=None, -> 默认创建第三张表时,数据库中表的名称
一对一OneToOneField()
to -> 要关联的表名
to_field=‘uid‘, -> 要关联的字段,不写默认关联主键
on_delete=None, -> 删除关联表中的数据时,当前表与其关联的行的行为
获取值时使用 . 连接
group_obj = models.UserGroup.objects.filter(id=1).first() # orm连表必须取单个对象
# 增
group_obj.user_info.add(1) -> 添加一个
group_obj.user_info.add(2,3,4) -> 添加多个
group_obj.user_info.add(*[1,2,3,4]) -> 添加*列表
# 删
group_obj.user_info.remove(1)
group_obj.user_info.remove(2,4)
group_obj.user_info.remove(*[1,2,3])
group_obj.user_info.clear() -> 清除当前对象关联的多对多数据
# 改
group_obj.user_info.set([3,5,7]) -> (不加*)只保留1-3,1-5,1-7,其它删除
# 查
group_obj.user_info.all() -> 获取所有相关的主机obj 的QuerySet
group_obj.user_info.filter()
......
搜索条件使用 __ 连接 (value、value_list、fifter)
obj = models.UserGroup.objects.filter(id=1).value(‘name‘,‘user_info__name‘).first()
在html里也用obj.user_group__name
反查
# . 操作,获取对象的QuerySet,表名小写_set
user_info_obj.usergroup_set.add(group_obj)
user_info_obj.usergroup_set.remove(group_obj)
user_info_obj.usergroup_set.all()
user_info_obj.usergroup_set.filter()
......
# __操作,搜索属性,表名小写__属性
obj = models.UserInfo.objects.filter(‘usergruop__name‘).first()
related_query_name -> 反向查找时用 obj.别名_set.all(),保留了_set
relatedname -> 反向查找时用 obj.别名.all()
# 例如:
‘‘‘把男女表混合在一起,在代码层面控制第三张关系表的外键关系‘‘‘
# models.py
class UserInfo(models.Model):
...
sex=((1,‘男‘),(2,‘女‘))
gender=models.IntegerField(choices=sex)
class U2U(models.Model):
b=models.ForeignKey(Userinfo,related_name=‘boy‘)
g=models.ForeignKey(Userinfo,related_name=‘girl‘)
# 写到此处问题就来了,原来两个外键 对应2张表 2个主键,可以识别男女
# 现在两个外键对应1张表,反向查找,无法区分男女了了
# object对象女.U2U.Userinfo.set object对象男.U2U.Userinfo.set
# 所以要加related_name设置反向查找命名 对表中主键加以区分
# 查找方法
# 男:obj.a.all()
# 女:obj.b.all()
# views.py
def index(request):
#查找 ID为1男孩 相关的女孩
boy_obj=models.UserInfo.objects.filter(id=1).first()
res = boy_obj.boy.all() # 得到U2U的对象再正向跨表
for obj in res:
print(obj.girl.name)
return HttpResponse(‘OK‘)
aggregate() 聚合函数
通过对QuerySet进行计算,返回一个聚合值的字典。
aggregate()中每一个参数都指定一个包含在字典中的返回值。即在查询集上生成聚合。
from django.db.models import Avg,Sum,Max,Min
# 求书籍的平均价
ret = models.Book.objects.all().aggregate(Avg(‘price‘))
# {‘price__avg‘: 145.23076923076923}
# 参与西游记著作的作者中最老的一位作者
ret = models.Book.objects.filter(title__icontains=‘西游记‘).values(‘author__age‘).aggregate(Max(‘author__age‘))
# {‘author__age__max‘: 518}
annotate() 分组函数
# 查看每一位作者出过的书中最贵的一本
# (按作者名分组 values(),然后 annotate() 分别取每人出过的书价格最高的)
ret=models.Book.objects.values(‘author__name‘).annotate(Max(‘price‘))
# < QuerySet[
# {‘author__name‘: ‘吴承恩‘, ‘price__max‘: Decimal(‘234.000‘)},
# {‘author__name‘: ‘吕不韦‘,‘price__max‘: Decimal(‘234.000‘)},
# {‘author__name‘: ‘姜子牙‘, ‘price__max‘: Decimal(‘123.000‘)},
# ] >
普通跨表查询
obj_list=models.Love.objects.all()
for row in obj_list: # for循环10次发送10次数据库查询请求
print(row.b.name)
原理:第一次发送查询请求,每for循环一次也会发送查询请求
select_related
结果为对象,query_set类型的对象都有该方法
原理:select_related查询时主动完成连表形成一张大表,for循环时不用额外发请求
试用场景:节省硬盘空间,数据量少的时候适用,相当于做了一次数据库查询;
obj_list=models.Love.objects.all().select_related(‘b‘) # 查询时关联b表
for row in obj_list:
print(row.b.name)
prefetch_related:
结果为对象
原理:select_related虽好,但是做连表操作依然会影响查询性能,prefetch_related不做连表,多次单表查询外键表,去重之后显示,2次单表查询(有N个外键做1+N次单表查询)
适用场景:效率高,数据量大的时候使用
obj_list=models.Love.objects.all().prefetch_related(‘b‘)
for obj in obj_list:
print(obj.b.name)
update()和对象.save()修改方式的性能PK
# 方式1
models.Book.objects.filter(id=1).update(price=3)
# 执行结果
(0.000) BEGIN; args=None
(0.000) UPDATE "app01_book" SET "price" = ‘3.000‘ WHERE "app01_book"."id" = 1; args=(‘3.000‘, 1)
# 方式2
book_obj=models.Book.objects.get(id=1)
book_obj.price=5
book_obj.save()
# 执行结果
(0.000) SELECT "app01_book"."id", "app01_book"."title", "app01_book"."price", "app01_book"."date", "app01_book"."publish_id", "app01_book"."classify_id" FROM "app01_book" WHERE "app01_book"."id" = 1; args=(1,)
(0.000) BEGIN; args=None
(0.000) UPDATE "app01_book" SET "title" = ‘我的奋斗‘, "price" = ‘5.000‘, "date" = ‘1370-09-09‘, "publish_id" = 4, "classify_id" = 3 WHERE "app01_book"."id" = 1; args=(‘我的奋斗‘, ‘5.000‘, ‘1370-09-09‘, 4, 3, 1)
# 结论:
update() 比 obj.save()性能好
Django程序启动后自带的一张表,记录了Django程序的所有APP下model中的表名和所在app的名称
通过ContentType中的app名和表名,查找到Django model中所有表;
from django.contrib.contenttypes.models import ContentType
def test(request):
c = ContentType.objects.get(app_label=‘app01‘,model=‘boy‘)
print(c) -> boy
print(c.model_class()) -> app01.models.Boy
解决 1张表 同时与其他N张表建立外键,并且多个外键中只能选择1个的复杂问题
场景1:现有N种优惠券,每1种优惠券分别对应N门课程中的一门课程,怎么设计表结构呢?
场景2:学生的学习成绩如何奖惩、 作业如何奖惩、学习进度如何奖惩...
# 例:场景1
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
class DegreeCourse(models.Model):
name = models.CharField(max_length=128, unique=True)
# GenericRelation 自动连表查询
xxx = GenericRelation(‘Coupon‘)
class Course(models.Model):
name = models.CharField(max_length=128, unique=True)
class Coupon(models.Model):
"""优惠券生成规则
ID 优惠券名称 content_type_id(表) object_id(表中数据ID)
1 通用 null null
2 满100-10 8 1
3 满200-30 8 2
4 满200-30 9 1
"""
name = models.CharField(max_length=64, verbose_name="活动名称")
# course_type 代指哪张表 注意该字段必须为 content_type
content_type = models.ForeignKey(ContentType,blank=True,null=True)
# 代指对象ID 该字段必须为 object_id
object_id = models.PositiveIntegerField(blank=True, null=True, help_text="可以把优惠券跟课程绑定")
# GenericForeignKey 通过 content_type 直接创建外键关系,不会生成额外的列
content_object = GenericForeignKey(‘content_type‘,‘object_id‘)
# 给学位课1,创建优惠券100
# 方式1:
# 1、在学位课表中 ,找到学位课1
d1 = models.DegreeCourse.objects.get(id=1)
# 2、在ContentType找到学位课表
c1 = ContentType.objects.get(app_label=‘app01‘,model=‘degreecourse‘)
# 3、给学位课1,创建优惠券100
models.Coupon.objects.create(name=‘优惠券‘,brief=‘100‘,content_type=c1,object_id=d1.id)
# 方式2:
d1 = models.DegreeCourse.objects.get(id=1)
models.Coupon.objects.create(name=‘优惠券‘,brief=‘100‘,content_object=d1)
# 查询关联的所有优惠券
d1 = models.DegreeCourse.objects.get(id=1)
print(d1.xxx.all())
v = models.DegreeCourse.objects.values(‘name‘,‘xxx__brief‘,‘xxx__name‘)
print(v)
先到数据库把表删掉:drop table
注释django中对应的Model
执行以下命令:
python manage.py makemigrations
python manage.py migrate --fake -> 只记录变化,不提交数据库操作
去掉注释重新迁移
python manage.py makemigrations
python manage.py migrate
# 把value传给新key并同时删除旧key
row[‘delivery‘] = [row.pop(‘投递‘)]
fields_data = Group._meta.fields
for key in data:
# 这里是将当前的数据转换成数据字典,方便后面修改后提交
data_dict = Group.__dict__
for field in fields_data:
# 这样或输出这条记录的所有字段名,需要的话还可以输出verbose_name
print(field.name)
if field.name == key:
#进行匹配,将前端传来的字段匹配到,然后修改数据库里面的数据
data_dict[key] = data[key]
# 保存数据到数据库,这样的好处就是提高效率,避免过多重复操作
标签:form required fan ... cap const oracl lam uri
原文地址:https://www.cnblogs.com/JeromeLong/p/9875171.html