字段选项
null和blank区别:
null指的是数据库范畴,字段是否允许为空,blank则是表单数据输入验证范畴,如果为true表示表单验证允许输入一个空值。
模型中的外键关系
one to one relationships
class Place(models.Model): name = models.CharField(max_length=50) address = models.CharField(max_length=80) def __str__(self): return self.name class Restaurant(models.Model): place = models.OneToOneField(Place, primary_key=True) serves_hot_dogs = models.BooleanField(default=False) serves_pizza = models.BooleanField(default=False) def __str__(self): return '%s the restaurant ' % self.place.name
地方和饭馆是一对一的关系
p1 = Place(name='北京', address='西城区55号')
p1.save()
p2 = Place(name='上海', address='西北街道22')
p2.save()
r = Restaurant(place=p1, serves_hot_dogs=True, serves_pizza=False)
r.save()
从饭馆对象访问地方,从地方访问饭馆
r.place
<Place: 北京>
p1.restaurant
<Restaurant: 北京 the restaurant >
p2 没有设置相关的餐厅,使用hasattr 来避免异常
hasattr(p2, 'restaurant')
False
通过地方得到饭馆
Restaurant.objects.get(place__pk=1)
<Restaurant: 北京 the restaurant
通过饭馆的属性帅选得到地方
Place.objects.filter(restaurant__place__name__icontains='北')
<QuerySet [<Place: 北京>, <Place: 北京>, <Place: 北京>]>
many to many
class Publication(models.Model): title = models.CharField(max_length=30) def __str__(self): # __unicode__ on Python 2 return self.title class Meta: ordering = ('title',) class Article(models.Model): headline = models.CharField(max_length=100) publications = models.ManyToManyField(Publication) def __str__(self): # __unicode__ on Python 2 return self.headline class Meta: ordering = ('headline',)
创建添加实例
p1 = Publication(title='The Python Journal') p1.save() p2 = Publication(title='Science News') p2.save() p3 = Publication(title='Science Weekly') p3.save()
创建article
a1 = Article(headline='Django lets you build Web apps easily')
a1.save() # 必须要保存之后才能添加
创建并将publications添加到article
a1.publications.add(p1)
new_pub = a1.publications.create(title='hahahah')
m2m可以互相访问
a1.publications.all()
<QuerySet [<Publication: hahahah>, <Publication: The Python Journal>]>
p1.article_set.all()
<QuerySet [<Article: Django lets you build Web apps easily>]>
Article.objects.filter(publications__title__icontains='he') <QuerySet [<Article: Django lets you build Web apps easily>]> # 支持反向m2m查询(即,从不具有ManyToManyField的表开始 Publication.objects.filter(article__in=[1,2]) <QuerySet [<Publication: hahahah>, <Publication: The Python Journal>]>
从Article中删除Publication:
a1.publications.remove(p1)
从Publication删除Article:
p1.article_set.remove(a1)
分配关系集,分配清除现有集成员:
a1.publications=[p1]
a1.publications=[] # 分配空集,全部清除
a1.publications.all()
[]
清除关系集:
p2.article_set.all()
<QuerySet [<Article: Django lets you build Web apps easily>]>
p2.article_set.clear()
p2.article_set.all()
<QuerySet []>
a1.publications.all()
<QuerySet [<Publication: hahahah>, <Publication: Science Weekly>]>
a1.publications.clear()
a1.publications.all()
<QuerySet []>
批量清除:
>>> q = Article.objects.filter(headline__startswith='Django')
>>> print(q)
[<Article: Django lets you build Web apps easily>]
>>> q.delete()
在delete后需要清除QuerySet 缓存,并且引用的对象应该消失:
q = Article.objects.filter(headline__startswith='Django')
q
<QuerySet [<Article: Django lets you build Web apps easily>]>
q.delete()
(1, {'demo1.Article_publications': 0, 'demo1.Article': 1})
q
<QuerySet []>
q=None
多对多的中介模型
http://usyiyi.cn/translate/django_182/topics/db/models.html
重写预定义模型方法
封装数据库行为的模型方法,自定义经常改变save() 和delete() 的工作方式。
在将博客保存到数据库之前对摘要进行处理
def save(self, *args, **kwargs): # 如果没有填写摘要 if not self.excerpt: # 首先实例化一个 Markdown 类,用于渲染 body 的文本 md = markdown.Markdown(extensions=[ 'markdown.extensions.extra', 'markdown.extensions.codehilite', ]) # 先将 Markdown 文本渲染成 HTML 文本 # strip_tags 去掉 HTML 文本的全部 HTML 标签 # 从文本摘取前 54 个字符赋给 excerpt self.excerpt = strip_tags(md.convert(self.content))[:54] # 调用父类的 save 方法将数据保存到数据库中 super(Article, self).save(*args, **kwargs)
注意,当使用查询集批量删除对象时,将不会为每个对象调用delete() 方法。为确保自定义的删除逻辑得到执行,你可以使用pre_delete 和/或post_delete 信号。
模型继承
1.抽象基类继承
from django.db import models
class CommonInfo(models.Model):
name = models.CharField(max_length=100)
age = models.PositiveIntegerField()
class Meta:
abstract = True
class Student(CommonInfo):
home_group = models.CharField(max_length=5)
Student有三个字段,name, age, home_group. CommonInfo既不能创建表,也不能实例化或者存储
元继承
子类没有自己的Meta类会继承父类的meta
class CommonInfo(models.Model):
# ...
class Meta:
abstract = True
ordering = ['name']
class Student(CommonInfo):
# ...
class Meta(CommonInfo.Meta):
db_table = 'student_info'
一些属性被包含在抽象基类的Meta类里面是没有意义的。如db_table属性意味着所有子类用同一张表,是没有意义的。
在继承了抽象基类时,有使用了related_name属性时,需要注意继承传递
http://usyiyi.cn/translate/django_182/topics/db/models.html
2.多表继承
使用这种方式继承同普通的python对象继承相似,父模型和子模型都是可以查询创建表。父类和子类隐式的添加一个链接(自动创建 OneToOneField)
from django.db import models
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
class Restaurant(Place):
serves_hot_dogs = models.BooleanField(default=False)
serves_pizza = models.BooleanField(default=False)
Place里面的所有字段在 Restaurant中也是有效的,只不过没有保存在数据库中的Restaurant表中
>>> Place.objects.filter(name="Bob's Cafe")
>>> Restaurant.objects.filter(name="Bob's Cafe")
>>> p = Place.objects.get(id=12)
# If p is a Restaurant object, this will give the child class:
>>> p.restaurant
<Restaurant: ...>
多表继承中的meta
子 model 并不能访问它父类的 Meta 类。但是在某些受限的情况下,子类可以从父类继承某些 Meta :如果子类没有指定 ordering属性或 get_latest_by 属性,它就会从父类中继承这些属性
父类有了排序设置,而你并不想让子类有任何排序设置,你就可以显式地禁用排序
class ChildModel(ParentModel):
# ...
class Meta:
# Remove parent's ordering effect
ordering = []
多表继承反向关联
如果哦与父类的另外一个子类做多对一或者多对多必须指明related_name, 否则报错
class Supplier(Place):
customers = models.ManyToManyField(Place, related_name='provider')
指定链接父类的字段
默认隐式创建 OneToOneField字段将子类链接至非抽象的父 model
创建自己的 OneToOneField字段并设置 parent_link=True ,从而使用该字段链接父类。
3.代理继承
为原始模型创建一个代理 。你可以创建,删除,更新代理 model 的实例,而且所有的数据都可以像使用原始 model 一样被保存。 不同之处在于:你可以在代理 model 中改变默认的排序设置和默认的 manager ,更不会对原始 model 产生影响
from django.db import models
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
class MyPerson(Person):
class Meta:
proxy = True
def do_something(self):
# ...
pass
MyPerson类和它的父类 Person 操作同一个数据表。特别的是,Person 的任何实例也可以通过 MyPerson访问,反之亦然:
>>> p = Person.objects.create(first_name="foobar")
>>> MyPerson.objects.get(first_name="foobar")
<MyPerson: foobar>
使用代理 model 给 model 定义不同的默认排序设置。 你可能并不想每次都给Person模型排序,但是使用代理的时候总是按照last_name属性排序
class OrderedPerson(Person):
class Meta:
ordering = ["last_name"]
proxy = True
使用Person查询是无序的,而OrderedPerson 则是按照last_name 排序
基类限制:
代理模型必须继承自一个非抽象基类,可以继承任意个抽象基类,但是没有定义任何model字段