Django 的 orm 和 数据库问题

2018-06-20  本文已影响0人  vckah

常用方法

单表查询

from models import Book
# Books 数据中 3 < id < 7 的数据
Book.objects.filter(id__lt=7, id__gt=3)
# Books 数据中 id 等于 [12, 34, 65] 的数据
Book.objects.filter(id__in=[12, 34, 65])
# Books 数据中 id 不等于 [12, 34, 65] 的数据
Book.objects.exclude(id__in=[12, 34, 65])
# Books 数据中 id 在 10-23 的数据,等价于 between and
Books.objects.filter(id__range=[10, 23]) 
# Books 数据中 name 包含 'test' 的数据
# icontains 表示大小写不敏感,一般用于英文 
Book.objects.exclude(name__contains='test')
# 关于字符串还有
startswith,istartswith, endswith, iendswith 
# 查找 时间字段
Book.objects.filter(created_time__year=1998)
# 还包括 __month __day 

外键查找

正向查找 .属性即可找到相关的对象
反向查找 obj.表名set 查到的是对象,若要查找属性 小写表名_属性

如果在外键中设置了 related_name = "<name>",那么直接可以使用此 name。用来代替 <表名>_set。注:一对一反向查询的时候不需要使用 _set,因为只可能取到一个对象。

注意只有得到的是一个 QuerySet 对象时才能 values,values_list。如果得到的是一个具体对象,则只能查看其属性。
基于对象查找时使用 _set,在 sql 中对应子查询,就是两条 sql 语句。一般是多条 orm 语句,对象。
基于 QuerySet 查询的时候,不用加 set,采用双下划线,在 sql 中类似于 join 操作。查询出来的 queryset 对象有一个属性 query 查看对应的 sql 语句。一般是一条 orm 语句,后面常跟 values()

多对多

正向查找和外键查找类似
例子:作者和书 多对多 关系

# 通过作者创建一本书
author_obj.books.create()
还有 .add()
添加多个的时候需要使用 * 号表达式,还可以直接添加 id
set() 更新对象  remove 删除关联的对象
clear()  删除关联的所有对象

聚合查询和分组查询

例子,一个 Book 的表,现在要求它的平均价格
ret = Books.objects.all().aggregate(price_avg=Avg("price"))
sql 语句:select avg(price) as price__avg from book
sql:
select Count(1) from xxx group by field
orm: 
 models.xxx.objects.values('field').annotate(Count('id'))

F 和 Q()

对两个字段的值做比较可以使用 F()
Django 支持 F() 对象和常数之间的数学操作,修改 char 字段时,可以使用 from django.db.models.functions import Concat
如果要执行 or 操作,可以使用 Q() 查询

事务

from django.db import transaction

try:
    from django.db import transaction
    with transaction.atomic():
        pass
except Exception as e:
    print(str(e))

ManyToMany 的特点

当在一个模型中写 ManyToMany 时,Django 会自动创建第三张表。
当然也可以自己创建第三张表,创建一个新模型里面写两个外键即可,不过这样取数据的时候比较麻烦,因为要显示地通过第三张表来查询。
还有一种方法就是在自己创建的第三张表时使用 ManyToMany。可以在模型的 ManyToMany() 属性中设置 through=<你要通过哪张表关联>,through_fields=(,)。自己创建第三张表时,需要指定一个联合唯一索引,但是这样会失去 ORM 封装的部分特性例如 add 和 remove 方法。联合唯一索引例如

class Meta:
    unique_together = ("字段名", "字段名")

如果第三张表没有额外的字段,就用 Django 默认提供的,如果又额外的字段,则可以自己建表。

其他

创建好一个 obj 的列表之后就可以进行
models.A.objects.bulk_create(obj_list)

Django 还有另外一种表结构 contenttype
主要用来一张表同时和多张表关联。
例如:如果现在有一张普通课程表,但是还有一张vip课程表。如果要做价格策略,可以按照整个课程做,也可以按照 vi p卖,这样策略必然不同。可以在策略表中添加两个字段:一个是课程,一个是vip,对应的里面填写课程/vip课程的 id,否则填 0 即可。但这样在后期需要添加另一张表需要和价格策略做匹配的时候,还需要添加字段,不方便。Django 提供了在表中添加表名字段的方法,即表名称和 id。

数据库

Django 可以配置多个数据库,借此实现读写分离
settings.py 中设置 DATABASES = {},拷贝上一份即可,改动某些参数。
然后再执行 python manage.py migrate 的时候,后面可以跟上参数,以指定保存的数据库,--database 数据库名称
在查询时,使用 .using(db_name) 来查询,当然了也可以提前指定,新建脚本 myrouter.py

class Router:
    def db_for_read(self, model, **hints):
        return db_name
    def db_for_write(self, model, **hints):
        return 'default'

settings.py 中指定 DATABASE_ROUTERS = ['myrouter.Router',]
当然了,也可以指定 app。

class Router:
    def db_for_read(self, model, **hints):
        if model._meta.app_label == 'app01':
            return 'db1'
        if model._meta.app_label == 'app02':
            return 'db2'

    def db_for_write(self, model, **hints):
       if model._meta.app_label == 'app01':
            return 'db1'
       if model._meta.app_label == 'app02':
            return 'db2'

详情见官网文档,顺便说一句,Django 的文档是真的好。

上一篇下一篇

猜你喜欢

热点阅读