Code前端首页关于Code前端联系我们

如何在Django抽象模型中使用ForeignKey?

terry 2年前 (2023-09-24) 阅读数 125 #后端开发

djangoForeignKey是Django数据库设计中经常使用的字段函数。无论是在 models.Model 还是 Forms.model 中,您都需要知道如何使用它。从细节上真正理解djangoForeignKey(外键)的具体功能,会让我们的数据库设计开发事半功倍。

djangoForeignKey(外键)

多对一连接。需要两个参数:与模型关联的类和 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

如何在抽象模型中使用 djangoForeignKey?

当模型被指定为具体模型且与抽象模型无关时,以这种方式定义的与抽象模型的关系是解析式的:app_label

定义抽象模型:

模型。 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

跨模型使用 DjangoForeignKey

要引用另一个应用程序中的特定模型,您可以使用完整的应用程序标记显式定义模型。例如,如果上述模型是在另一个应用程序中定义的,则需要首先使用以下形式加载此模型:

#定义以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约束的行为。例如,如果您有一个可为 null 的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 的级联删除行为,也使用外键删除对象。

    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)

  • 即使意味着删除 所引用的艺术家也可以被删除,因为它也通过流关系引用了自己。示例: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() 的值,或者在发送调用时将其调用的结果。 .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

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

示例:

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

使字段与 的字段列表相匹配。这可能对 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 对象(这对于复杂查询很有用),它只会影响 admin 中可用的选项(如果它们未在 raw_id_fields 字段中列出)。 。 limit_choices_toModelAdmin

注意

如果您使用可调用对象 ,则每次创建新模型时都会调用该对象。也可以在验证模型时调用它,例如通过管理或经理命令。该处理程序构建一系列查询来针对不同的边缘情况多次验证表单条目,因此您的调用可能会被多次调用。 limit_choices_to

ForeignKey.lated_name

用于与与此对象相关的对象进行通信的名称。它也是 related_query_name(目标模型中反向过滤器名称所使用的名称)的默认值。有关完整的说明和示例,请参阅相关文档。请注意,在定义与抽象模型的连接时必须设置该值。执行此操作时,您可以使用特殊语法。

如果您希望 Django 不创建反向连接,请将其设置为 或 。例如,这将确保模型不会与此模型有任何向后关系: related_name'+''+'User

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

ForeignKey .lated_query_name

用于目标中反向过滤器名称的名称模型。它默认为 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

将其设置为并不意味着可修改的模型即使被反转也可以被复制 - 这意味着使用此外键的迁移将始终引用您指定的模型(例如,如果用户尝试使用您指定的模型)不支持)用户模型,它将不起作用)。 FalseFalse

如有疑问,请将其保留为默认值。正确的

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门