2

単一のモデルに関連する複数のモデルがあります。これらのモデルの保存時に、メイン モデルの pk をキーとするディレクトリに OS 上のファイルを配置するために、メイン モデルの ID を取得するために save をオーバーライドしました。

たとえば、多くの部屋がある建物を考えてみましょう。部屋の画像はすべて、建物の ID をキーとするディレクトリに保存されます (部屋のサブディレクトリはありません)。

部屋が保存されたときに建物が存在する限り、オーバーライドされた保存メソッドは正常に機能します。ただし、建物がまだ保存されておらず、django admin を介して建物に部屋を追加している場合、建物の pk がまだ存在しないため、画像はアップロード ディレクトリに残ります。

最初に、建物の保存を上書きし、部屋の画像を新しく作成された建物ディレクトリに移動しようとしました(再び建物の pk をキーオフしました)。super(Building, self).save(*args, **kwargs) にもかかわらず、最初に建物の ID が設定されていませんでした。

次に、とにかく post_save シグナルがおそらくよりクリーンであると判断し、そのようにしました。残念ながら、ID は投稿保存にも存在しないようです。ID を印刷しようとしても、モデルを 2 回目に保存するまでポスト保存がトリガーされたときに値が表示されません。

この他の SO 回答で受け入れられた出力が期待されるように id が設定されていない理由を説明する方向に誰かが私を向けることができますか?

ありがとう。

編集:

コメントで要求されたコードを次に示します。最初の質問を単純化したので、ここにもう少し含めます。ここには 3 つのレベルがあり、部屋のある建物のリストです。リストは、私が行を介して単純に印刷しようとしたものですprint kwargs['instance']. 下部には、2 回連続して保存した後の出力が含まれています。最初の保存後にインスタンスが完全に存在しないことに注意してください。これらは文字通り背中合わせで、間にアクションはありませんでした。Building_Room などへの参照は、テーブルを介して行われます。RoomImage、BuildingImage、および ListingImage は、データ フィールドを除けばすべて似ているため、1 つだけ含めました。

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の問題で多対多の関係で保存する

ManyToMany リレーションシップが保存後すぐに更新されない問題

建物と部屋の関係を変更するために、コードをリファクタリングすることを検討します。現時点では、「多くの部屋があり、建物はそれらの部屋の数に関連付けることができます」と言っています。さらに、2 つの建物を同じ部屋に関連付けることができます。これは本当に意味がありません。実際には、部屋は 1 つのビルディングにのみ関連付ける必要があります。つまり、

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

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

これは、どの部屋も特定の 1 つの建物にしかリンクできないことを意味します。

于 2011-10-31T01:29:46.940 に答える
0

まず、pastylegs は正しく、彼の答えはより優れています。しかし、何らかの理由で (現在の私のように) なんらかの理由でコードを変更できず、post_save モデル インスタンスに存在しない問題が発生した場合は、過去数日間に発見されたように、次のアイデアが役立つ可能性があります。

私たちの場合、post_save にはテーブルを介した多対多で十分でした。スルー テーブル自体にポスト セーブ シグナルをアタッチすることで、基本的には、ポスト セービングを実行する必要があるすべてのケースをキャッチすることができました。また、多対多関係の 2 つの接続されたテーブルの ID がスルー テーブルに存在するため、これを取得するのに十分でした。仕事が終わった。同様の理由でここにいる場合は、代わりに post_save をスルー テーブルにアタッチできますか?

繰り返しますが、pastylegs は正しいですが、何らかの理由で同じことができない場合は、これが役立つことを願っています。

于 2011-10-31T04:21:10.620 に答える