Django: слияние объектов

У меня есть такая модель:

class Place(models.Model):
    name = models.CharField(max_length=80, db_index=True)
    city = models.ForeignKey(City)
    address = models.CharField(max_length=255, db_index=True)
    # and so on

Так как я импортирую их из многих источников, и пользователи моего веб-сайта могут добавить новые Места, мне нужен способ объединить их от администраторского интерфейса. Проблема, имя не очень надежно, так как они могут быть записаны по-разному, и т.д. я используюсь для использования чего-то вроде этого:

class Place(models.Model):
    name = models.CharField(max_length=80, db_index=True) # canonical
    city = models.ForeignKey(City)
    address = models.CharField(max_length=255, db_index=True)
    # and so on

class PlaceName(models.Model):
    name = models.CharField(max_length=80, db_index=True)
    place = models.ForeignKey(Place)

запросите как это

Place.objects.get(placename__name='St Paul\'s Cathedral', city=london)

и слияние как это

class PlaceAdmin(admin.ModelAdmin):
    actions = ('merge', )

    def merge(self, request, queryset):
        main = queryset[0]
        tail = queryset[1:]

        PlaceName.objects.filter(place__in=tail).update(place=main)
        SomeModel1.objects.filter(place__in=tail).update(place=main)
        SomeModel2.objects.filter(place__in=tail).update(place=main)
        # ... etc ...

        for t in tail:
            t.delete()

        self.message_user(request, "%s is merged with other places, now you can give it a canonical name." % main)
    merge.short_description = "Merge places"

как Вы видите, я должен обновить все другие модели с FK для Размещения с новыми значениями. Но это - не очень хорошее решение, так как я должен добавить каждую новую модель к этому списку.

Как делают меня "каскадное обновление" все внешние ключи к некоторым объектам до удаления их?

Или возможно существуют другие решения/избежать, объединяясь

6
задан Valentin Golev 3 August 2010 в 03:14
поделиться

1 ответ

Если кому-то интересно, вот общий код для этого:

def merge(self, request, queryset):
    main = queryset[0]
    tail = queryset[1:]

    related = main._meta.get_all_related_objects()

    valnames = dict()
    for r in related:
        valnames.setdefault(r.model, []).append(r.field.name)

    for place in tail:
        for model, field_names in valnames.iteritems():
            for field_name in field_names:
                model.objects.filter(**{field_name: place}).update(**{field_name: main})

        place.delete()

    self.message_user(request, "%s is merged with other places, now you can give it a canonical name." % main)
6
ответ дан 8 December 2019 в 18:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: