东莞市盛裕绒艺玩具有限公司

东莞市盛裕绒艺玩具有限公司

利来w66是干嘛的

15232203829
联系方式
全国服务热线: 15232203829

咨询热线:18537849764
联系人:武腾
地址:浙江嘉兴丁桥镇万新村4组

Django - ORM操作

来源:利来w66是干嘛的   发布时间:2019-11-05   点击量:69

目录

ORM介绍创建ORM类增删改查进阶查询类的字段和参数ORM连表的几种类型ORM连表操作浅谈ORM查询性能Django自带ContentType表其他小技巧参考博客

ORM介绍

ORM的两种方式

db first 先连接数据库 -> ...code first 先创建类 -> sqlachemy、Django、大多数都是

Django ORM

ORM:Object Relational Mapping(关系对象映射)

类名 ->> 数据库中的表名类属性 ->> 数据库里的字段类实例 ->> 数据库表里的一行数据obj.name..... ->> 类实例对象的属性

Django orm的优势:Django的orm操作本质上会根据对接的数据库引擎,翻译成对应的sql语句;所有使用Django开发的项目无需关心程序底层使用的是MySQL、Oracle、sqlite....,如果数据库迁移,只需要更换Django的数据库引擎即可

QuerySet数据类型介绍

QuerySet特点:

可迭代的

可切片

惰性计算:等于一个生成器,.objects.all()或者.filter()等都只是返回了一个QuerySet的查询结果集对象,它并不会马上执行sql,而是当调用QuerySet的时候才执行。

缓存机制:每一次数据库查询结果QuerySet都会对应一块缓存,再次使用该QuerySet时,不会发生新的SQL操作

这样减小了频繁操作数据库给数据库带来的压力

但是有时候取出来的数据量太大会撑爆缓存,可以使用迭代器解决这个问题:

models.Publish.objects.all().iterator()

创建ORM类

1. 在models里创建表的类

/app/models.pyfrom django.db import models# 表名为app01_userinfoclass UserInfo(models.Model): # 自动创建id列,自增,主键 # 列名,字符串类型,指定长度 username = models.CharField(max_length=32) password = models.CharField(max_length=64) email = models.EmailField(max_length=19)

类的字段和参数详见字段和参数

2. 注册APP

/./settings.pyINSTALLED_APPS = [ ..., "app01",]

3. 执行命令,每次更改表结构都要重复一遍

python manage.py makemigrations -> 生成表结构的缓存python manage.py migrate -> 创建表结构

4. 默认使用sqlite3数据库,可修改为mysql

/./settings.py -> DATABASES********** 注意 ***********Django默认使用MySQLdb模块链接MySQL主动修改为pymysql,在project同名文件夹下的__init__文件中添加如下代码即可: import pymysql pymysql.install_as_MySQLdb()

增删改查

1.增

/app/views.pyfrom app01 import modelsdef 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()

2.查

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

3.删

models.UserInfo.objects.filter(username="alex").delete()

4.改

models.UserInfo.objects.filter(id=3).update(password="69") # 可添加**kwargs形式# 或者先查找对象再修改保存 obj = models.tb.objects.get(id=1) obj.c1 = "111" obj.save() # 修改单条数据

特殊的判断语句(神奇的双下划线1)

# 大于小于 .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_112233d+", message="又错误了", code="c2"), EmailValidator(message="又错误了", code="c3"), ]

更多错误信息的使用方法参考武沛齐 - FORM

创建 Django admin用户: python manage.py createsuperuser

Meta元信息

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/

Admin拓展知识

    触发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)

ORM连表的几种类型

ORM一对多

当一张表中创建一行数据时,有一个单选的下拉框(可以被重复选择)

创建表结构时关联外键

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

ORM多对多

在某表中创建一行数据是,有一个可以多选的下拉框

两种创建方式

以下两种创建方式建议都用,自动创建的只能关联两个表,自定义的可以不断关联

方式一:自定义关系表

可以直接操作第三张表,但无法通过字段跨表查询,查询麻烦

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()

ORM一对一

在某表中创建一行数据时,有一个单选的下拉框(下拉框中的内容被用过一次就消失了)

例如:原有含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)

ORM连表操作

字段参数

一对多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, -> 删除关联表中的数据时,当前表与其关联的行的行为

跨表查询(神奇的双下划线2)

获取值时使用 . 连接

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,表名小写_setuser_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(),保留了_setrelatedname -> 反向查找时用 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")}, # ] >

浅谈ORM查询性能

    普通跨表查询

    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自带ContentType表

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

字典key替换

# 把value传给新key并同时删除旧keyrow["delivery"] = [row.pop("投递")]

获取字段名和verbose_name

fields_data = Group._meta.fieldsfor 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]# 保存数据到数据库,这样的好处就是提高效率,避免过多重复操作


参考博客

ORM详细讲解武沛齐的博客 - Django

相关产品

COPYRIGHTS©2017 利来w66是干嘛的 ALL RIGHTS RESERVED 备案号:69