django-model外鍵關(guān)系之一對多

一對多

外鍵字段是放在多的一方模型類里面的

比如,一輛汽車(Car)有一個(gè)制造商(Manufacturer) —— 但是一個(gè)制造商(Manufacturer) 生產(chǎn)很多汽車(Car),每一輛汽車(Car) 只能有一個(gè)制造商(Manufacturer) —— 使用下面的定義:

from django.db import models

class Manufacturer(models.Model):
    # ...
    pass

class Car(models.Model):
    company_that_makes_it = models.ForeignKey(Manufacturer)

如果想要?jiǎng)?chuàng)建和自己關(guān)聯(lián)的一對多關(guān)系,使用self指向自己

models.ForeignKey('self')

一對多的使用和綁定

準(zhǔn)備數(shù)據(jù)

比如有下面兩個(gè)模型類

from django.db import models

class Reporter(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    email = models.EmailField()

    def __str__(self):              # __unicode__ on Python 2
        return "%s %s" % (self.first_name, self.last_name)

class Article(models.Model):
    headline = models.CharField(max_length=100)
    pub_date = models.DateField()
    reporter = models.ForeignKey(Reporter)

    def __str__(self):              # __unicode__ on Python 2
        return self.headline

    class Meta:
        ordering = ('headline',)

關(guān)聯(lián)對象

默認(rèn)方式

# 創(chuàng)建幾個(gè)Reporter:
>>> r = Reporter(first_name='John', last_name='Smith', email='john@example.com')
>>> r.save()

>>> r2 = Reporter(first_name='Paul', last_name='Jones', email='paul@example.com')
>>> r2.save()
#創(chuàng)建一個(gè)Article:
>>> from datetime import date
>>> a = Article(id=None, headline="This is a test", pub_date=date(2005, 7, 27), reporter=r)
>>> a.save()

>>> a.reporter.id
1

>>> a.reporter
<Reporter: John Smith>

# 注意,將對象分配給一個(gè)外鍵之前必須保存。例如,使用未保存的Reporter 創(chuàng)建Article 將引發(fā)ValueError:
>>> r3 = Reporter(first_name='John', last_name='Smith', email='john@example.com')
>>> Article(headline="This is a test", pub_date=date(2005, 7, 27), reporter=r3)
Traceback (most recent call last):
...
ValueError: 'Cannot assign "<Reporter: John Smith>": "Reporter" instance isn't saved in the database.'

#訪問關(guān)聯(lián)對象,具體看模型的查詢
>>> r = a.reporter
>>> r.first_name, r.last_name
('John', 'Smith')

除了上面的方式外還有幾個(gè)內(nèi)建的關(guān)聯(lián)對象的方法,add,create,remove,clear

  • add(obj1, obj2, ...)添加一指定的模型對象到關(guān)聯(lián)的對象集中。
    >>> r1 = Reporter(first_name='John', last_name='Smith', email='john@example.com')
    >>> r1.save()
    >>> a1 = Article(id=None, headline="This is a test", pub_date=date(2005, 7, 27))
    >>> a1.save()
    >>> r1.article_set.add(a1)

  • create(**kwargs)創(chuàng)建一個(gè)新的對象,將它保存并放在關(guān)聯(lián)的對象集中。返回新創(chuàng)建的對象。
    >>> r1 = Reporter(first_name='John', last_name='Smith', email='john@example.com')
    >>> r1.save()
    >>> r1.article_set.create(headline="This is a test", pub_date=date(2005, 7, 27))

  • remove(obj1, obj2, ...)從關(guān)聯(lián)的對象集中刪除指定的模型對象。
    >>> r1 = Reporter(first_name='John', last_name='Smith', email='john@example.com')
    >>> r1.save()
    >>> r1.article_set.create(headline="This is a test", pub_date=date(2005, 7, 27))
    >>> a1 = Article.objects.filter(id=1)
    >>> r1.article_set.remove(a1)

  • clear()從關(guān)聯(lián)的對象集中刪除所有的對象。
    >>> r1 = Reporter(first_name='John', last_name='Smith', email='john@example.com')
    >>> r1.save()
    >>> r1.article_set.create(headline="This is a test", pub_date=date(2005, 7, 27))
    >>> r1.article_set.clear()

  • 一次性關(guān)聯(lián)多個(gè)對象
    若要一次性給關(guān)聯(lián)的對象集賦值,只需要給它賦值一個(gè)可迭代的對象。這個(gè)可迭代的對象可以包含對象的實(shí)例,或者一個(gè)主鍵值的列表。
    >>> r1 = Reporter.objects.get(id=1)
    >>> r1.entry_set = [a1, a2]
    a1 和a2 可以是Article 實(shí)例,也可以是Article實(shí)例主鍵的整數(shù)值。

外鍵關(guān)聯(lián)對象的查找(或者說是索引也可以說是獲取)或者說是關(guān)聯(lián)模型的反向查詢

比如有兩個(gè)模型類A和B,A是多的一方,B是一的一方,外鍵字段是設(shè)置在多的一方里面的

  • 使用默認(rèn)方式(源模型名__set方式) 源模型名要小寫

    class A(models.Model):
    age = models.IntField()
    obj_b = models.ForeignKey(B)

    class B(modes.Model):
    name = models.CharField()
    pass

    b1 = B()
    b1.save()
    a1 = A(b=b1)
    a1.save()
    那么a拿到b的對象
    a1.obj_b.name 就能拿到了 a對象綁定的b對象的name字段值
    那么b怎么拿到a 呢 使用源模型名(小寫)__set方法
    b1.a_set.age b就拿到了關(guān)聯(lián)的a對象的age字段值

  • 使用related_name屬性(覆蓋上面的默認(rèn)方式)

    class A(models.Model):
    age = models.IntField()
    obj_b = models.ForeignKey(B,related_name="obj_a")

    class B(modes.Model):
    name = models.CharField()
    pass

    b1 = B()
    b1.save()
    a1 = A(b=b1)
    a1.save()
    a拿到b的方式還是一樣的
    a1.obj_b.name 就能拿到了 a對象綁定的b對象的name字段值
    b拿到a 的方式變了,不在是源模型名__set,而是related_name指定的值
    b1.obj_a.age b1就拿到了關(guān)聯(lián)的a1對象的age字段值

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容