django抽象模型中如何使用 ForeignKey?

django ForeignKey(外键),是在Django数据库设计当中经常需要用到的字段功能,无论是在models.Model还是在Forms.model都需要了解其实使用方法。真的从细节去了解django ForeignKey(外键)具体功能将会使我们的数据库设计和开发事半功倍。

django ForeignKey(外键)

多对一关系。需要两个位置参数:与模型相关的类和on_delete选项。

要创建递归关系(与自身具有多对一关系的对象),请使用models.ForeignKey('self', on_delete=models.CASCADE)。

如果需要在尚未定义的模型上创建关系,则可以使用模型的名称,而不是模型对象本身:

Model.py
from django.db import models

class Car(models.Model):
    manufacturer = models.ForeignKey(
        'Manufacturer',
        on_delete=models.CASCADE,
    )
    # ...

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

抽象模型中如何使用django ForeignKey?

当模型被子类化为具体模型并且不相对于抽象模型时,在抽象模型上以这种方式定义的关系是解析的:app_label

 

定义抽象模型:

model.py

from django.db import models

class AbstractCar(models.Model):
    manufacturer = models.ForeignKey('Manufacturer', on_delete=models.CASCADE)

    class Meta:
        abstract = True#定义为抽象模型
from django.db import models
from products.models import AbstractCar

class Manufacturer(models.Model):
    pass

class Car(AbstractCar):#通过使用抽象模板的类,来继承抽象模型
    pass

跨模型使用django ForeignKey

若要引用在其他应用程序中定义的模型,可以使用完整的应用程序标签显式指定模型。例如,如果上面的模型是在另一个名为 的应用程序中定义的,则需要使用form先引入这个模型:

#定义以soogor应用下的Manufacturer模型为外键数据
form soogor import models as AAA#先引用模型

class Car(models.Model):
    manufacturer = models.ForeignKey(
        AAA.Manufacturer,#将模型调过来
        on_delete=models.CASCADE,
    )

 

数据库表示

在幕后,Django 附加到字段名称以创建其数据库列名称。在上面的示例中,模型的数据库表将包含一列。(您可以通过指定db_column来显式更改此设置)但是,除非编写自定义 SQL,否则您的代码永远不必处理数据库列名。您将始终处理模型对象的字段名称。

例:

a=models.ForeignKey(b) #这样在数据库字段为b_id
a=models.ForeignKey(b,db_column='a') #这样在数据库字段为a

 

参数

ForeignKey 接受定义关系如何工作的详细信息的其他参数。

定义可为空的ForeignKey

当 ForeignKey 引用的对象被删除时,Django 将模拟由 on_delete 参数指定的 SQL 约束的行为。例如,如果您有一个可为空的 ForeignKey,并且您希望在删除引用的对象时将其设置为 null:

user = models.ForeignKey(
    User,
    models.SET_NULL,
    blank=True,
    null=True,
)

ForeignKey.on_delete

on_delete不会在数据库中创建 SQL 约束。对数据库级级联选项的支持可以在以后实现。

on_delete有以下属性:

  • on_delete=models.CASCADE

    级联删除。Django 模拟了 SQL 约束在 级联删除上的行为,并且还删除了包含 ForeignKey 的对象。

    不会在相关模型上调用 Model.delete(),但会为所有已删除的对象发送pre_delete和post_delete信号。

  • PROTECT

    通过引发 ProtectedError(django.db.IntegrityError 的子类)来防止删除引用的对象。

  • RESTRICT

    通过引发 RestrictedError(django 的子类.db.IntegrityError)来防止删除引用的对象。与 PROTECT 不同,如果引用的对象还引用了在同一操作中被删除但通过 CASCADE 关系删除的其他对象,则允许删除该对象。

    请考虑以下一组模型:

    class Artist(models.Model):
        name = models.CharField(max_length=10)
    
    class Album(models.Model):
        artist = models.ForeignKey(Artist, on_delete=models.CASCADE)
    
    class Song(models.Model):
        artist = models.ForeignKey(Artist, on_delete=models.CASCADE)
        album = models.ForeignKey(Album, on_delete=models.RESTRICT)

     

  • Artist即使这意味着删除由 a 引用的 一个,也可以删除,因为也通过级联关系引用自身。例如:AlbumSongSongArtist
    >>> artist_one = Artist.objects.create(name='artist one')
    >>> artist_two = Artist.objects.create(name='artist two')
    >>> album_one = Album.objects.create(artist=artist_one)
    >>> album_two = Album.objects.create(artist=artist_two)
    >>> song_one = Song.objects.create(artist=artist_one, album=album_one)
    >>> song_two = Song.objects.create(artist=artist_one, album=album_two)
    >>> album_one.delete()
    # Raises RestrictedError.
    >>> artist_two.delete()
    # Raises RestrictedError.
    >>> artist_one.delete()
    (4, {'Song': 2, 'Album': 1, 'Artist': 1})

     

  • SET_NULL.这里我们在上面提到过

    设置外键空;仅当 null 为 时才可能。True

  • SET_DEFAULT

    将外键设置为其默认值;必须设置外键的默认值。

  • SET()

    将 ForeignKey 设置为传递给 SET() 的值,或者如果传入可调用项,则为调用它的结果。在大多数情况下,传递可调用文件是必要的,以避免在导入 models.py 时执行查询:

    from django.conf import settings
    from django.contrib.auth import get_user_model
    from django.db import models
    
    def get_sentinel_user():
        return get_user_model().objects.get_or_create(username='deleted')[0]
    
    class MyModel(models.Model):
        user = models.ForeignKey(
            settings.AUTH_USER_MODEL,
            on_delete=models.SET(get_sentinel_user),
        )

     

  • DO_NOTHING

    不执行任何操作。如果数据库后端强制实施引用完整性,这将导致完整性错误,除非您手动向数据库字段添加 SQL 约束。ON DELETE

ForeignKey.limit_choices_to

当使用 a 或 admin 呈现此字段时,对此字段的可用选项设置限制(默认情况下,查询集中的所有对象都可供选择)。可以使用字典、Q 对象或返回字典或 Q 对象的可调用对象。ModelForm

例如:

staff_member = models.ForeignKey(
    User,
    on_delete=models.CASCADE,
    limit_choices_to={'is_staff': True},
)

 

导致 to 上的相应字段仅列出具有 的 字段。这在 Django 管理员中可能会有所帮助。ModelFormUsersis_staff=True

例如,当与Python模块结合使用以按日期范围限制选择时,可调用表单可能会有所帮助。例如:datetime

def limit_pub_date_choices():
    return {'pub_date__lte': datetime.date.today()}

limit_choices_to = limit_pub_date_choices

 

如果 是 或返回 Q 对象(这对于复杂查询很有用),则仅当该字段未在模型的 raw_id_fields 中列出时,它才会对 admin 中可用的选项产生影响。limit_choices_toModelAdmin

注意

如果将可调用对象用于 ,则每次实例化新窗体时都会调用它。在验证模型时,也可以调用它,例如通过管理命令或管理员。管理员构造查询集以多次验证其在各种边缘情况下的表单输入,因此您的可调用对象可能会被多次调用。limit_choices_to

ForeignKey.related_name

用于从相关对象到此对象的关系的名称。它也是related_query_name(用于目标模型中的反向筛选器名称的名称)的默认值。有关完整的说明和示例,请参阅相关对象文档。请注意,在抽象模型上定义关系时,必须设置此值。当您这样做时,可以使用一些特殊的语法。

如果您希望 Django 不要创建向后关系,请设置为 或以 .例如,这将确保模型不会与此模型具有反向关系:related_name'+''+'User

user = models.ForeignKey(
    User,
    on_delete=models.CASCADE,
    related_name='+',
)

 

ForeignKey.related_query_name

用于目标模型中的反向筛选器名称的名称。它默认为related_name的值,如果已设置,则为default_related_name,否则默认为模型的名称:

# Declare the ForeignKey with related_query_name
class Tag(models.Model):
    article = models.ForeignKey(
        Article,
        on_delete=models.CASCADE,
        related_name="tags",
        related_query_name="tag",
    )
    name = models.CharField(max_length=255)

# That's now the name of the reverse filter
Article.objects.filter(tag__name="important")

 

与related_name一样,它通过一些特殊语法支持应用标签和类插值。related_query_name

ForeignKey.to_field

关系所针对的相关对象上的字段。默认情况下,Django 使用相关对象的主键。如果引用其他字段,则该字段必须具有 。unique=True

ForeignKey.db_constraint

控制是否应在数据库中为此外键创建约束。默认值为 ,这几乎可以肯定是您想要的;将此值设置为可能对数据完整性非常不利。也就是说,在以下一些情况下,您可能希望执行此操作:TrueFalse

  • 您有无效的旧数据。
  • 您正在对数据库进行分片。

如果将其设置为 ,则访问不存在的相关对象将引发其异常。FalseDoesNotExist

ForeignKey.swappable

控制迁移框架的反应(如果此 ForeignKey 指向可交换模型)。如果是 - 默认值 - 则如果 ForeignKey 指向与当前值匹配的模型(或其他可交换模型设置),则该关系将使用对设置的引用存储在迁移中,而不是直接存储到模型。Truesettings.AUTH_USER_MODEL

如果您确定模型应始终指向换入的模型(例如,如果它是专门为自定义用户模型设计的配置文件模型),则只想重写此值。False

将其设置为并不意味着即使已换出也可以引用可交换模型 - 这意味着使用此 ForeignKey 进行的迁移将始终引用您指定的确切模型(例如,如果用户尝试使用您不支持的用户模型运行,它将失败)。FalseFalse

如果有疑问,请将其保留为默认值。True

THE END