python 与 mysql 相关的记录。
django orm对数据库的操作原理
django models
简介
一个模型(model)是单一的,与数据库相关的数据源。它包含了存储数据必需的字段和行为。一般情况下,每个模型映射一个单独的数据库表。
- 每个模型是 django.db.models.Model 的一个Python子类。
- 该模型的每个属性都代表一个数据库字段。
- 综上,Django给你自动生成数据库的访问API。
- 数据表名
appname_modelnme
是根据模型的元数据生成,但可以进行自定义。
字段类型
1 | from django.db import models |
1 | # -*- coding: utf-8 -*- |
字段选项
1 | # 以下参数对所以字段类型均有效,且是可选的。 |
ForeignKey 示例
1 | class ForeignKey( |
多对一的关系。需要两个位置参数:被关联的类和 on_delete 选项。
如果要创建一个递归关系,一个与其自身有多对一关系的对象,则使用 models.ForeignKey('self', on_delete=models.CASCADE)
。
1 | from django.db import models |
ManyToManyField 示例
1 | class ManyToManyField( |
示例:
1 | from django.db import models |
OneToOneField 示例
1 | class OneToOneField( |
model操作方法
1 | # mysite/blog/models.py |
创建对象
1 | Model.save(force_insert=False, force_update=False, using=DEFAULT_DB_ALIAS, update_fields=None) |
要创建一个对象,用关键字参数初始化它,然后调用 save() 将其存入数据库。
这在幕后执行了 INSERT SQL 语句。Django 在你显式调用 save() 才操作数据库。
save() 方法没有返回值。
1 | >>> from blog.models import Blog |
保存 ForeignKey 字段
本例为 Entry 类的实例 entry 更新了 blog 属性,假设 Entry 和 Blog 的实例均已保存在数据库中(因此能在下面检索它们):
1 | >>> from blog.models import Blog, Entry |
保存 ManyToManyField 字段
在字段上使用 add() 方法为关联关系添加一条记录。本例将 Author 实例 joe 添加至 entry 对象:
1 | >>> from blog.models import Author |
要一次添加多行记录至 ManyToManyField 字段,在一次调用 add() 时传入多个参数,像这样:
1 | >>> john = Author.objects.create(name="John") |
更新对象
1 | >>> from blog.models import Blog |
字段查询
字段查询即你如何制定 SQL WHERE 子句。它们以关键字参数的形式传递给 QuerySet 方法 filter(), exclude() 和 get()。
基本的查询关键字参数遵照 field__lookuptype=value
。(有个双下划线)。例如:
1 | >>> Entry.objects.filter(pub_date__lte='2006-01-01') |
转换为 SQL 语句大致如下:
1 | SELECT * FROM blog_entry WHERE pub_date <= '2006-01-01'; |
exact
精确匹配。如果提供的用于比较的值是None,它将被解释为SQL NULL。
1 | Entry.objects.get(id__exact=14) |
1 | SELECT ... WHERE id = 14; |
iexact
不区分大小写的精确匹配。如果提供的用于比较的值是None,它将被解释为SQL NULL。
1 | Blog.objects.get(name__iexact='beatles blog') |
1 | SELECT ... WHERE name ILIKE 'beatles blog'; |
contains
1 | Entry.objects.get(headline__contains='Lennon') |
1 | SELECT ... WHERE headline LIKE binary '%Lennon%'; |
icontains
1 | Entry.objects.get(headline__icontains='Lennon') |
1 | SELECT ... WHERE headline ILIKE '%Lennon%'; |
in
在给定的迭代中;通常是列表、元组或查询集。
1 | Entry.objects.filter(id__in=[1, 3, 4]) |
1 | SELECT ... WHERE id IN (1, 3, 4); |
也可以使用queryset来动态地评估值列表,而不是提供一个文字值列表:
1 | inner_qs = Blog.objects.filter(name__contains='Cheddar') |
1 | SELECT ... WHERE blog.id IN (SELECT id FROM ... WHERE NAME LIKE '%Cheddar%') |
gt
1 | Entry.objects.filter(id__gt=4) |
1 | SELECT ... WHERE id > 4; |
gte
lt
lte
startswith
1 | Entry.objects.filter(headline__startswith='Lennon') |
1 | SELECT ... WHERE headline LIKE binary 'Lennon%'; |
istartswith
1 | Entry.objects.filter(headline__istartswith='Lennon') |
1 | SELECT ... WHERE headline ILIKE 'Lennon%'; |
endswith
1 | Entry.objects.filter(headline__endswith='Lennon') |
1 | SELECT ... WHERE headline LIKE '%Lennon'; |
iendswith
1 | Entry.objects.filter(headline__iendswith='Lennon') |
1 | SELECT ... WHERE headline LIKE '%Lennon'; |
range
1 | import datetime |
1 | SELECT ... WHERE pub_date BETWEEN '2005-01-01' and '2005-03-31'; |
date
对于datetime字段,将值强制转换为date。允许链接其他字段查找。获取日期值。
1 | Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1)) |
注:当USE_TZ为真时,字段将在过滤前转换为当前时区。这需要在数据库中定义时区。
year
1 | Entry.objects.filter(pub_date__year=2005) |
1 | SELECT ... WHERE pub_date BETWEEN '2005-01-01' AND '2005-12-31'; |
注:当USE_TZ为真时,字段将在过滤前转换为当前时区。这需要在数据库中定义时区。
month
1 | Entry.objects.filter(pub_date__month=12) |
1 | SELECT ... WHERE EXTRACT('month' FROM pub_date) = '12'; |
注:当USE_TZ为真时,字段将在过滤前转换为当前时区。这需要在数据库中定义时区
day
1 | Entry.objects.filter(pub_date__day=3) |
1 | SELECT ... WHERE EXTRACT('day' FROM pub_date) = '3'; |
注:当USE_TZ为真时,字段将在过滤前转换为当前时区。这需要在数据库中定义时区
week
对于date和datetime字段,根据ISO-8601返回周数(1-52或53),即。在美国,一周从周一开始,第一周包含全年的第一个周四。
1 | Entry.objects.filter(pub_date__week=52) |
注:当USE_TZ为真时,字段将在过滤前转换为当前时区。这需要在数据库中定义时区
week_day
对于日期和日期时间字段,“星期几”匹配。允许链接其他字段查找。
获取一个整数值,表示一周的日期从1(星期日)到7(星期六)。
1 | Entry.objects.filter(pub_date__week_day=2) |
quarter
获取一个1到4之间的整数值,表示一年中的季度。
检索第二季度(4月1日至6月30日)条目的示例:
1 | Entry.objects.filter(pub_date__quarter=2) |
time
1 | Entry.objects.filter(pub_date__time=datetime.time(14, 30)) |
hour
取0到23之间的整数。
1 | Event.objects.filter(timestamp__hour=23) |
1 | SELECT ... WHERE EXTRACT('hour' FROM timestamp) = '23'; |
minute
取0到之间59的整数。
1 | Event.objects.filter(timestamp__minute=29) |
1 | SELECT ... WHERE EXTRACT('minute' FROM timestamp) = '29'; |
second
取0到之间59的整数。
1 | Event.objects.filter(timestamp__second=31) |
1 | SELECT ... WHERE EXTRACT('second' FROM timestamp) = '31'; |
isnull
取True或False,分别对应于IS NULL和IS NOT NULL的SQL查询。
1 | Entry.objects.filter(pub_date__isnull=True) |
1 | SELECT ... WHERE pub_date IS NULL; |
regex
1 | Entry.objects.get(title__regex=r'^(An?|The) +') |
1 | SELECT ... WHERE title REGEXP BINARY '^(An?|The) +'; -- MySQL |
iregex
1 | Entry.objects.get(title__iregex=r'^(an?|the) +') |
1 | SELECT ... WHERE title REGEXP '^(an?|the) +'; -- MySQL |
检索对象
要从数据库检索对象,要通过模型类的 Manager 构建一个 QuerySet。
一个 QuerySet 代表来自数据库中对象的一个集合。它可以有 0 个,1 个或者多个 filters. Filters,可以根据给定参数缩小查询结果量。在 SQL 的层面上, QuerySet 对应 SELECT 语句,而filters对应类似 WHERE 或 LIMIT 的限制子句。
你能通过模型的 Manager 获取 QuerySet。每个模型至少有一个 Manager,默认名称是 objects。像这样直接通过模型类使用它:
1 | >>> Blog.objects |
检索全部对象.
1 | >>> all_entries = Entry.objects.all() |
通过过滤器检索指定对象.
filter(\kwargs)** :返回一个新的 QuerySet,包含的对象满足给定查询参数exclude(\kwargs)**: 返回一个新的 QuerySet,包含的对象 不 满足给定查询参数。
例如,要包含获取 2006 年的博客条目(entries blog)的 QuerySet,像这样使用 filter():
1 | Entry.objects.filter(pub_date__year=2006) |
用 get()
检索单个对象
Manager 上使用 get() 方法,它会直接返回这个对象:
1 | 1) one_entry = Entry.objects.get(pk= |
如果没有满足查询条件的结果, get() 会抛出一个 DoesNotExist 异常。
有不止一个记录满足 get() 查询条件时发出警告。这时会抛出MultipleObjectsReturned
QuerySet API
class QuerySet(model=None,query=None,using=None,hints=None)**[源代码]
filter(**kwargs)
exclude(**kwargs)
annotate(args, *kwargs)
1 | from django.db.models import Count |
1 | 'entry')) q = Blog.objects.annotate(number_of_entries=Count( |
order_by(*fields)
默认情况下,查询集返回的结果按照模型元数据中的排序选项给出的排序元组进行排序。您可以使用order_by方法在每个查询集的基础上覆盖它。
1 | Entry.objects.filter(pub_date__year=2005).order_by('-pub_date', 'headline') |
reverse()
distinct(*fields)
默认情况下,查询集不会消除重复行。实际上,这很少出现问题,因为像blog .object .all()这样的简单查询没有引入重复结果行的可能性。但是,如果查询跨越多个表,那么在计算一个查询集时可能会得到重复的结果。这时就要使用distinct()了。
1 | Author.objects.distinct() |
values(fields, *expressions)
当用作可迭代时,返回一个查询集,该查询集返回字典,而不是模型实例。
每个字典都表示一个对象,其键与模型对象的属性名相对应。例:
1 | # This list contains a Blog object. |
values()方法接受可选的位置参数*fields
,它指定SELECT应该被限制的字段名。如果指定字段,每个字典将只包含指定字段的字段键/值。如果不指定字段,每个字典将包含数据库表中每个字段的键和值。
1 | Blog.objects.values() |
values()方法也接受可选的关键字参数
1 | from django.db.models.functions import Lower |
也可以使用内置和自定义查找。例如:
1 | from django.db.models import CharField |
values_list(*fields, flat=False, named=False)
这类似于values(),不同的是,它在遍历时返回元组,而不是返回字典。每个元组包含传入values_list()调用的各自字段或表达式的值—因此第一项是第一个字段,以此类推。
1 | 'id', 'headline') Entry.objects.values_list( |
如果只传入单个字段,还可以传入平面参数。如果为真,则意味着返回的结果是单个值,而不是一个元组。
1 | 'id').order_by('id') Entry.objects.values_list( |
您可以传递named=True来获得namedtuple()的结果
1 | 'id', 'headline', named=True) Entry.objects.values_list( |
常见的需求是获取某个模型实例的特定字段值。为此,使用values_list(),然后调用get():
1 | 'headline', flat=True).get(pk=1) Entry.objects.values_list( |
dates(field, kind, order=’ASC’)
field:模型的日期字段的名称。
kind: “year”、“month”、“week”或者“day”。
order: 默认为“ASC”,应该是“ASC”或“DESC”。指定了如何对结果排序。
1 | 'pub_date', 'year') Entry.objects.dates( |
datetimes(field_name, kind, order=’ASC’, tzinfo=None)
field_name: 应该是模型的DateTimeField的名称。
kind: “year”, “month”, “week”, “day”, “hour”, “minute”, 或 “second”。
order: 默认为“ASC”,应该是“ASC”或“DESC”。指定了如何对结果排序。
tzinfo: 将日期时间转换到的相应的时区时间。
none()
调用none()将创建一个从不返回任何对象的查询集,并且在访问结果时不会执行任何查询。none()查询集是EmptyQuerySet的一个实例。
1 | Entry.objects.none() |
all()
intersection(*other_qs)
difference(*other_qs)
union(*other_qs, all=False)
默认情况下,UNION操作符只选择不同的值。若要允许重复值,请使用all=True
参数。
多个结果集合并时,其它操作只能使用第一个结果集中的字段进行相关操作。
1 | 'name') qs1 = Author.objects.values_list( |
此外,在生成的查询集中只允许LIMIT、OFFSET、COUNT(*)、ORDER BY和指定列(即切片、COUNT()、order_by()和values()/values_list())。此外,数据库对组合查询中允许的操作进行了限制。例如,大多数数据库在组合查询中不允许限制或偏移。
select_related(*fields)
extra(select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
有时候,Django查询语法本身不能轻松地表达复杂的WHERE子句。对于这些边缘情况,Django提供了extra() QuerySet修饰符—用于将特定子句注入到查询集生成的SQL中的钩子。
defer(*fields)
延迟加载给定字段
1 | Entry.objects.defer("headline", "body") |
延迟字段的查询集仍将返回模型实例。如果您访问该字段,将从数据库检索每个延迟字段(一次一个,而不是一次访问所有延迟字段)。
您可以多次调用defer()。每次调用都会向延迟集添加新的字段:
1 | # Defers both the body and headline fields. |
在使用 select_related()
方法时,可使用标准的双下划线符号来分隔相关的字段来延迟相关模型中的字段的加载:
1 | Blog.objects.select_related().defer("entry__headline", "entry__body") |
如果您想要清除延迟字段集,可以将None作为参数传递给defer():
1 | # Load all fields immediately. |
only(*fields)
如果您的模型中几乎所有字段都需要延迟,那么使用only()指定字段的补充集可以得到更简单的代码。
假设您有一个包含name、age和biography字段的模型。以下两个查询集在延迟字段方面是相同的:
1 | Person.objects.defer("age", "biography") |
由于defer()的行为是递增的(向延迟列表中添加字段),所以您可以组合调用only()和defer(),这样事情的行为就会符合逻辑:
1 | # Final result is that everything except "headline" is deferred. |
using(alias)
1 | # queries the database with the 'default' alias. |
select_for_update(nowait=False,skip_locked=False,of=())
返回一个queryset,它将锁定行,直到事务结束,生成一个SELECT…用于更新受支持数据库上的SQL语句。
1 | from django.db import transaction |
raw(raw_query, params=None, translations=None)
将查询字段映射为模型字段.
raw()
字段将查询语句中的字段映射至模型中的字段。
查询语句中的字段排序并不重要。换而言之,以下两种查询是一致的:
1 | 'SELECT id, first_name, last_name, birth_date FROM myapp_person') Person.objects.raw( |
匹配是根据名字来的。这意味着你可以使用 SQL 的 AS
子句将查询语句中的字段映射至模型中的字段。所以,若你还有一些数据表包含了 Person
数据,你可以很方便的将其映射至 Person
实例:
1 | '''SELECT first AS first_name, Person.objects.raw( |
用 raw()
的 translations
参数将查询语句中的字段映射至模型中的字段。这是一个字典,将查询语句中的字段名映射至模型中的字段名。例如,上面的查询也能这样写:
1 | 'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'} name_map = { |
索引查询.
raw()
支持索引,所以,若你只需要第一个结果就这样写:
1 | 'SELECT * FROM myapp_person')[0] first_person = Person.objects.raw( |
不过,索引和切片不是在数据库层面上实现的。若数据库中有非常多的 Person
对象,更搞笑的方式是在 SQL 层面使用 limit 子句:
1 | 'SELECT * FROM myapp_person LIMIT 1')[0] first_person = Person.objects.raw( |
延迟模型字段.
1 | 'SELECT id, first_name FROM myapp_person') people = Person.objects.raw( |
1 | for p in Person.objects.raw('SELECT id, first_name FROM myapp_person'): |
将参数传给 raw()
如果你需要执行参数化的查询,可以使用 raw()
的 params
参数:
1 | 'Doe' lname = |
params
是一个参数字典。你将用一个列表替换查询字符串中 %s
占位符,或用字典替换 %(key)s
占位符(其中, key
理所应当由字典 key 替换),不论你使用哪个数据库引擎。这些占位符会被 params
参数的值替换。
AND (&)
1 | Model.objects.filter(x=1) & Model.objects.filter(y=2) |
1 | SELECT ... WHERE x=1 AND y=2 |
or(|)
1 | Model.objects.filter(x=1) | Model.objects.filter(y=2) |
1 | SELECT ... WHERE x=1 OR y=2 |
不返回QuerySets的方法
get(**kwargs)
1 | from django.core.exceptions import ObjectDoesNotExist |
creteate(**kwargs)
1 | p = Person.objects.create(first_name="Bruce", last_name="Springsteen") |
get_or_create(defaults=None,** kwargs)
防止在并行请求时创建重复对象,并作为boilerplatish代码的快捷方式。例如:
1 | try: |
对于并发请求,可能会多次尝试保存具有相同参数的人员。为了避免这种竞争条件,上面的例子可以使用get_or_create()重写,如下所示:
1 | obj, created = Person.objects.get_or_create( |
update_or_create(defaults=None, **kwargs)
1 | defaults = {'first_name': 'Bob'} |
1 | obj, created = Person.objects.update_or_create( |
bulk_create(objs, batch_size=None, ignore_conflicts=False)
将提供的对象列表高效地插入到数据库中(通常只有一个查询,无论有多少对象):
1 | from itertools import islice |
bulk_update(objs, fields, batch_size=None)
1 | objs = [ |
count()
1 | # Returns the total number of entries in the database. |
in_bulk(id_list=None, field_name=’pk’)
1 | 1]) Blog.objects.in_bulk([ |
iterator(chunk_size=2000)
latest(*fields)
根据给定字段返回表中的最新对象。
1 | Entry.objects.latest('pub_date') |
1 | Entry.objects.latest('pub_date', '-expire_date') |
earliest(*fields)
first()
1 | p = Article.objects.order_by('title', 'pub_date').first() |
等价于
1 | try: |
last()
aggregate(args, *kwargs)
1 | from django.db.models import Count |
1 | 'entry')) q = Blog.objects.aggregate(number_of_entries=Count( |
exists()
1 | entry = Entry.objects.get(pk=123) |
快于
1 | if entry in some_queryset: |
update(**kwargs)
1 | Entry.objects.filter(id=10).update(comments_on=False) |
快于
1 | e = Entry.objects.get(id=10) |
update()未调用save()方法,若重写了save()方法,慎用之。
delete()
as_manager()
explain(format=None, **options)
返回查询集执行计划的字符串,其中详细说明数据库将如何执行查询,包括将使用的任何索引或连接。了解这些细节可以帮助您提高慢速查询的性能。
1 | 'My Blog').explain()) print(Blog.objects.filter(title= |
F表达式
- 更新字段的值
示例1:
1 | reporter = Reporters.objects.get(name='Tintin') |
示例2:
1 | from django.db.models import F |
注:示例2的操作快于示例1,一个F()对象代表一个模型字段的值或注释列。使用它可以直接引用模型字段的值并执行数据库操作而不用把它们导入到python的内存中。Django使用F()对象生成一个描述数据库级别所需操作的SQL表达式。
F()
函数结合update()
方法使用
1 | from django.db.models import F |
- 在过滤器(filter)中使用
F()
函数
要怎么做才能将模型字段值与同一模型中的另一字段做比较呢?
Django 提供了 F 表达式
可实现将模型字段值与同一模型中的另一字段做比较。 F()
的实例充当查询中的模型字段的引用。这些引用可在查询过滤器中用于在同一模型实例中比较两个不同的字段。
例,要查出所有评论数大于 pingbacks 的博客条目,我们构建了一个 F() 对象,指代 pingback 的数量,然后在查询中使用该 F() 对象:
1 | >>> from django.db.models import F |
Django支持F()对象使用加、减、乘、除、取模和幂运算等算术操作,两个操作数可以是常数或F()对象
1 | models.Test.objects.filter(input_price__gt=F("output_price")*2) |
Django 支持对 F() 对象进行加、减、乘、除、求余和次方,另一操作数既可以是常量,也可以是其它 F() 对象。要找到那些评论数两倍于 pingbacks 的博客条目,我们这样修改查询条件:
1 | >>> Entry.objects.filter(number_of_comments__gt=F('number_of_pingbacks') * 2) |
也能用双下划线在 F() 对象中通过关联关系查询。带有双下划线的 F() 对象将引入访问关联对象所需的任何连接。例如,要检索出所有作者名与博客名相同的博客,这样修改查询条件:
1 | >>> Entry.objects.filter(authors__name=F('blog__name')) |
对于 date 和 date/time 字段,你可以加上或减去一个 timedelta 对象。以下会返回所有发布 3 天后被修改的条目:
1 | >>> from datetime import timedelta |
F() 对象通过 .bitand(), .bitor(), .bitrightshift() 和 .bitleftshift() 支持位操作。例子:
1 | >>> F('somefield').bitand(16) |
- 在
annotate
中使用F()
F()可以使用算术运算组合不同字段在模型中创建动态字段。
1 | company = Company.objects.annotate(chairs_needed=F('num_employees') - F('num_chairs')) |
如果组合的是不同类型的字段,你需要告诉Django返回值是哪种字段类型。由于F()不直接支持output_field,所以需要使用ExpressionWrapper来封装表达式:
1 | from django.db.models import DatetimeField, ExpressionWrapper, F |
当引用关联字段(如ForeignKey)时,F()返回的主键值而不是一个模型实例:
1 | >>> car = Company.objects.annotate(built_by=F('manufacturrer'))[0] |
- 使用F()对null值排序
使用F()和传递nulls_first或nulls_last参数给Expression.asc()或desc()来控制字段的null值的排序。默认情况下这个排序取决于你的数据库。
例如,要将未联系过(last_contacted为null)的公司排在已联系过的公司后面:
1 | from django.db.models import F |
F()
函数可以通过以下方式提供性能优势:- 直接在数据库中操作而不是python
- 减少一些操作所需的数据库查询次数
Q表达式
主键 (pk) 查询快捷方式
出于方便的目的,Django 提供了一种 pk 查询快捷方式, pk 表示主键 “primary key”。
示例 Blog 模型中,主键是 id 字段,所以这 3 个语句是等效的:
1 | >>> Blog.objects.get(id_exact=1) |
pk
的使用并不仅限于 __exact
查询——任何的查询项都能接在 pk
后面,执行对模型主键的查询:
1 | # Get blogs entries with id 1, 4 and 7 |
pk 查找也支持跨连接。例如,以下 3 个语句是等效的:
1 | >>> Entry.objects.filter(blog__id__exact=3) # __exact is implied |
在 LIKE 语句中转义百分号和下划线
等效于 LIKE SQL 语句的字段查询子句 (iexact, contains, icontains, startswith, istartswith, endswith 和 iendswith) 会将 LIKE 语句中有特殊用途的两个符号,即百分号和下划线自动转义。(在 LIKE 语句中,百分号匹配多个任意字符,而下划线匹配一个任意字符。)
这意味着事情都是表里如一的,不会出现抽象事故。例如,要检索所有包含百分号的条目,就像对待其它字符一样使用百分号:
1 | >>> Entry.objects.filter(headline__contains='%') # SELECT ... WHERE headline LIKE '%\%%'; |
缓存和 QuerySet
每个 QuerySet 都带有缓存,尽量减少数据库访问。理解它是如何工作的能让你编写更高效的代码。
新创建的 QuerySet 缓存是空的。一旦要计算 QuerySet 的值,就会执行数据查询,随后,Django 就会将查询结果保存在 QuerySet 的缓存中,并返回这些显式请求的缓存(例如,下一个元素,若 QuerySet 正在被迭代)。后续针对 QuerySet 的计算会复用缓存结果。
牢记这种缓存行为,在你错误使用 QuerySet 时可能会被它咬一下。例如,以下会创建两个 QuerySet,计算它们,丢掉它们:
1 | >>> print([e.headline for e in Entry.objects.all()]) |
查询结果集并不总是缓存结果。当仅计算查询结果集的 部分 时,会校验缓存,若没有填充缓存,则后续查询返回的项目不会被缓存。特别地说,这意味着使用数组切片或索引的 限制查询结果集 不会填充缓存。
例如,重复的从某个查询结果集对象中取指定索引的对象会每次都查询数据库:
1 | >>> queryset = Entry.objects.all() |
不过,若全部查询结果集已被检出,就会去检查缓存:
1 | >>> queryset = Entry.objects.all() |
这些动作会触发计算全部的查询结果集,并填充缓存的过程:
1 | >>> [entry for entry in queryset] |
参考
jango中Q查询及Q()对象 F查询及F()对象用法
F() filter使用
model字段别名
1 | from django.db.models import Q, F |
django命令
makemigrations
第一次执行该操作,会在app下面创建migrations目录,并创建0001_inital.py文件,文件中记录了当前的建表、依赖等信息。
下一次执行该操作,如果 model.py 有改动,会在migrations下生成以修改内容为名,类似0002_alter_permission_name_max_length.py的文件,文件中记录了你修改字段等信息,如果没有改动则提示:
No changes detected
。
注:这些改动在此时都没有迁移到数据库。
migrate
- migrate命令执行时Django会做4件事:
- 迁移判定,将你的项目中所有未迁移的变动文件进行迁移(django会去查询django_migrations表判断你是否有新的迁移变动),在完成接下来的迁移后,便会在该表中生成一条迁移记录。
- 迁移映射关系 django_contenttype表新增映射关系(app与模型关系)
- 迁移权限 auth_permission表新增权限
- 执行迁移,生成数据表,或变动
migrate –fake 只执行第一步,并生成迁移记录。
migrate –fake-initial 执行前三步,不实际变动数据库
migrate 全部依次执行所有步骤。
注:当django 环境变了时,原其他环境下的项目不能正常运行,需要进行修改。
sqlmigrate
- 可以查看下migrations 0001会对应于什么样子的SQL命令
1 | python manage.py sqlmigrate appname 0020_packappname |
showmigrations
- 查看当前项目所有的app及对应的已经生效的migration文件,[x]表示migrte通过,[]表示未通过