对数据的操作

元选项

 在模型类中定义类 Meta,用于设置元信息
 元信息db_table:定义数据表名称,推荐使用小写字母,数据表的默认名称
_
 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))

你可能感兴趣的:(对数据的操作)