文章目录
模型
每一个模型都映射一个数据库表。
使用模型
定义完模型后需要在INSTALLED_APPS中添加models.py文件的模块的名字。
-
先数据库迁移:python manage.py makemigrations
-
在运行python manage.py migrate
-
向INSTALLED_APPS中添加新的应用
INSTALLED_APPS = [
#...
'myapp',
#...
]
初识模型
模型类名不能与 模型API 冲突的名称,如clean
,save
,_delete
等。
字段选项
如果为True
,则Django将NULL
在数据库中存储空值。默认值为False
。 避免在CharField
字段上设置为True
,字符串字段不输入默认为None
类型,但是字符串字段如果加上unique=True
的约束后在设置null=true就会出异常。
blank
如果为True
,则该字段允许为空白。默认值为False
。
请注意,这与null
有所不同。null
与数据库完全相关,而blank
与验证相关。如果字段包含blank=True
,则表单验证将允许输入一个空值。如果字段包含blank=False
,则将需要该字段。
choices
该参数接收一个可重复的列表或元组(基本单位为二元组)。如果指定了该参数,在实例化该模型时,该变量只能取选择列表中的值。
一个选项列表:
YEAR_IN_SCHOOL_CHOICES = (
('FR', 'Freshman'),
('SO', 'Sophomore'),
('JR', 'Junior'),
('SR', 'Senior'),
('GR', 'Graduate'),
)
每个二元组的第一个值会储存在数据库中,而第二个值将只会用作显示作用。
要获取该细分二元组中相对应的第二个值,使用get_FOO_display()
方法。例如:
>>> p = Person(name="Fred Flintstone", shirt_size="L")
>>> p.save()
>>> p.shirt_size
'L'
>>> p.get_shirt_size_display()
'Large'
default
该变量的值。可以是一个值或者是一个可调用的对象,如果是个可调用对象,每次实例化模型时都会调用该对象。 默认值必须是是不可变对象。
def contact_default():
return {"email": "to1@example.com"}
contact_info = JSONField("ContactInfo", default=contact_default)
primary_key
默认false,不设置为true
Django会自动添加一个IntegerField
的字段为主键。
主键是只可读的,如果修改一个模型实例主键字段相当于创建了一个新的模型实例。
from django.db import models
class Fruit(models.Model):
name = models.CharField(max_length=100, primary_key=True)
>>> fruit = Fruit.objects.create(name='Apple')
>>> fruit.name = 'Pear'
>>> fruit.save()
>>> Fruit.objects.values_list('name', flat=True)
<QuerySet ['Apple', 'Pear']>
unique
默认false, 如果设置为 True
,这个字段必须在整个表中保持值唯一。
备注名
除了 ForeignKey
和 OneToOneField
,任何字段类型都接收一个可选的参数 verbose_name
,如果未指定该参数值, Django 会自动使用该字段的属性名作为该参数值,并且把下划线转换为空格。
备注名为 "person's first name"
:
first_name = models.CharField("person's first name", max_length=30)
备注名为 "first name"
:
first_name = models.CharField(max_length=30)
ForeignKey,ManyToManyField和OneToOneField接收到的第一个参数为模型的类名,后边可以添加一个备注名。
poll = models.ForeignKey(
Poll,
on_delete=models.CASCADE,
verbose_name="the related poll",
)
sites = models.ManyToManyField(Site, verbose_name="list of sites")
place = models.OneToOneField(
Place,
on_delete=models.CASCADE,
verbose_name="related place",
)
关联关系
Many-to-one relationships
通过在多的模型字段外键设置多对一关系,需要两个位置参数。
from django.db import models
class Manufacturer(models.Model):
# ...
pass
class Car(models.Model):
manufacturer = models.ForeignKey(Manufacturer, on_delete=models.CASCADE)
Many-to-many relationships
多对多在任何模型中添加ManyToManyField字段都可以,但是只能在一个中设置。
在实例化 ManyToManyField
的时候使用through
参数指定多对多关系使用哪个中间模型。
在设置中间模型的时候,需要显式地为多对多关系中涉及的模型指定外键。这种显式声明定义了这两个模型之间的关系。
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=128)
def __str__(self):
return self.name
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership')
def __str__(self):
return self.name
class Membership(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)
通过中间模型创建多对多的关系:
>>> ringo = Person.objects.create(name="Ringo Starr")
>>> paul = Person.objects.create(name="Paul McCartney")
>>> beatles = Group.objects.create(name="The Beatles")
>>> m1 = Membership(person=ringo, group=beatles,
... date_joined=date(1962, 8, 16),
... invite_reason="Needed a new drummer.")
>>> m1.save()
>>> beatles.members.all()
<QuerySet [<Person: Ringo Starr>]>
>>> ringo.group_set.all()
<QuerySet [<Group: The Beatles>]>
>>> m2 = Membership.objects.create(person=paul, group=beatles,
... date_joined=date(1960, 8, 1),
... invite_reason="Wanted to form a band.")
>>> beatles.members.all()
<QuerySet [<Person: Ringo Starr>, <Person: Paul McCartney>]>
但是通过中间模型创建的关系不能使用add(),create(),或set()来创建关系,remove方法也同样无法使用。
>>> # The following statements will not work
>>> beatles.members.add(john)
>>> beatles.members.create(name="George Harrison")
>>> beatles.members.set([john, paul, ringo, george])
>>> # This will not work because it cannot tell which membership to remove
>>> beatles.members.remove(ringo)
但是clear()方法可以被用来移除一个实例的所有多对多关系:
>>> # Beatles have broken up
>>> beatles.members.clear()
>>> # Note that this deletes the intermediate model instances
>>> Membership.objects.all()
<QuerySet []>
One-to-one relationships
一对一关系,必须设置为主键
from django.db import models
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
def __str__(self):
return "%s the place" % self.name
class Restaurant(models.Model):
place = models.OneToOneField(
Place,
on_delete=models.CASCADE,
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
class Waiter(models.Model):
restaurant = models.ForeignKey(Restaurant, on_delete=models.CASCADE)
name = models.CharField(max_length=50)
def __str__(self):
return "%s the waiter at %s" % (self.name, self.restaurant)
创建几个地方:
>>> p1 = Place(name='Demon Dogs', address='944 W. Fullerton')
>>> p1.save()
>>> p2 = Place(name='Ace Hardware', address='1013 N. Ashland')
>>> p2.save()
创建一个餐馆,将“父”对象的ID传递为该对象的ID:
>>> r = Restaurant(place=p1, serves_hot_dogs=True, serves_pizza=False)
>>> r.save()
餐厅可进入其地点:
>>> r.place
<Place: Demon Dogs the place>
一个可以进入餐厅的地方(如果有的话):
>>> p1.restaurant
<Restaurant: Demon Dogs the restaurant>
p2没有关联餐厅:
>>> from django.core.exceptions import ObjectDoesNotExist
>>> try:
>>> p2.restaurant
>>> except ObjectDoesNotExist:
>>> print("There is no restaurant here.")
There is no restaurant here.
可以使用hasattr
来避免例外捕获的需要:
>>> hasattr(p2, 'restaurant')
False
使用赋值符号来设置地方。因为地方是餐厅的主键,保存将创建一个新的餐厅:
>>> r.place = p2
>>> r.save()
>>> p2.restaurant
<Restaurant: Ace Hardware the restaurant>
>>> r.place
<Place: Ace Hardware the place>
再次设置地方,使用相反方向的赋值:
>>> p1.restaurant = r
>>> p1.restaurant
<Restaurant: Demon Dogs the restaurant>
请注意,必须先保存一个对象,然后才能将其分配给一对一关系。例如,Restaurant
使用未保存的Place
加注创建一个ValueError
:
>>> p3 = Place(name='Demon Dogs', address='944 W. Fullerton')
>>> Restaurant.objects.create(place=p3, serves_hot_dogs=True, serves_pizza=False)
Traceback (most recent call last):
...
ValueError: save() prohibited to prevent data loss due to unsaved related object 'place'.