Лучший способ объединить дубликаты в Django 1.3? - PullRequest
2 голосов
/ 14 января 2012

Я нашел этот код http://djangosnippets.org/snippets/2283/, но я думаю, что он не работает со многими полями множества, которые используют другую модель (ключевое слово через) - я получаю AttributeError при попытке слияния.

Знаете ли вы, как исправить тот или иной метод объединения объектов?

Редактировать: подробнее

У меня есть 3 модели: A, B, C

A имеет множество полей "m2mfield", указывающих от C до B.

Когда я запускаю код из фрагментов django, он завершается ошибкой, за исключением

'ManyRelatedManager' object has no attribute 'remove'

Я думаю, что это как-то связано с комментарием в источнике Django (django.db.models.fields.related.py, строка 499), в котором говорится:

# If the ManyToMany relation has an intermediary model,
# the add and remove methods do not exist.

Я думаю, что полученный фрагмент кода не имеет никакого значения для отношений ManyToMany с и без посреднической модели. Вот почему я ищу способ исправить этот код или другой способ достичь того, чего я хочу (слияние).

Ответы [ 2 ]

2 голосов
/ 19 января 2012

Я в конечном итоге изменил код, чтобы обработать случай ManyToMany полей, созданных «через» модель.Вот что нужно изменить:

# Migrate all many to many references from alias object to primary object.
for related_many_object in alias_object._meta.get_all_related_many_to_many_objects():
    alias_varname = related_many_object.get_accessor_name()
    obj_varname = related_many_object.field.name

    # Treatment depends on if the many_to_many field is created through another model
    if getattr(alias_object, alias_varname).through._meta.auto_created:
        if alias_varname is not None:
            # standard case
            related_many_objects = getattr(alias_object, alias_varname).all()
        else:
            # special case, symmetrical relation, no reverse accessor
            related_many_objects = getattr(alias_object, obj_varname).all()
        for obj in related_many_objects.all():
            getattr(obj, obj_varname).remove(alias_object)
            getattr(obj, obj_varname).add(primary_object)
    else:
        related_many_objects = getattr(alias_object, alias_varname).all()

        through_model = getattr(alias_object, alias_varname).through
        through_field_name = None
        for f in through_model._meta.fields:
            if isinstance(f, ForeignKey):
                if f.rel.to == primary_class :
                # f is the field in our 'through' model which points to an instance of primary_class
                    through_field_name = f.name

        for obj in related_many_objects.all():
            kwargs = {
                through_field_name: obj,
            }
            for through_obj in through_model.objects.filter(**kwargs):
                setattr(through_obj, through_field_name, primary_object)
                through_obj.save()
0 голосов
/ 19 января 2012

Ошибка, которую вы имеете, означает, что многие поля, которые вы пытаетесь заполнить, управляются сквозной моделью.

В фрагменте вы вставили код, который должен быть через осведомленные модели чтобы слияние сработало, начинается L55:

    # Migrate all many to many references from alias object to primary object.
    for related_many_object in alias_object._meta.get_all_related_many_to_many_objects():
        alias_varname = related_many_object.get_accessor_name()
        obj_varname = related_many_object.field.name

        if alias_varname is not None:
            # standard case
            related_many_objects = getattr(alias_object, alias_varname).all()
        else:
            # special case, symmetrical relation, no reverse accessor
            related_many_objects = getattr(alias_object, obj_varname).all()
        for obj in related_many_objects.all():
            getattr(obj, obj_varname).remove(alias_object)
            getattr(obj, obj_varname).add(primary_object)  # this can't work

Вы должны предоставить merge_model_objects словарь функций, в котором merge_model_objects сможет выбрать функцию для построения сквозного класса.Скорее всего, этот код должен заменить последнюю строку фрагмента, который я взял выше.

Но вы также должны позаботиться о том, чтобы A1, A2 и C1, C2 могли быть равны, в то время как B1, B2 не совпадают 't, который текущий код тоже не обрабатывает.

...