Django 1.11 Прямое присваивание прямой стороне набора «многие ко многим» запрещено.

У меня есть одна модель UserSong, в которой есть два поля m2m с моделями Genre и Language.

class UserSong(models.Model):
    title           = models.CharField(max_length=100)
    song_file       = models.FileField(upload_to=user_song_directory_path, validators=[validate_audio_file_extension])
    genre           = models.ManyToManyField(Genre)
    language        = models.ManyToManyField(Language)

Жанр класс

class Genre(models.Model):
    name            = models.CharField(max_length=255)
    created_date    = models.DateTimeField(auto_now_add=True)
    updated_date    = models.DateTimeField(auto_now=True)
    status          = models.BooleanField(default=False)

Языковой класс

class Language(models.Model):
    name            = models.CharField(max_length=255)
    created_date    = models.DateTimeField(auto_now_add=True)
    updated_date    = models.DateTimeField(auto_now=True)
    status          = models.BooleanField(default=False)

Я пытаюсь добавить поля m2m в объект UserSong как

genre_name_list =  Genre.objects.filter(name__in=self.cleaned_data['genre'].values_list('name',flat=True))
        # instance.genre.add(*genre_name_list)
        instance.genre.set(genre_name_list)

language_name_list =  Language.objects.filter(name__in=self.cleaned_data['language'].values_list('name',flat=True))
        # instance.language.add(*language_name_list)
        instance.language.set(language_name_list)

Проблема здесь заключается в том, что таблица m2m обновляется должным образом, но Django все равно выдает мне ошибку Direct assignment to the forward side of a many-to-many set is prohibited. Use language.set() instead.

Трассировки стека

form.cleaned_data['genre'] <class 'genre.models.Genre'>
artist received is  <QuerySet [<UserProfile: Pragya Nagpal>]>
Internal Server Error: /users/5/25/edit_music
Traceback (most recent call last):
  File "/usr/lib/python3.5/site-packages/django/core/handlers/exception.py", line 35, in inner
    response = get_response(request)
  File "/usr/lib/python3.5/site-packages/django/core/handlers/base.py", line 128, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/usr/lib/python3.5/site-packages/django/core/handlers/base.py", line 126, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/usr/lib/python3.5/site-packages/django/contrib/auth/decorators.py", line 21, in _wrapped_view
    return view_func(request, *args, **kwargs)
  File "/usr/lib/python3.5/site-packages/django/contrib/auth/decorators.py", line 21, in _wrapped_view
    return view_func(request, *args, **kwargs)
  File "/root/new_songdew_store/songdewUser/views.py", line 833, in add_edit_music
    status=model_instance.status)
  File "/usr/lib/python3.5/site-packages/django/db/models/manager.py", line 82, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/usr/lib/python3.5/site-packages/django/db/models/query.py", line 415, in create
    obj = self.model(**kwargs)
  File "/usr/lib/python3.5/site-packages/django/db/models/base.py", line 490, in __init__
    _setattr(self, prop, kwargs[prop])
  File "/usr/lib/python3.5/site-packages/django/db/models/fields/related_descriptors.py", line 509, in __set__
    % self._get_set_deprecation_msg_params(),
TypeError: Direct assignment to the forward side of a many-to-many set is prohibited. Use language.set() instead.

person angrysumit    schedule 26.09.2018    source источник
comment
Ваш код с использованием .set(...) выглядит нормально. Вы уверены, что именно этот код вызывает ошибку? Убедитесь, что вы сохранили/развернули этот код и перезапустили сервер, и включите полную трассировку в свой вопрос.   -  person Alasdair    schedule 26.09.2018
comment
@Alasdair, мне трудно найти это. Как вы сказали, я думаю, что это работает, потому что у меня есть похожие модели UserVideo и Album, и они делают то же самое. Странно то, что это находится на сервере разработки и было протестировано достаточно честно. Но теперь только эта модель выдает ошибку, а не другие. P.S ошибка use language.set() instead иногда меняется на use genre.set() instead.   -  person angrysumit    schedule 26.09.2018
comment
form.cleaned_data в вашем вопросе предполагает, что ошибка возникает раньше, когда вы сохраняете форму. Трассировка покажет вам, где именно происходит ошибка.   -  person Alasdair    schedule 26.09.2018
comment
@Alasdair Я дважды проверил это. Игнорируя тип self.cleaned_data['genre'] (это уже набор запросов, поэтому использование set(self.cleaned_data['genre']) тоже сработает), трассировка стека не дает никакой полезной информации.   -  person angrysumit    schedule 26.09.2018
comment
и, слава богу, таблица m2m все еще обновляется. достаточно смешно, чтобы плакать вслух   -  person angrysumit    schedule 26.09.2018
comment
Пожалуйста, покажите полный add_edit_music вид.   -  person Alasdair    schedule 26.09.2018
comment
@Alasdair ideone.com/9zs8v1 пожалуйста, посмотрите на это   -  person angrysumit    schedule 26.09.2018


Ответы (1)


Трассировка показывает, что ошибка возникает в вызове product_item = Product.objects.create(). Сначала вам нужно создать экземпляр, а затем установить значения для любых полей «многие ко многим»:

product_item = Product.objects.create(...)
product_item.genre.set(...)
person Alasdair    schedule 26.09.2018
comment
в этом преимущество взгляда третьим глазом - person angrysumit; 26.09.2018
comment
Убедитесь, что вы внимательно прочитали трассировку, чтобы убедиться, что вы ищете нужную часть кода. Поскольку вызов Product.objects.create(...) занимает несколько строк, трассировка показывает status=model_instance.status, что не очень полезно, но если вы используете номера строк (или даже ищете status=model_instance.status в своем коде), вы увидите, в чем проблема. - person Alasdair; 26.09.2018
comment
спасибо, мне также пришлось удалить поле списка dict, потому что был назначен пустой список - person franciscorode; 14.02.2020