模型和数据库
模型
各种Model Field类型
- AutoField,自动增长的IntegerField,如果不指定,则默认添加。
- IntegerField/BigIntegerField/PositiveSmallIntegerField/SmallIntegerField:都是类似的,只是数字的范围不同。
- BinaryField/DecimalField:二进制和十进制。
- BooleanField,如果没有指定default的话,默认为None
- CharField,**必须**接收另外一个参数 max_length
DateField,使用Python的datetime.date实例表示的日期。
需要注意的是,auto_now用于每次保存对象的时候,自动设置该字段为当前时间;auto_now_add则用于第一次被创建时自动设置该字段为当前时间,这些选项还有default之间相互违背的,所以不要同时使用任意多个。这些选项默认保存的是 django.utils.timezone.datetime 里面的now,所以如果想要进行特殊的保存,需要自己重写save函数。
FileField,上传文件,字段的选项不支持primary_key和unique。
需要在settting文件里面,需要添加MEDIA_ROOT用来提供文件上传的根路径,而参数upload则提供文件具体的位置。 当你删除了该model,文件需要你自己手动去删除。
NullBooleanField,和之前BooleanField不同的是,它除了允许True或者False,还允许Null=True,也就是为null。
TextField,适用于大文本字段,如果设定了max_length属性,那么其只会对组件进行一个内容显示的限制,但是不会对数据库存在限制。
- ForeignKey,对应的是一对多的关系,可以指定关联删除-**on_delete=models.CASCADE**,如果要关联的对象还没有定义好,可以使用其名字。
- limit_choices_to,可以限制关联返回的内容。
- related_name,可以让关联的对象反查到源对象,如果不想创建反向关联,则设置为"+"即可。需要注意的是,如果没有使用该Field,那么想要使用反向关联,则需要**foo_set**,foo为关联对象的小写名称,如果使用了该Field,则可以直接使用自己定义的名称。
- related_query_name,和上面的作用类似,同样可以反向查询,两者只需要设置一个即可。
- to_field,指定关联对象的字段名称,默认情况下为对方的主键。
- db_constraint,控制是否在数据库中为这个外键创建约束,默认为True。
- on_delete,可以实现CASCADE,级联删除;PROTECT,防止被引用对象删除,抛出ProtectedError;SET_NULL,将其设置成null;
- ManyToManyField,对应的是多对多的关系。
OneToOneField,对应的是一对一的关系,其可以直接返回关系另一边的对象,最主要的用途是作为扩展自另外一个模型的主键。比如多表继承就是利用这样的原理,通过对子模型添加一个隐式的一对一关联关系到父亲模型实现的。
如果你没有指定其的related_name参数,那么Django将使用当前模型的小写名称作为默认值。 如果访问相应的对象不存在的话,则会抛出ObjectDoesNotExist的异常。 当设置**parent_link**为True时,??
Model Field Options
- Field.null,注意在CharField或者TextField里避免使用null,因为其存储的值是空字符串而不是NULL。
- Field.blank,和上面的不同,其限制的是组件,而上面限制的是数据库。
- Field.choices,由可迭代的二元祖来组成,其中元祖里面第一个元素是存储在数据中的值,第二个则是元素更加详细的描述,界面上显示的是后者。,数据库存储的是前者。
- Field.db_column,数据库中用来表示字段的名称,如果没有提供,则默认使用filed的名称。
- Field.db_index,如果为True,则为该字段创建索引。
- Field.db_tablespace,表空间,如果该字段已经创建了索引,那么数据库表空间的名称将作为该字段的索引名。注意,部分数据库不支持表空间。
- Field.db_default,指定一个默认值,它可以是一个值或者可调用对象,注意的是,其不可以是一个可变对象,因为会指向同一个引用。
- Field.editable,如果为false,则不可编辑,那么admin和其它model则忽略掉这个字段。
- Field.error_messages,能够重写默认抛出的错误信息。
- Field.help_text,将会作为提示信息显示在表单中。
- Field.primary_key,这意味着null=False和unique=True,所以一个对象只能拥有一个主键。
- Field.unique,当设定为True时,不需要再设定db_index,因为其本身就是一个索引的创建。注意的是,ManyToManyField和OneToOneField和FileField以外的其它类型都可以使用这个字段(????)。
- Field.unique_for_date/Field.unique_for_month/Field.unique_for_year/Field,设置对应的时间是唯一的。
- Field.validators,指定验证器。
- ForeignKey、ManyToManyField和OneToOneField需要通过Field.verbose_name才能自定义设置字段名,其它均可以每个字段类型都可在第一个参数上自定义设置字段的字段名。
- Field.many_to_many,多对多关系;
- Field.many_to_one,多对一关系,例如ForeignKey;
- Field.one_to_many,一对多关系,例如GenericRelation或者ForeignKey的反向;
- Field.one_to_one,一对一关系;
- Field.related_model,指向字段涉及的模型;
自定义Model Field
Relationships
Many-to-one relationships
Many-to-many relationships
One-to-one relationships
Meta 选项
- abstract,如果声明为True,则表明这是一个抽象基类。
- app_label,如果定义在application之外,则需要指明它是那个applicaition的,也可以通过其属性自定义格式。
- base_manager_name,指定managers的名字。
- db_table,指定数据库表格的名字。
- db_tablespace,指定表格空间,如果数据库不支持则忽略。
- default_manger_name,指定manager的名字。
- default_related_name,指定反向关联的模型的名称,需要注意的是,这个名称应该是唯一的,建议命名中包含app和model名字以避免冲突,
%(app_label)s和%(model_name)s
。 - get_latest_by,指定model中某个可排序的字段的名称,这样当通过managers去调用lates函数的时候会返回根据排序的最新的结果。
- managed,是否指明Django为当前模型创建和删除数据库表,True或者False。
order_with_respect_to,通常用在关联对象上面,指定某个字段,使其在父对象中有序。
设置之后,可以通过get_RELATED_order和set_RELATED_order进行获取关联对象的已经拍好序的主键列表或者是自定义设置其顺序。 我们还可以通过get_next_in_order和get_previous_in_order,可以用于获取一个生成器。
模型属性
模型方法
创建对象
模型加载
验证对象
保存对象
- 发出一个pre-save 信号。 发送一个django.db.models.signals.pre_save 信号,以允许监听该信号的函数完成一些自定义的动作。
大部分字段不需要预处理 —— 字段的数据将保持原样。预处理只用于具有特殊行为的字段。例如,如果你的模型具有一个auto_now=True 的DateField,那么预处理阶段将修改对象中的数据以确保该日期字段包含当前的时间戳。(我们的文档还没有所有具有这种“特殊行为”字段的一个列表。)
准备数据库数据。 要求每个字段提供的当前值是能够写入到数据库中的类型。
大部分字段不需要数据准备。简单的数据类型,例如整数和字符串,是可以直接写入的Python 对象。但是,复杂的数据类型通常需要一些改动。 例如,DateField 字段使用Python 的 datetime 对象来保存数据。数据库保存的不是datetime 对象,所以该字段的值必须转换成ISO兼容的日期字符串才能插入到数据库中。
发出一个post-save 信号。 发送一个django.db.models.signals.post_save 信号,以允许监听听信号的函数完成一些自定义的动作。
- 如果对象的主键属性为一个求值为True 的值(例如,非None 值或非空字符串),Django 将执行UPDATE。
- 如果对象的主键属性没有设置或者UPDATE 没有更新任何记录,Django 将执行INSERT。
更新对象
删除对象
Pickling对象
Model.__str__
Model.__eq__
Model.__hash__
Model.get_absolute_url
其它
模型继承
- 通常,你只想使用父类来持有一些信息,你不想在每个子模型中都敲一遍。这个类永远不会单独使用,所以你要使用抽象基类。
- 如果你继承一个已经存在的模型且想让每个模型具有它自己的数据库表,那么应该使用多表继承。继承关系在子model和它的每个父类之间添加一个链接,这是通过自动创建的OneToOneField来实现的。
- 最后,如果你只是想改变一个模块Python 级别的行为,而不用修改模型的字段,你可以使用代理模型。
抽象基类
多表继承
代表模型
多重模型
查询
关联对象参考
获取对象
链式过滤
Entry.objects.filter(headline__startswith='What')
.exclude(pub_date__gte=datetime.date.today())
.filter(pub_date__gte=datetime(2005, 1, 30))
使用get
另外一些查询字段:
- exact:精确匹配,通常我们查询时使用的字段都包含了exact,只不过Dangjo都默认帮你处理好了;
- iexact:匹配,忽略大小写;
- contains,icontains:包含和忽略大小写的包含;
- startswith,endswith,istartswith,iendswith:以某字符串开头和其忽略大小写的情况;
- pk:和主键的作用一样,任何查询类型都可以与pk 结合来完成一个模型上对主键的查询;
F表达式
Entry.objects.filter(n_comments__gt=F('n_pingbacks') * 2) # n_pingbacks为一个字段
缓存和查询集
使用Q对象
Poll.objects.get(
Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),
question__startswith='Who')
删除对象
update
for item in my_queryset:
item.save()
聚合
- Avg:平均值;
- Count:返回对应expression的个数;
- Max:返回expression的最大值;
- Min:返回expression的最小值;
- StdDev:标准差;
- Sum:和;
- Variance:方差;
annotate() 和 values() 字句的顺序
Author.objects.annotate(average_rating=Avg('book__rating')) # 根据作家id进行分组
Author.objects.values('name').annotate(average_rating=Avg('book__rating')) # 根据作家名字进行分组
默认排序交换或order_by()
Item.objects.values("data").annotate(Count("id")).order_by()
搜索
Managers
自定义管理器和模型继承
AbstractBase.objects.do_something()
class MyManager(models.Manager):
use_for_related_fields = True # 注意是在管理器中进行定义
原生SQL语句的查询
使用raw
for p in Person.objects.raw('SELECT * FROM myapp_person'):
print(p)
name_map = {'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'}
Person.objects.raw('SELECT * FROM some_other_table', translations=name_map)
使用原生orm
from django.db import connection
def my_custom_sql(self):
cursor = connection.cursor()
cursor.execute("UPDATE bar SET foo = 1 WHERE baz = %s", [self.baz])
cursor.execute("SELECT foo FROM bar WHERE baz = %s", [self.baz])
row = cursor.fetchone()
return row
延迟加载
数据库事务
管理事务
使用默认的管理事务
from django.db import transaction
@transaction.non_atomic_requests(using='other')
def my_other_view(request):
do_stuff_on_the_other_database()
自定义管理事务
from django.db import transaction
@transaction.atomic
def viewfunc(request):
# This code executes inside a transaction.
do_stuff()
def viewfunc(request):
# This code executes in autocommit mode (Django's default).
do_stuff()
with transaction.atomic():
# This code executes inside a transaction.
do_more_stuff()
使用原生的api
数据库访问优化
在模版中使用with标签
{% with total=business.employees.count %}
{{ total }} employee{{ total|pluralize }}
{% endwith %}
在数据库中操作而不是在Python中操作
用唯一的被索引的列来当作检索的对象
entry = Entry.objects.get(id=10)
entry = Entry.object.get(headline="News Item Title")
一次性检索需要的东西
获取你想要的
使用QuerySet.values()和values_list()
使用QuerySet.defer()和only()
使用QuerySet.count()
使用QuerySet.exists()
不要过度使用count和exists
{% if display_inbox %}
{% with emails=user.emails.all %}
{% if emails %}
<p>You have {{ emails|length }} email(s)</p>
{% for email in emails %}
<p>{{ email.body }}</p>
{% endfor %}
{% else %}
<p>No messages today.</p>
{% endif %}
{% endwith %}
{% endif %}
使用QuerySet.update()和delete()
直接使用外键的值
entry.blog_id # 正确
entry.blog.id # 不好
没有需要就不需要进行排序
整体插入
Entry.objects.bulk_create([
Entry(headline="Python 3.0 Released"),
Entry(headline="Python 3.1 Planned")
])
my_band.members.add(me, my_friend)