У меня есть такая модель:
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 для Размещения с новыми значениями. Но это - не очень хорошее решение, так как я должен добавить каждую новую модель к этому списку.
Как делают меня "каскадное обновление" все внешние ключи к некоторым объектам до удаления их?
Или возможно существуют другие решения/избежать, объединяясь
Если кому-то интересно, вот общий код для этого:
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)