Django - 模型层 - 查询操作 - 1

为查询创建一个博客应用模型

from django.db import models

class Blog(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.TextField()

    def __str__(self):
        return self.name

class Author(models.Model):
    name = models.CharField(max_length=200)
    email = models.EmailField()

    def __str__(self):
        return self.name

class Entry(models.Model):
    blog = models.ForeignKey(Blog, on_delete=models.CASCADE)
    headline = models.CharField(max_length=255)
    body_text = models.TextField()
    pub_date = models.DateField()
    mod_date = models.DateField()
    authors = models.ManyToManyField(Author)
    number_of_comments = models.IntegerField()
    number_of_pingbacks = models.IntegerField()
    rating = models.IntegerField()

    def __str__(self):
        return self.headline

创建对象

>>> from myapp.models import Blog
>>> b = Blog(name='Beatles Blog', tagline='All the latest Beatles news.')
>>> b.save()

上面的代码会执行一条SQL的INSERT语句. 如果不调用save()方法, Django不会立刻执行该操作.

提示 :
在代码或者shell中使用API的方式直接创建模型实例是不会引发数据验证的.

上面的diam可以简写为 :

b = Blog.objects.create(name='Beatles Blog', tagline='All the latest Beatles news.')

修改对象并保存

使用save()方法, 保存对象数据库已有对象的修改, 例如如果已经存在b对象在数据库内 :

>>> b.name = 'New name'
>>> b.save()

在后台会运行一条SQL的UPDATE语句.

可以重新编写save方法, 添加其他的业务逻辑

from django.db import models

class Blog(models.Model):
	name = models.CharField(lmax_length=100)
	tagline = models.TextField()
	
	def save(self, *args, **kwargs):
		do_something() #保存前添加其他的业务逻辑
		super().save(*args, **kwargs)
		do_something_else() # 保存后再添加其他的业务逻辑

super().save(*args, **kwargs) 这行确保了Django源码中关于save方法的代码依然会被执行

模型实例保存的注意事项

  • 执行save()方法后, Django才会真正为对象设置自增主键的值.
>>> b1 = Blog(name='laowang', tagline='kkkkkk')
>>> b1.id  # 返回None
>>> b1.save()
>>> b1.id 
>>> 2
  • 也可以自己指定主键的值, 要确保自己指定的主键值是没有被使用过的
>>> b2 = Blog(id=4, name='xiaoming', tagline='ggggg')
>>> b2.save()
>>> b2.id
4
  • 有时候必须自己强制进行INSERT或者UPDATE操作, 而不是让Django自动决定
  • 数据冲突的问题, 使用F表达式
>>> from django.db.models import F
>>> entry = Entry.objects.get(name='laowang')
>>> entry.number_of_pingbacks = F('number_of_pingbacks') + 1
>>> entry.save()
  • save方法的最后一个参数是update_fields, 它用于指定你要对模型的那些字段进行更新.
>>> blog.name = 'name'
>>> blog.save(update_fields=['name'])

保存外键和多对多字段

>>> from myapp.models import Blog, Entry
>>> blog = Blog.objects.get(pk=1)
>>> entry = Entry.objects.create(blog=blog, headline='laowang blog', body_text='hhhhhhh', number_of_comments=1, number_of_pingbacks=1,rating=1)

这里有一个blog的实例, 把blog的实例作为值赋给了entry的blog属性

多对多字段的保存

多对多字段的保存需要调用一个add()方法

>>> from myapp.models import Author
>>> joe = Author.objects.create(name="joe")
>>> entry = Entry.objects.get(pk=1)
>>> entry.authors.add(joe)

在一行语句内, 可以同时添加多个对象到多对多的字段

>>> john = Author.objects.create(name="John")
>>> paul = Author.objects.create(name="Paul")
>>> george = Author.objects.create(name="George")
>>> ringo = Author.objects.create(name="Ringo")
>>> entry.authors.add(john, paul, george, ringo)

检索对象

  • 从数据库检索对象, 需要基于模型类, 通过管理器操作数据库并返回一个查询结果集(QuerySet)

检索所有对象

使用all()方法

>>> all_entries = Entry.objects.all()
>>> all_entries
<QuerySet [<Entry: laowang blog>]>

过滤对象

  • filter(**kwargs) : 返回一个根据指定参数查询出来的QuerySet
  • exclude(**kwargs) : 返回除了根据指定参数查询出来结果的QuerySet

例如 : 获取2020年的所有文章

>>> Entry.objects.filter(pub_date__year=2020)
<QuerySet [<Entry: laowang blog>]>

QuerySets都是懒惰的

一个创建QuerySets的动作不会立刻导致任何的数据库行为.

>>> q = Entry.objects.filter(headline__startswith="laowang")
>>> q = q.filter(pub_date__lte=datetime.date.today())
>>> q = q.exclude(body_text__icontains='aa')
>>> print(q)
<QuerySet [<Entry: laowang blog>]>

上面的代码, 在print语句执行时才会访问一次数据库.

检索单一对象

使用get()方法检索会获得一个对象

>>> one_entry = Entry.objects.get(pk=1)
  • 如果在查询时没有匹配到对象, get()方法将抛出DoesNotExist异常
  • 如果查询结果超过1个, 则会抛出MultipleObjectsReturned

QuerySet的切片

>>> Entry.objects.all()[:5]  # 获取前5个对象
>>> Entry.objects.all()[5:10]  # 获取第6个到第10个对象

注意 : 不支持负索引

  • 通常情况, 切片操作会返回一个新的QuerySet, 并且不会被立刻执行. 有一个例外, 那就是指定步长的时候, 查询操作会立刻在数据库内执行
>>> Entry.objects.all()[:10:2]
[<Entry: laowang blog>]
  • 若要获取单一的对象可以使用索引
>>> Entry.objects.order_by('headline')[0]

字段查询

基本格式为 : field__lookuptype=value
例如 :

>>> Entry.objects.filter(pub_date__lte='2021-01-01')

查询外键字段需要在其后面添加一个 _id

>>> Entry.objects.filter(blog_id=1)
<QuerySet [<Entry: laowang blog>]>

查询类型

exact

默认类型. 不提供查询类型, 或者关键字参数不包含一个双下划线, 那么查询类型就是默认的exact.

iexact

不区分大小写的查询

# 匹配"LaoWang", "LAOWANG" 等.
>>> Blog.objects.get(name__iexact="laowang")

contains

包含类型的匹配, 区分大小写

>>> Entry.objects.get(headline__contains='lao')
# 相当于
# select ... where headline like '%lao%';

icontains

contains的大小写不敏感模式

startswith和endswith

以什么开头和以什么结果

istartswith和iendswith

不区分大小写的模式

in

在给定的列表里查找

>>> Entry.objects.filter(id__in=[1, 2, 3])

还可以使用动态查询集

>>> blog_name = Blog.objects.filter(name__contains='Beatles Blog')
>>> entries = Entry.objects.filter(blog__in=blog_name)
>>> print(entries)

gt

大于

get

大于或等于

lt

小于

lte

小于或等于

range

查询的范围

>>> start_date = datetime.date(2020,12,31)
>>> end_date = datetime.date(2021,1,2)
>>> Entry.objects.filter(pub_date__range=(start_date, end_date))
<QuerySet [<Entry: laowang blog>]>

date

进行日期对比

Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))

year

对年份进行匹配

Entry.objects.filter(pub_date__year=2021)

month

对月份进行匹配

Entry.objects.filter(pub_date__month=12)

day

对具体到某一天的匹配

week_day

进行星期几的匹配

>>> Entry.objects.filter(pub_date__week_day=6)
<QuerySet [<Entry: laowang blog>]>

iso_week_day

以ISO8601标准确定的星期几.

>>> Entry.objects.filter(pub_date__iso_week_day=6)

quarter

季度, 取值范围1-4

>>> Entry.objects.filter(pub_date__quarter=2)

time

将字段的值转为datetime.time格式并进行对比

hour

对小时进行匹配。 取0和23之间的整数。

minute

对分钟匹配。取0和59之间的整数。

second

对秒数进行匹配。取0和59之间的整数。

regex

区分大小写的正则表达式匹配。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值