django之ORM数据库操作
自己没有记住的一点小知识(ORM查询相关)
django之数据库表的单表查询
django之跨表查询及添加记录
关于查询知识点总结
一、细的总结
-
Save()
基本方法:object.save()
save顾名思义是保存的意思,在django中既可以进行新增也可以进行修改操作。具体判定的算法如下:-
如果对象的主键属性为一个求值为
True
的值(例如,非None值或非空字符串),Django将执行UPDATE。 -
如果对象的主键属性没有设置或者
UPDATE
没有更新任何记录,Django
将执行INSERT
。
Save函数可跟参数如下:
Model.save([force_insert=False, force_update=False, using=DEFAULT_DB_ALIAS, update_fields=None])
高级方法:重写
Save()
重写的方式是覆盖模型的方法-
添加其他操作
defsave(self,*args,**kwargs): do_something() super(YourModel, self).save(*args,**kwargs) # Call the "real" save() method. do_something_else()
-
添加判断条件
defsave(self,*args,**kwargs): ifself.name =="Yoko Ono's blog": return # Yoko shall never have her own blog! else: super(YourModel, self).save(*args,**kwargs) # Call the "real" save() method.
注意:批量操作中被覆盖的模型方法不会被调用
-
-
返回新的查询集的方法
filter
filter(**kwargs)
:返回一个新的QuerySet
,包含与给定的查询参数匹配的对象。其中查找的参数(**kwargs)
应该满足字段查找中的格式。在底层的SQL
语句中,多个参数通过AND
连接。exclude
返回一个新的QuerySet
,它包含不满足给定的查找参数的对象。在底层的SQL
语句中,多个参数通过AND连接,然后所有的内容放入NOT()
中。例如:
Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3), headline='Hello')
等价于SQL:
SELECT ... WHERE NOT (pub_date > '2005-1-3' AND headline = 'Hello')
不过它的严格写法是:
Entry.objects.exclude(pub_date__gt=datetime.date(2005,1,3)).exclude(headline='Hello')
等价于SQL:
SELECT ... WHERE NOT pub_date > '2005-1-3' AND NOT headline = 'Hello'
Annotate
使用提供的查询表达式Annotate 查询集中的每个对象。查询表达式可以是一个简单的值、模型(或关联模型)字段的一个引用或对查询集中的对象一个聚合函数(平均值、和等)。例如,如果你正在操作一个Blog列表,你可能想知道每个Blog有多少Entry:
>>> fromdjango.db.models importCount >>> q= Blog.objects.annotate(Count('entry')) # The name of the first blog >>> q[0].name 'Blogasaurus' # The number of entries on the first blog >>> q[0].entry__count 42
order_by
order_by(*fields):默认情况下,QuerySet根据模型Meta类的ordering选项排序。你可以使用order_by方法给每个QuerySet指定特定的排序。默认情况下,QuerySet 根据模型Meta类的ordering选项排序。你可以使用order_by方法给每个QuerySet指定特定的排序。
例如:
Entry.objects.filter(pub_date__year=2005).order_by('-pub_date', 'headline')
上面的结果将按照pub_date 降序排序,然后再按照headline升序排序。"
-pub_date
"前面的负号表示降序排序若要按照另外一个模型中的字段排序,可以使用查询关联模型时的语法。即通过字段的名称后面跟上两个下划线
(__)
,再跟上新模型中的字段的名称,直至你希望连接的模型。例如:Entry.objects.order_by('blog__name', 'headline')
reverse
reverse()
方法反向排序QuerySet
中返回的元素。第二次调用reverse()将恢复到原有的排序。如要获取
QuerySet
中最后五个元素,你可以这样做:my_queryset.reverse()[:5]
注意,这与
Python
中从一个序列的末尾进行切片有点不一样。上面的例子将首先返回最后一个元素,然后是倒数第二个元素,以此类推。如果我们有一个Python
序列,当我们查看seq[-5:]
时,我们将一下子得到倒数五个元素。Django
不支持这种访问模型(从末尾进行切片),因为它不可能利用SQL
高效地实现。同时还要注意,
reverse()
应该只在一个已经定义排序的QuerySet
上调用(例如,在一个定义了默认排序的模型上,或者使用order_by()
的时候)。如果QuerySet
没有定义排序,调用reverse()
将不会有任何效果(在调用reverse()
之前没有定义排序,那么调用之后仍保持没有定义)。distinct
返回一个在SQL
查询中使用SELECT DISTINCT
的新QuerySet
。它将去除查询结果中重复的行。values
返回一个ValuesQuerySet ——QuerySet
的一个子类,迭代时返回字典而不是模型实例对象。每个字典表示一个对象,键对应于模型对象的属性名称。
下面的例子将
values()
与普通的模型对象进行比较:# This list contains a Blog object. >>> Blog.objects.filter(name__startswith='Beatles') [<Blog: Beatles Blog>] # This list contains a dictionary. >>> Blog.objects.filter(name__startswith='Beatles').values() [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]
-
不返回查询集的方法
create
create(**kwargs)
是一个在一步操作中同时创建对象并且保存的便捷方法.所以:p = Person.objects.create(first_name="Bruce", last_name="Springsteen")
和:
p = Person(first_name="Bruce", last_name="Springsteen") p.save(force_insert=True)
是等同的.
get_or_create
一个通过给出的kwargs
来查询对象的便捷方法(如果你的模型中的所有字段都有默认值,可以为空),需要的话创建一个对象。返回一个由
(object, created)
组成的元组,元组中的object
是一个查询到的或者是被创建的对象,created
是一个表示是否创建了新的对象的布尔值。这主要用作样板代码的一种快捷方式。例如:
try: obj = Person.objects.get(first_name='John', last_name='Lennon') except Person.DoesNotExist: obj = Person(first_name='John', last_name='Lennon', birthday=date(1940, 10, 9)) obj.save()
如果模型的字段数量较大的话,这种模式就变的非常不易用了。上面的示例可以用
get_or_create()
重写:obj,created=Person.objects.get_or_create(first_name='John',last_name='Lennon',defaults={'birthday': date(1940, 10, 9)})
count()
返回在数据库中对应的QuerySet
.对象的个数。count()
永远不会引发异常。例如:
# 返回数据库中条目的总数。 Entry.objects.count() #返回标题包含“Lennon”的条目数量 Entry.objects.filter(headline__contains='Lennon').count() latest latest(field_name=None)
通过实践返回表中最近一条记录,使用表中字段名作为查询的日期字段
下面这个例子返回
Entry
表中按pub_date
字段排序的最新的一条记录Entry.objects.latest('pub_date')
earliest
earliest(field_name=None)
工作方式和上面的
latest
相同,只是取得的值相反first
first()
返回结果集的第一个对象, 当没有找到时返回
None
.如果QuerySet
没有设置排序,则将会自动按主键进行排序例子:
p = Article.objects.order_by('title', 'pub_date').first()
说明:
first()
是一个简便方法 下面这个例子和上面的代码效果是一样try: p = Article.objects.order_by('title', 'pub_date')[0] except IndexError: p = None
last
last()工作方式类似
first()
,只是返回的是查询集中最后一个对象。exists
exists()如果
QuerySet
包含任何结果,则返回True,否则返回False
。它会试图用最简单和最快的方法完成查询,但它执行的方法与普通的QuerySet查询确实几乎相同。exists()
用于搜寻对象是否在QuerySet
中以及QuerySet
是否存在任何对象,特别是QuerySet
比较大的时候。查找具有唯一性字段(例如
primary_key
)的模型是否在一个QuerySet中的最高效的方法是:entry = Entry.objects.get(pk=123) if some_queryset.filter(pk=entry.pk).exists(): print("Entry contained in queryset") update update(**kwargs)
为特定的字段执行
SQL
更新查询,然后返回受影响的行数。例如,将2010年发布的所有
blog
下entry
中的评论关了,可以执行下面操作>>> Entry.objects.filter(pub_date__year=2010).update(comments_on=False) delete delete()
执行
SQL
删除时将直接删除设定数据集中的所有记录。例如, 删除主键为
1
的blog
下的所有entries:b = Blog.objects.get(pk=1) # Delete all the entries belonging to this Blog. >>> Entry.objects.filter(blog=b).delete()
-
字段查找
exact、iexact
exact
:精确匹配。区分大小写例如:
Entry.objects.get(id__exact=14) Entry.objects.get(id__exact=None) iexact:不区分大小写的精确匹配
例如:
Blog.objects.get(name__iexact='beatles blog') Blog.objects.get(name__iexact=None) contains、icontains contains:包含,大小写敏感
例如:
Entry.objects.get(headline__contains='Lennon') icontains:包含,大小写不明感.
例如:
Entry.objects.get(headline__icontains='Lennon') in 在一个给定的列表中. Example: Entry.objects.filter(id__in=[1, 3, 4])
gt、gte、lt、lte
gt
:大于例子:
Entry.objects.filter(id__gt=4)
Gte
:大于或等于Lt
:小于Lte
:小于或等于startswith、istartswith、endswith、iendswith
startswith
:区分大小写,开始位置匹配例如:
Entry.objects.filter(headline__startswith='Will') istartswith:不区分大小写,开始位置匹配 endswith:区分大小写,结束位置匹配 iendswith:不区分大小写,结束位置匹配
range
范围例如:
import datetime start_date = datetime.date(2005, 1, 1) end_date = datetime.date(2005, 3, 31) Entry.objects.filter(pub_date__range=(start_date, end_date))
等价
SQL
:SELECT ... WHERE pub_date BETWEEN '2005-01-01' and '2005-03-31';
year、month、day
year
: 返回精确的年份例如:
Entry.objects.filter(pub_date__year=2005)
等价SQL:
SELECT ... WHERE pub_date BETWEEN '2005-01-01' AND '2005-12-31';
month
: 对于月份时间字段,匹配一个整数从1 (January)
到12 (December).
day
: 对于日期和日期时间字段,具体到某一天的匹配。取一个整数的天数。isnull
值为True
或False
, 相当于SQL
语句IS NULL
和IS NOT NULL.
例如:
Entry.objects.filter(pub_date__isnull=True)
等价
SQL
:SELECT ... WHERE pub_date IS NULL;
-
常见聚合函数
Avg:
class Avg(expression, output_field=None, **extra)
返回给定
expression
的平均值,其中expression
必须为数值。默认的别名:
<field>__avg
返回类型:
float
Count:
class Count(expression, distinct=False, **extra)
返回与
expression
相关的对象的个数。默认的别名:
<field>__count
返回类型:
int
有一个可选的参数:
distinct:
如果distinct=True
,Count
将只计算唯一的实例。它等同于COUNT(DISTINCT <field>)
SQL
语句。默认值为False
。Max:
class Max(expression, output_field=None, **extra)
返回
expression
的最大值。默认的别名:
<field>__max
返回类型:与输入字段的类型相同,如果提供则为 output_field 类型
Min:
class Min(expression, output_field=None, **extra)
返回
expression
的最小值。默认的别名:
<field>__min
返回的类型:与输入字段的类型相同,如果提供则为 output_field类型
StdDev:
class StdDev(expression, sample=False, **extra)
返回
expression
的标准差。默认的别名:
<field>__stddev
返回类型:
float
有一个可选的参数:
sample
:默认情况下,
StdDev
返回群体的标准差。但是,如果sample=True
,返回的值将是样本的标准差。Sum:
class Sum(expression, output_field=None, **extra)
计算
expression
的所有值的和。默认的别名:
<field>__sum
返回类型:与输入的字段相同,如果提供则为
output_field
的类型Variance
class Variance(expression, sample=False, **extra)
返回
expression
的方差。默认的别名:
<field>__variance
返回的类型:
float
有一个可选的参数:
sample
二、通过ORM写偏原生SQL:
-
extra
Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,)) Entry.objects.extra(where=['headline=%s'], params=['Lennon']) Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"]) Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid'])
-
raw
# 执行原生SQLmodels.UserInfo.objects.raw('select * from userinfo') # 如果SQL是其他表时,必须将名字设置为当前UserInfo对象的主键列名 models.UserInfo.objects.raw('select id as nid from 其他表') # 为原生SQL设置参数 models.UserInfo.objects.raw('select id as nid from userinfo where nid>%s', params=[12,]) name_map = {'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'} Person.objects.raw('SELECT * FROM some_other_table', translations=name_map)
-
原生SQL
from django.db import connection, connections cursor = connection.cursor() # cursor = connections['default'].cursor() cursor.execute("""SELECT * from auth_user where id = %s""", [1]) row = cursor.fetchone() # fetchall()/fetchmany(..)
PS: 选择数据库
queryset = models.Course.objects.using('default').all()