2

我有多个与单个模型相关的模型。在保存这些模型时,我覆盖了 save 以检索主模型的 id,以便将文件放在 OS 上由主模型的 pk 键入的目录中。

例如,以具有许多房间的建筑物为例。房间的任何图像都将保存在由建筑物 ID 键入的目录中(房间没有子目录)。

只要保存房间时建筑物存在,我的覆盖保存方法就可以正常工作。但是,如果尚未保存建筑物,并且我正在通过 django 管理员向建筑物添加房间,则图像仍保留在上传目录中,因为该建筑物的 pk 尚不存在。

我最初尝试覆盖建筑物的保存并将任何房间图像移动到新创建的建筑物目录(再次关闭建筑物的 pk)。尽管 super(Building, self).save(*args, **kwargs) 首先没有设置 Building 的 id。

然后我决定 post_save 信号可能更干净,并且这样做了。不幸的是,该 id 似乎也不存在于帖子保存中。我可以尝试打印 ID 并在触发后保存时看不到任何值,直到我第二次保存模型。

有人可以向我指出一个方向,可以解释为什么 id 没有像其他 SO 答案中所接受的预期输出那样设置吗?

谢谢。

编辑:

这是评论中要求的一些代码。因为我简化了最初的问题,所以我在这里包含更多内容。这里有 3 个级别,一个带有房间的建筑物列表。该清单是我尝试通过该print kwargs['instance']行简单打印的内容。在底部,我包含了两次背靠背保存后的输出。请注意在第一次保存后完全没有实例存在。这些实际上是背靠背的,中间没有任何动作。对 Building_Room 之类的东西的引用是通过表来实现的。除了数据字段之外,RoomImage、BuildingImage 和 ListingImage 都是相似的,因此我只包括了一个。

class Listing(models.Model):
    ...
    buildings = models.ManyToManyField('Building', null=True, blank=True, through = 'Building_Listing')
    addresses = models.ManyToManyField(Address, null=True, blank=True)
    def __unicode__(self):
        return '  &  '.join([a.__unicode__() for a in self.addresses.all()])

class Building(models.Model):
    ...
    rooms = models.ManyToManyField('Room', null=True, through="Building_Room")
    def __unicode__(self):
        return self.description

class Room(models.Model):
    ...
    def __unicode__(self):
        return str(self.room_type)

class RoomImage(models.Model):
    room = models.ForeignKey(Room)
    room_photo = FileBrowseField("Image", max_length=200, blank=True, null=True)

    def save(self, *args, **kwargs):
        try:
            listing = Building_Listing.objects.get(building=Building_Room.objects.get(room=self.room).building).listing
            self.room_photo = moveFileBeforeSave(listing, self.room_photo)
        except Building_Listing.DoesNotExist:
            pass
        except Building_Room.DoesNotExist:
            pass
        super(RoomImage, self).save(*args, **kwargs)

@receiver(post_save, sender=Listing, weak=False)
def save_images_on_listing_create(sender, **kwargs):
    #if kwargs['created']:
    listing = kwargs['instance']
    print kwargs['instance']
    listing_image_list = ListingImage.objects.filter(listing = listing)
    listing_buildings = Building_Listing.objects.filter(listing = listing).values_list('building', flat=True)
    building_image_list = BuildingImage.objects.filter(building__in = listing_buildings)
    building_rooms = Building_Room.objects.filter(building__in = listing_buildings).values_list('room', flat=True)
    room_image_list = RoomImage.objects.filter(room__in = building_rooms)
    for image in listing_image_list:
        image.save()
    for image in building_image_list:
        image.save()
    for image in room_image_list:
        image.save()

@receiver(post_save, sender=Building, weak=False)
def save_images_in_building_create(sender, **kwargs):
    #if kwargs['created']:
    print str(kwargs['instance'])+" : building save trigger"
    building = kwargs['instance']
    building_image_list = BuildingImage.objects.filter(building = building)
    building_rooms = Building_Room.objects.filter(building = building).values_list('room', flat=True)
    room_image_list = RoomImage.objects.filter(room__in = building_rooms)
    for image in building_image_list:
        image.save()
    for image in room_image_list:
        image.save()

一些输出:

[30/Oct/2011 19:52:05] "POST /admin/mls/building/add/?_popup=1 HTTP/1.1" 200 97
# This is the print of the instance kwarg after the first save (ie nothing)
[30/Oct/2011 19:52:10] "POST /admin/mls/listing/add/ HTTP/1.1" 302 0
[30/Oct/2011 19:52:10] "GET /admin/mls/listing/8/ HTTP/1.1" 200 72495
[30/Oct/2011 19:52:10] "GET /admin/jsi18n/ HTTP/1.1" 200 2158
1 Ben Blvd sometown, MN #this is the print of the instance kwarg after the second save
[30/Oct/2011 19:52:12] "POST /admin/mls/listing/8/ HTTP/1.1" 302 0
[30/Oct/2011 19:52:13] "GET /admin/mls/listing/8/ HTTP/1.1" 200 72497
[30/Oct/2011 19:52:13] "GET /admin/jsi18n/ HTTP/1.1" 200 2158
4

2 回答 2

2

好的,所以问题看起来是因为您使用的多对多关系。看看这些帖子:

在 django 问题中保存多对多关系

保存后多对多关系未立即更新的问题

我会考虑重构您的代码以改变建筑物与其房间之间的关系。目前,您在说“有很多房间,而建筑物可以将自己与其中的许多房间相关联”。此外,两个建筑物可以与同一个房间相关联。这真的没有意义。实际上,一个房间应该与一个且只有一个建筑物相关联,即

class Building(models.Model):
    name = models.CharField(...)
    ...

class Room(models.Model):
    building = models.ForeignKey(Building, unique=True)
    ....

这意味着任何房间只能连接到一栋特定的建筑物。

于 2011-10-31T01:29:46.940 回答
0

首先,pastylegs 是对的,他的答案更好。但是,如果由于某种原因(就像我现在一样)由于某种原因而无法更改代码并且发现自己在 post_save 模型实例中不存在像我们在过去几天中发现自己的问题,那么以下想法可能会有所帮助。

在我们的例子中,多对多通表对于 post_save 来说已经足够了。通过将 post save 信号附加到 through 表本身,我们基本上能够捕捉到我们需要为其执行 post_saving 的所有情况,并且作为两个连接表的 id 以用于通过表中存在的多对多关系,这足以获得完成的工作。因此,如果您出于类似的原因发现自己在这里,您可以将 post_save 附加到直通表吗?

再一次,pastylegs 是对的,但如果你因为某种原因不能做同样的事情,我希望这会有所帮助。

于 2011-10-31T04:21:10.620 回答