对数据的操作

元选项

 在模型类中定义类 Meta,用于设置元信息
 元信息db_table:定义数据表名称,推荐使用小写字母,数据表的默认名称
<app_name>_<model_name>
 ordering:对象的默认排序字段,获取对象的列表时使用,接收属性构成的列表

加入一个内部类类 来改变默认排序

class BookInfo(models.Model):
...
class Meta():
ordering = ['id']
 字符串前加-表示倒序,不加-表示正序
class BookInfo(models.Model):
...
class Meta():
ordering = ['-id']
排序会增加数据库的开销

   # 改变排序顺序
   class Meta():
       ordering = ['-id']
管理器Manager

管理器是Django 的模型进行数据库的查询操作的接口,用于与数据库进行交互,Django
应用的每个模型都拥有至少一个管理器
当定义模型类时没有指定管理器,则 Django 会为模型类提供一个名为 objects 的管理器

1:显式定义管理器

 继承 models.Manager
 自定义管理器类主要用于两种情况
情况一:向管理器类中添加额外的方法:见下面“创建对象”中的方式二
情况二:修改管理器返回的原始查询集:重写get_queryset()方法
当为模型类指定管理器后,django 不再为模型类生成名为 objects 的默认管理器
class BookInfoManager(models.Manager):
def get_queryset(self):
return super(BookInfoManager, self).get_queryset().filter(isDelete=False)
class BookInfo(models.Model):
...
books = BookInfoManager()
模型对象创建
方式一:在模型类中增加一个类方法
class BookInfo(models.Model):
...
@classmethod
def create(cls, title, pub_date):
book = cls(btitle=title, bpub_date=pub_date)
book.bread=0
book.bcommet=0
book.isDelete = False
return book
引入时间包:from datetime import *
调用:book=BookInfo.create("hello",datetime(1980,10,11));
保存:book.save()
方式二:在自定义管理器中添加一个方法
在管理器的方法中,可以通过 self.model 来得到它所属的模型类
class BookInfoManager(models.Manager):
def create_book(self, title, pub_date):
book = self.model()
book.btitle = title
book.bpub_date = pub_date
book.bread=0
book.bcommet=0
book.isDelete = False
return book
调用:book=BookInfo.books.create_book("abc",datetime(1980,1,1))
保存:book.save()

模型方法

 str (self):重写object方法,此方法在将对象转换成字符串时会被调用
 save():将模型对象保存到数据表中
 delete():将模型对象从数据表中删除
查询
查询集表示从数据库中获取的对象集合
返回查询集的方法,称为过滤器
过滤器基于所给的参数限制查询的结果
从Sql的角度,查询集和select语句等价,过滤器像where和limit子句
查询集是可迭代的对象

from django.db import models

# Create your models here.


class BookInfoManger(models.Manager):
    def get_queryset(self):
        return super(BookInfoManger, self).get_queryset().filter()

    def create_book(self,title,pub_date):
        book = self.model()
        book.btitle = title
        book.bpub_date = pub_date
        return book


class BookInfo(models.Model):
    btitle = models.CharField(max_length=20)
    bpub_date = models.DateTimeField()

    # 装饰器类方法
    # 重写类的创建方法
    @classmethod
    def create(cls,title,pub_date):
        book = cls(btitle=title,bpub_date=pub_date)
        return book

    def __str__(self):
        return "%d--%s--%s" % (self.pk, self.btitle, self.bpub_date)

    # 改变排序顺序
    class Meta():
        ordering = ['-id']

    books = BookInfoManger()


class HeroInfo(models.Model):
    hname = models.CharField(max_length=20)
    hcontent = models.CharField(max_length=100)
    hgender = models.BooleanField(default=True)
    hBook = models.ForeignKey("BOOkInfo", on_delete=models.CASCADE)

    def __str__(self):
        return "%d--%s--%s" % (self.pk, self.hname, self.hBook)

    books = BookInfoManger()

过滤器

返回查询集的方法,称为过滤器
all() :检索所有的对象
fileter(**kwargs) :检索特定的对象 返回一个与参数匹配的QuerySet
exclude():返回一个与参数不匹配的QuerySet
order_by("column_name"):检索排序后的对象
column_name:排序的列,默认升序,列名前加- 降序排序
get():返回单个满足条件的对象
如果未找到会引发"模型类.DoesNotExist"异常
如果多条被返回,会引发"模型类.MultipleObjectsReturned"异常
count():返回当前查询的总条数
first():返回第一个对象
last():返回最后一个对象
exists():判断查询集中是否有数据,如果有则返回True

限制查询集

 查询集返回列表,可以使用下标的方式进行限制,等同于 sql 中的limit 和 offset 子句
 注意:不支持负数索引
 使用下标后返回一个新的查询集,不会立即执行查询
 如果获取一个对象,直接使用[0],等同于[0:1].get()
 但是如果没有数据,[0]引发IndexError 异常,[0:1].get()引发DoesNotExist 异常
BookInfo.objects.all()[:5]
查找前5个entry表里的数据
BookInfo.objects.all()[5:10]
查找从第5个到第 10个之间的数据。
BookInfo.objects.all()[:10:2]
查询从第0个开始到第10个,步长为2的数据。

查询集的缓存

 每个查询集都包含一个缓存来最小化对数据库的访问
 首次对查询集求值时,会发生数据库查询,django 会将查询的结果存在查询集的缓存中,
并返回请求的结果,接下来对查询集求值将重用缓存的结果
 情况一:这构成了两个查询集,无法重用缓存,每次查询都会与数据库进行一次交互,
增加了数据库的负载
print([e for e in BookInfo.books.all()])
print([e.btitle+":"+e.bpub_date.strftime("%Y-%m-%d") for e in
BookInfo.books.all()])
 情况二:两次循环使用同一个查询集,第二次使用缓存中的数据
b = BookInfo.books.all()
print([e.btitle for e in b])
print([e.bpub_date.strftime("%Y-%m-%d") for e in b])
何时查询集不会被缓存:当只对查询集的部分进行求值时会检查缓存,但是如
果这部分不在缓存中,那么接下来查询返回的记录将不会被缓存,这意味着使

用索引来限制查询集将不会填充缓存,如果这部分数据已经被缓存,则直接使
用缓存中的数据

条件查询

 实现where 子名,作为方法 filter()、exclude()、get()的参数
 语法:属性名称__比较运算符=值
 表示两个下划线,左侧是属性名称,右侧是比较类型
 对于外键,使用“属性名_id”表示外键的原始值
 转义:like 语句中使用了%与 ,匹配数据中的 % 与 ,在过滤器中直接写,例如:
filter(title__contains="%")=>where title like '%%%',表示查找标题中包含%的

比较运算符

判等exact
 表示判等,大小写敏感;如果没有写“比较运算符”,表示判等
filter(isDelete=False)
范例
BookInfo.books.filter(btitle__exact='射雕英雄传')
BookInfo.books.get(btitle__exact='射雕英雄传')
BookInfo.books.filter(btitle='射雕英雄传')
BookInfo.books.get(btitle='射雕英雄传')
BookInfo.books.get(btitle__exact='射雕英雄传')
包含contains
 是否包含,大小写敏感
范例
BookInfo.books.exclude(btitle__contains='传')
BookInfo.books.filter(btitle__contains='雕')
BookInfo.books.filter(btitle__contains='龙')
BookInfo.books.exclude(btitle__contains='龙')
开头或结尾

startswith、endswith

 以 value 开头或结尾,大小写敏感
BookInfo.books.exclude(btitle__endswith='传')
BookInfo.books.filter(btitle__endswith='传')
BookInfo.books.get(btitle__startswith='倚',btitle__endswith='记')
是否为null
 isnull
BookInfo.books.filter(btitle__isnull=False)

大小写不敏感

 在前面加个i 表示不区分大小写,如 iexact、icontains、istarswith、iendswith,

不连续查询

 in:是否包含在范围内
BookInfo.books.filter(pk__in=[1, 2, 3, 4, 5])
 gt、gte、lt、lte:大于、大于等于、小于、小于等于
BookInfo.books.filter(id__gt=3)

日期时间查询

 year、month、day、week_day、hour、minute、second
 对日期时间类型的属性进行运算
BookInfo.books.filter(bpub_date__year=1980)
BookInfo.books.filter(bpub_date__gt=date(1980, 12, 31))
BookInfo.books.filter(bpub_date__gt=date(1990, 12, 31))
注意
为避免查询 month 和 day 结果为空,请在 setting.py 中设置:
USE_TZ = False

跨关联关系的查询

 处理join 查询
o 语法:模型类名<属性名><比较>
o 注:可以没有__<比较>部分,表示等于,结果同 inner join

o 可反向使用,即在关联的两个模型中都可以使用
BookInfo.books.filter(heroinfo__hcontent__contains='八')
BookInfo.books.filter(heroinfo__hname__contains='靖')
查询的快捷方式:pk
 pk 表示primary key,默认的主键是 id
BookInfo.books.filter(pk__lt=3)
BookInfo.books.filter(id__gt=3)

聚合函数

 使用aggregate()函数返回聚合函数的值
 函数:Avg,Count,Max,Min,Sum
from django.db.models import Max
maxDate = BookInfo.books.all().aggregate(Max('bpub_date'))
 count 的一般用法:
count = BookInfo.books.all().count()

F对象

F()允许Django 在未实际链接数据的情况下具有对数据库字段的值的引用。
场景

Python 操作方式

通常情况下我们在更新数据时需要先从数据库里将原数据取出后方在内存里,然后编辑
某些属性,最后提交。
book = BookInfo.books.get(pk=3)
print(book.bpub_date)
delta = timedelta(days=3)
book.bpub_date = book.bpub_date + delta
book.save()
book = BookInfo.books.get(pk=3)
print(book.bpub_date)
当我们使用了F()之后呢?
book = BookInfo.books.get(pk=3)
print(book.bpub_date)
delta = timedelta(days=3)
book.bpub_date = F('bpub_date') + delta
book.save()

book = BookInfo.books.get(pk=3)
print(book.bpub_date)

结论

当Django程序中出现F()时,Django会使用SQL语句的方式取代标准的Python操作。
上述代码中不管book.bpub_date 的值是什么,Python 都不曾获取过其值,python 做
的唯一的事情就是通过 Django 的 F()函数创建了一条 SQL 语句然后执行而已。
特别是并发的情况,效率也变高了,减少了多线程同时操作带来的隐患。 但是不支持字
符串相加的操作
 可以使用模型的字段 A 与字段 B 进行比较,如果 A写在了等号的左边,则 B 出现在等号
的右边,需要通过 F 对象构造
list.filter(bread__gte=F('bcommet'))
 django 支持对F()对象使用算数运算
list.filter(bread__gte=F('bcommet') * 2)
 F()对象中还可以写作“模型类__列名”进行关联查询
list.filter(isDelete=F('heroinfo__isDelete'))
 对于date/time 字段,可与 timedelta()进行运算

list.filter(bpub_date__lt=F('bpub_date') + timedelta(days=1))

Q对象

 应用场景
 一般我们在 Django 程序中查询数据库操作都是在 QuerySet 里进行进行,例如下面
代码:
 q1 = BookInfo.books.filter(bpub_date__gt=date(1992, 1, 1))
 q2 = q1.exclude(btitle__startswith="笑")
 q3 = q2.filter(bpub_date__year=1992)
 将其组合起来:
 q = BookInfo.books.filter(bpub_date__gt=date(1992, 1,
1)).exclude(btitle__startswith="笑").filter(bpub_date__year=1992)
 问题
 复杂的查询条件,导致查询越来越长。
 引入Q 对象
 Q()对象就是为了将这些条件组合起来。
 当我们在查询的条件中需要组合条件时(例如两个条件“且”或者“或”)时。我们可
以使用Q()查询对象。
 fromdjango.db.modelsimports Q
 Q(bpub_date__gt=date(1992, 1, 1))
 Q(btitle__startswith="笑")
 Q(bpub_date__year=1992)

 &(与)或者|(或)~(非)
 可以将多个 Q()对象组合起来传递给 filter(),exclude(),get()等函数。
 当操作符应用在两个 Q 对象时,会产生一个新的 Q 对象
 结合括号进行分组,构造复杂的 Q 对象
 Q(bpub_date__gt=date(1992, 1, 1)) & ~Q(btitle__startswith="笑") &
Q(bpub_date__year=1992)
 对应SQL 语句可以理解为:
 WHERE bpub_date__gt=date(1992, 1, 1) and not btitle like "笑%" and
year(bpub_date) =1992

 q = BookInfo.books.filter(Q(bpub_date__gt=date(1992, 1, 1)) &
~Q(btitle__startswith="笑") & Q(bpub_date__year=1992))
 改写一下
 c1 = Q(bpub_date__gt=date(1992, 1, 1))
 c2 = Q(btitle__startswith="笑")
 c3 = Q(bpub_date__year=1992)
 q= BookInfo.books.filter(c1 & ~c2 & c3)
 使用~(not)操作符在 Q 对象前表示取反
list.filter(~Q(pk__lt=6))

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,961评论 5 473
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,444评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,009评论 0 333
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,082评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,101评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,271评论 1 278
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,738评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,395评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,539评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,434评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,481评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,160评论 3 317
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,749评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,816评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,038评论 1 256
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,548评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,140评论 2 341