模型是你的數據的惟一的、權威的信息源。它包含你所儲存數據的必要字段和行爲。一般,每一個模型對應數據庫中惟一的一張表。python
基礎:數據庫
這個例子定義一個Person模型,它有first_name 和last_name 兩個屬性:django
from django.db import models class Person(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=30)
一些技術上的注意事項:app
詳見博客:Django模型字段類型詳解post
詳見博客:Django模型字段選項詳解this
Django 提供了三種最多見的數據庫關係:多對一(many-to-one),多對多(many-to-many),一對一(one-to-one)。spa
Django 使用 django.db.models.ForeignKey 定義多對一關係。和使用其它字段類型同樣:在模型當中把它作爲一個類屬性包含進來。.net
ForeignKey 須要一個位置參數:與該模型關聯的類。rest
好比,一輛汽車(Car)有一個製造商(Manufacturer) —— 可是一個製造商(Manufacturer) 生產不少汽車(Car),每一輛汽車(Car) 只能有一個製造商(Manufacturer) —— 使用下面的定義:code
from django.db import models class Manufacturer(models.Model): # ... pass class Car(models.Model): manufacturer = models.ForeignKey(Manufacturer) # ...
ManyToManyField 用來定義多對多關係,用法和其餘Field字段類型同樣:在模型中作爲一個類屬性包含進來。
ManyToManyField 須要一個位置參數:和該模型關聯的類。
例如,一個披薩能夠有多種餡料 ,一種餡料 也能夠位於多個披薩上。 以下展現:
from django.db import models class Topping(models.Model): # ... pass class Pizza(models.Model): # ... toppings = models.ManyToManyField(Topping)
一般,ManyToManyField 實例應該位於能夠編輯的表單中。在上面的例子中,toppings 位於Pizza 中(而不是在 Topping 裏面設置pizzas 的 ManyToManyField 字段),由於設想一個Pizza 有多種Topping 比一個Topping 位於多個Pizza 上要更加天然。按照上面的方式,在Pizza 的表單中將容許用戶選擇不一樣的Toppings。
處理相似搭配 pizza 和 topping 這樣簡單的多對多關係時,使用標準的ManyToManyField 就能夠了。可是,有時你可能須要關聯數據到兩個模型之間的關係上。
例如,有這樣一個應用,它記錄音樂家所屬的音樂小組。咱們能夠用一個ManyToManyField 表示小組和成員之間的多對多關係。可是,有時你可能想知道更多成員關係的細節,好比成員是什麼時候加入小組的。
對於這些狀況,Django 容許你指定一箇中介模型來定義多對多關係。 你能夠將其餘字段放在中介模型裏面。源模型的ManyToManyField 字段將使用through 參數指向中介模型。對於上面的音樂小組的例子,代碼以下:
from django.db import models class Person(models.Model): name = models.CharField(max_length=128) def __str__(self): # __unicode__ on Python 2 return self.name class Group(models.Model): name = models.CharField(max_length=128) members = models.ManyToManyField(Person, through='Membership') def __str__(self): # __unicode__ on Python 2 return self.name class Membership(models.Model): person = models.ForeignKey(Person) group = models.ForeignKey(Group) date_joined = models.DateField() invite_reason = models.CharField(max_length=64)
在設置中介模型時,要顯式地指定外鍵並關聯到多對多關係涉及的模型。這個顯式聲明定義兩個模型之間是如何關聯的。
既然你已經設置好ManyToManyField 來使用中介模型(在這個例子中就是Membership),接下來你要開始建立多對多關係。你要作的就是建立中介模型的實例:
>>> 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() [<Person: Ringo Starr>] >>> ringo.group_set.all() [<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() [<Person: Ringo Starr>, <Person: Paul McCartney>]
與普通的多對多字段不一樣,你不能使用add、 create和賦值語句(好比,beatles.members = [...])來建立關係:
# THIS WILL NOT WORK >>> beatles.members.add(john) # NEITHER WILL THIS >>> beatles.members.create(name="George Harrison") # AND NEITHER WILL THIS >>> beatles.members = [john, paul, ringo, george]
爲何不能這樣作? 這是由於你不能只建立 Person和 Group之間的關聯關係,你還要指定 Membership模型中所須要的全部信息;而簡單的add、create 和賦值語句是作不到這一點的。因此它們不能在使用中介模型的多對多關係中使用。此時,惟一的辦法就是建立中介模型的實例。
remove()方法被禁用也是出於一樣的緣由。可是clear() 方法倒是可用的。它能夠清空某個實例全部的多對多關係:
>>> # Beatles have broken up >>> beatles.members.clear() >>> # Note that this deletes the intermediate model instances >>> Membership.objects.all() []
過建立中介模型的實例來創建對多對多關係後,你就能夠執行查詢了。 和普通的多對多字段同樣,你能夠直接使用被關聯模型的屬性進行查詢:
# Find all the groups with a member whose name starts with 'Paul' >>> Group.objects.filter(members__name__startswith='Paul') [<Group: The Beatles>]
若是你使用了中介模型,你也能夠利用中介模型的屬性進行查詢:
# Find all the members of the Beatles that joined after 1 Jan 1961 >>> Person.objects.filter( ... group__name='The Beatles', ... membership__date_joined__gt=date(1961,1,1)) [<Person: Ringo Starr]
若是你須要訪問一個成員的信息,你能夠直接獲取Membership模型:
>>> ringos_membership = Membership.objects.get(group=beatles, person=ringo) >>> ringos_membership.date_joined datetime.date(1962, 8, 16) >>> ringos_membership.invite_reason 'Needed a new drummer.'
另外一種獲取相同信息的方法是,在Person對象上查詢多對多反轉關係:
>>> ringos_membership = ringo.membership_set.get(group=beatles) >>> ringos_membership.date_joined datetime.date(1962, 8, 16) >>> ringos_membership.invite_reason 'Needed a new drummer.'
OneToOneField用來定義一對一關係。 用法和其餘字段類型同樣:在模型裏面作爲類屬性包含進來。
當某個對象想擴展自另外一個對象時,最經常使用的方式就是在這個對象的主鍵上添加一對一關係。
from django.db import models class Place(models.Model): name = models.CharField(max_length=50) address = models.CharField(max_length=80) def __str__(self): # __unicode__ on Python 2 return "%s the place" % 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): # __unicode__ on Python 2 return "%s the restaurant" % self.place.name class Waiter(models.Model): restaurant = models.ForeignKey(Restaurant) name = models.CharField(max_length=50) def __str__(self): # __unicode__ on Python 2 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()
使用內部的class Meta 定義模型的元數據,例如:
from django.db import models class Ox(models.Model): horn_length = models.IntegerField() class Meta: ordering = ["horn_length"] verbose_name_plural = "oxen"
模型元數據是「任何不是字段的數據」,好比排序選項(ordering),數據庫表名(db_table)或者人類可讀的單複數名稱(verbose_name 和verbose_name_plural)。在模型中添加class Meta是徹底可選的,全部選項都不是必須的。
更多詳細,見博客:Django模型類Meta元數據詳解
能夠在模型上定義自定義的方法來給你的對象添加自定義的「底層」功能。Manager 方法用於「表範圍」的事務,模型的方法應該着眼於特定的模型實例。
這是一個很是有價值的技術,讓業務邏輯位於同一個地方 —— 模型中。
例如,下面的模型具備一些自定義的方法:
from django.db import models class Person(models.Model): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) birth_date = models.DateField() def baby_boomer_status(self): "Returns the person's baby-boomer status." import datetime if self.birth_date < datetime.date(1945, 8, 1): return "Pre-boomer" elif self.birth_date < datetime.date(1965, 1, 1): return "Baby boomer" else: return "Post-boomer" def _get_full_name(self): "Returns the person's full name." return '%s %s' % (self.first_name, self.last_name) full_name = property(_get_full_name)
這個例子中的最後一個方法是一個屬性。
還有另一部分封裝數據庫行爲的模型方法,你可能想要自定義它們。特別是,你將要常常改變save() 和delete() 的工做方式。
你能夠自由覆蓋這些方法(和其它任何模型方法)來改變它們的行爲。
覆蓋內建模型方法的一個典型的使用場景是,你想在保存一個對象時作一些其它事情。:
from django.db import models class Blog(models.Model): name = models.CharField(max_length=100) tagline = models.TextField() def save(self, *args, **kwargs): do_something() super(Blog, self).save(*args, **kwargs) # Call the "real" save() method. do_something_else()
你還能夠阻止保存:
from django.db import models class Blog(models.Model): name = models.CharField(max_length=100) tagline = models.TextField() def save(self, *args, **kwargs): if self.name == "Yoko Ono's blog": return # Yoko shall never have her own blog! else: super(Blog, self).save(*args, **kwargs) # Call the "real" save() method.
必需要記住調用超類的方法—— super(Blog, self).save(*args, **kwargs) —— 來確保對象被保存到數據庫中。若是你忘記調用超類的這個方法,默認的行爲將不會發生且數據庫不會有任何改變。
還要記住傳遞參數給這個模型方法 —— 即*args, **kwargs。 Django 將來將一直會擴展內建模型方法的功能並添加新的參數。若是在你的方法定義中使用*args, **kwargs,將保證你的代碼自動支持這些新的參數。
批量操做中被覆蓋的模型方法不會被調用
注意,當使用查詢集批量刪除對象時,將不會爲每一個對象調用delete() 方法。爲確保自定義的刪除邏輯獲得執行,你可使用pre_delete 和/或post_delete 信號。
不幸的是,當批量creating 或updating 對象時沒有變通方法,由於不會調用save()、pre_save和 post_save。