【问题标题】:How to get just the relational fields of a model?如何仅获取模型的关系字段?
【发布时间】:2021-07-21 19:11:38
【问题描述】:

这是我的模型,问题如下。

from django.db import models

# ...

class County(models.Model):
    name = models.CharField(max_length=50, verbose_name=_("Numele județului"))
    capital = models.ForeignKey("Municipality", on_delete=models.PROTECT, null=True, blank=True, related_name="capital_of", verbose_name=_("Reședința"))
    region = models.ManyToManyField(Region, related_name="counties", verbose_name=_("Regiunea"))
    area = models.IntegerField(verbose_name=_("Suprafața"))
    population = models.IntegerField(verbose_name=_("Populația"))
    description = models.TextField(verbose_name=_("Descrierea"))
    north = models.ForeignKey("self", on_delete=models.SET_NULL, null=True, blank=True, related_name="to_south", verbose_name=_("Nord"))
    northeast = models.ForeignKey("self", on_delete=models.SET_NULL, null=True, blank=True, related_name="to_southwest", verbose_name=_("Nord-est"))
    east = models.ForeignKey("self", on_delete=models.SET_NULL, null=True, blank=True, related_name="to_west", verbose_name=_("Est"))
    southeast = models.ForeignKey("self", on_delete=models.SET_NULL, null=True, blank=True, related_name="to_northwest", verbose_name=_("Sud-est"))
    south = models.ForeignKey("self", on_delete=models.SET_NULL, null=True, blank=True, related_name="to_north", verbose_name=_("Sud"))
    southwest = models.ForeignKey("self", on_delete=models.SET_NULL, null=True, blank=True, related_name="to_northeast", verbose_name=_("Sud-vest"))
    west = models.ForeignKey("self", on_delete=models.SET_NULL, null=True, blank=True, related_name="to_east", verbose_name=_("Vest"))
    northwest = models.ForeignKey("self", on_delete=models.SET_NULL, null=True, blank=True, related_name="to_southeast", verbose_name=_("Nord-vest"))

    class Meta:
        verbose_name = _("Județ")
        verbose_name_plural = _("Județe")

    def __str__(self):
        return self.name

    @property
    def neighbours(self):
        neighbour_counties = {}
        for field in self._meta.fields:
            if field.related_model == County:
                neighbour_counties[field.name] = field
        return neighbour_counties
    neighbours.fget.short_description = _("Vecinii")

在本例中,我想添加两个实例:Olt 和 Teleorman。如果我创建 Olt 并将 Teleorman 指定为其东部邻居,如何自动将 Teleorman 的西部邻居设置为 Olt?

我的想法是获取一个包含八个相邻字段作为属性的列表,它可以正常工作,直到我尝试在信号处理程序中获取字段实例。我需要反转邻居列表并获得最近更改的那个相反的值:如果我更改county1.east 的值,我需要一种方法如何将西作为应该在county2 中更新的字段。

pre_save 信号处理程序应该是什么样子?邻居@property 是否正确编写?

【问题讨论】:

  • OltTeleorman 的第一个示例中,您可以通过访问.to_west 访问Teleorman 的西侧,对吗?因此,如果您有一个 FK east,其中有 related_name='west'(或者在您的情况下为 to_west),那么您已经在一个字段中拥有东西。
  • 所以你可以简单地使用:olt.east = teleorman来设置关系。 olt.east 将是 teleormanteleorman.to_westteleorman.west 将是 olt
  • 我理解你的观点,这很合乎逻辑。但是,我也在尝试添加 Teleorman.west = Teleorman.to_west。有没有办法做到这一点?例如,我怎样才能捕获字符串“to_west”,修剪“to_”部分并将“west”作为要更新的字段名称?也许我的设计没有什么意义,我不知道,但是在模板中我列出了邻居,并且“to_...”字段没有出现在那里。这就是这个问题的原因。
  • 我认为这是因为关系被定义为ForeignKey。所以to_west 比如会是一个经理,所以实际用法是to_west.first()。解决此问题的一种方法是将所有外键定义为一对一。我会尝试发布答案

标签: django django-models


【解决方案1】:

我看到解决此问题的一种方法是仅定义一半方向,并为另一半使用反向相关名称。但为了做到这一点,您需要将字段定义为OneToOneField

class County(models.Model):
    north = models.OneToOneField(
        "self", on_delete=models.SET_NULL, 
        null=True, blank=True, 
        related_name="south"  # the other side
    )
    northeast = models.OneToOneField(
        "self", on_delete=models.SET_NULL, 
        null=True, blank=True, 
        related_name="southwest"  # the other side
    )
    east = models.OneToOneField(
        "self", on_delete=models.SET_NULL, 
        null=True, blank=True, 
        related_name="west"  # the other side
    )
    southeast = models.OneToOneField(
        "self", on_delete=models.SET_NULL, 
        null=True, blank=True, 
        related_name="northwest"  # the other side
    )

然后像这样使用它们:

c1 = County()
c2 = County()
c3 = County()

c1.north = c2  # this means c2.south == c1
c2.southeast = c3  # this means c3.northeast == c2

等等。这样您就不必担心设置方向的另一侧。此外,OneToOneField 还将确保一次只能有一个县位于另一个县的北部。

【讨论】:

  • 这对我来说是一种新方法......它比我试图完成的复杂事情要好,但这里有一个小问题。如果我需要直接指定当前显示为related_name 值的字段之一,会发生什么?例如,c1.south = c3
  • 你不能。你只能做c3.north = c1,但这和c1.south = c3是一样的
  • 谢谢。顺便说一句,我发现了一些可能有用的东西,model.field.related_query_name 属性,我们会看看它对我有什么帮助。 :)
猜你喜欢
  • 2020-02-12
  • 1970-01-01
  • 1970-01-01
  • 2019-04-17
  • 2018-02-24
  • 2019-10-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多