Метод добавления не работает при попытке установить отношения m2m с помощью post_save в Django

Моя модель Content имеет отношение many-to-many к модели Tag. Когда я сохраняю объект Content, я хочу динамически добавлять отношения. Я делаю это следующим образом.

def tag_content(obj):
    for tag in Tag.objects.all():
        print tag
        obj.tags.add(tag)
    obj.is_tagged = True
    obj.save()

class Tag(models.Model):
    name = models.CharField(max_length=255)

class Content(models.Model):
    title = models.CharField(max_length=255)
    is_tagged = models.BooleanField(default=False)
    tags = models.ManyToManyField(Tag, blank=True)

    def save(self, *args, **kwargs):
        super(Content, self).save(*args, **kwargs)

@receiver(post_save, sender = Content)
def update_m2m_relationships_on_save(sender, **kwargs):
    if not kwargs['instance'].is_tagged:
        tag_content(kwargs['instance'])

Функция tag_content выполняется, однако связи m2m не устанавливаются. Я использую Django 1.9.8, кстати. Это не имеет никакого смысла. Что мне не хватает? Более того, если я делаю что-то вроде tag_content(content_instance) в оболочке, то теги устанавливаются, так что функция в порядке. Думаю проблема в ресивере. Любая помощь?

Изменить

Мой вопрос не имеет ничего общего с m2m_changed, как я уже сказал, создание объекта Content в оболочке работает отлично. Следовательно, проблема кроется в настройке админки.


person darkhorse    schedule 23.08.2016    source источник
comment
Можете ли вы убедиться, что update_m2m_relationships_on_save вызывается и что он получает правильные kwargs? Вот как я бы отладил это лично. Потому что вы, кажется, проверили все остальные части...   -  person shark3y    schedule 23.08.2016
comment
Ага. print tag делает именно это, и да, метод сохранения вызывает метод update_m2m.   -  person darkhorse    schedule 23.08.2016
comment
Попробуйте напечатать kwargs['instance'] и kwargs['instance'].is_tagged перед оператором if в вашем приемнике, чтобы убедиться, что объект и логическое значение соответствуют вашим ожиданиям.   -  person souldeux    schedule 23.08.2016
comment
Я тоже пробовал это, и я получаю правильный экземпляр.   -  person darkhorse    schedule 23.08.2016
comment
Если бы он не сохранял хотя бы поле is_tagged, это был бы цикл обратной связи, потому что вы снова вызываете сохранение. И это зациклится навсегда. Итак, если он распечатывает теги (как вы утверждали), а obj является правильным, и он не зацикливается навсегда. Это спасает. Возможно ли, что вы проверяете устаревшие данные (например, из оболочки). У меня это случилось несколько дней назад ... Просто повторно получите предмет после того, как это будет выполнено, чтобы перепроверить. (стоит попробовать!)   -  person shark3y    schedule 23.08.2016
comment
Возможный дубликат Django - Как сохранить данные m2m через post_save сигнал?   -  person solarissmoke    schedule 24.08.2016
comment
Поля kwargs, is_tagged являются правильными. Я протестировал их с помощью команд печати. Тем не менее, это не работает.   -  person darkhorse    schedule 24.08.2016


Ответы (1)


Итак, я решил проблему. По сути, это как-то связано с тем, как Django обрабатывает свою форму в панели администратора. При попытке добавить содержимое от администратора я оставил поле тегов пустым, думая, что функция tag_content справится с этим. Однако именно в этом и заключалась проблема, так как создание контента из оболочки пометило его просто отлично. Другими словами, изменение панели администратора на что-то вроде этого решило мою проблему:

from django.contrib import admin
from myapp.models import *
from django import forms

class ContentCreationForm(forms.ModelForm):
    class Meta:
        model = Content
        fields = ('title',)

class ContentChangeForm(forms.ModelForm):
    class Meta:
        model = Content
        fields = ('title', 'is_tagged', 'tags')

class ContentAdmin(admin.ModelAdmin):

    def get_form(self, request, obj=None, **kwargs):
        if obj is None:
            return ContentCreationForm
        else:
            return ContentChangeForm


admin.site.register(Tag)
admin.site.register(Content, ContentAdmin)

При попытке создать новый контент отображается только поле «заголовок». Это решает проблему.

person darkhorse    schedule 24.08.2016