【问题标题】:How to write a Django model field that refers to another field in the same model?如何编写引用同一模型中另一个字段的 Django 模型字段?
【发布时间】:2023-02-24 03:20:21
【问题描述】:

我有一个名为 booking 的模型,它有两个外键:艺术家和场地。 艺术家可以要求预订场地,但场地也可以要求预订艺术家。我想保存在试图预订谁的模型中。 我该怎么做呢?

class Booking(models.Model):
    name = models.CharField(max_length=100)

    #relationships
    artist = models.ForeignKey(Artist, related_name="events", on_delete=models.CASCADE)
    venue = models.ForeignKey(Venue, related_name="events", on_delete=models.CASCADE)
    
    requester = # Either artist or venue (preferablly pointing to the object) How do I write this?  

我考虑过创建另一个外键,但这必须是有条件的,因为它可以是艺术家或场地。这将导致数据库重复。

我还考虑过创建一个简单的布尔值“booked_by_artist”,但这不会指向哪个艺术家。

【问题讨论】:

  • 对于这样的情况,通常人们会使用“多态”/通用关系。 Django 使用他们的Content types framework 启用它。

标签: python django


【解决方案1】:

笔记: 通用关系并不能解决这里的问题,因为它用于防止外键的代码重复非互连楷模。 通过 Generic Relation 我们可以为 ArtistVenue 创建一个通用模型 Bookings,但是创建的每个 Bookings 对象对它们来说都是不同的。此外,任何一个创建的Bookings对象将无法为另一个提供ForeignKey

最直接的方式要实现这一点,是通过仅提供 artistvenue ForeignKey 中的一个来创建对象。然后在第一次保存后更新另一个。您可以通过要求 null 和 blank 在两个外部字段上都为真来实现这一点,然后在 clean 方法中减轻它。请注意,必须在重写的save 方法中手动调用 clean 方法,否则默认情况下不会调用它。这是Bookings模型:

class Bookings(models.Model):
    requester = models.CharField(max_length=50)
    artist = models.ForeignKey(Artist,null=True,blank=True,on_delete=models.CASCADE,related_name="artist_booking")
    venue = models.ForeignKey(Venue,null=True,blank=True,on_delete=models.CASCADE,related_name="venue_booking")

    def clean(self):
        if self.artist and self.venue:
        raise ValidationError('A booking cannot have both an artist and a venue.')
        super(Bookings,self).clean()

    def save(self,*args,**kwargs):
        self.clean() 
        if not self.requester:
            if self.artist:
                self.requester="artist:"+self.artist.name
            elif self.venue:
                self.requester="venue:"+self.venue.name
        super(Bookings,self).save(*args,**kwargs)

要创建它,

booking1=None
try:
    # If you create booking with both artist and venue 
    # at the same time,it should throw `ValidationError`.
    booking1=Bookings.objects.create(artist=artist)
except Exception as e:
    print(e)
venue = Venue.objects.create(...)
booking1.venue = venue
booking1.save()
# Get event requester from booking object.
event_requester,name  = booking1.requester.split(":")
if event_requster=="artist":
    do_something(name)
elif event_requester=="venue":
    do_something_else(name)

【讨论】:

    猜你喜欢
    • 2011-05-21
    • 2019-09-04
    • 2019-03-11
    • 1970-01-01
    • 2015-09-26
    • 2021-10-05
    • 2017-01-31
    • 1970-01-01
    • 2012-05-20
    相关资源
    最近更新 更多