【问题标题】:Django 1.11 Direct assignment to the forward side of a many-to-many set is prohibitedDjango 1.11 禁止直接分配到多对多集合的前端
【发布时间】:2019-03-02 03:46:30
【问题描述】:

我有一个模型 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)

我正在尝试将 UserSong 对象中的 m2m 字段添加为

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.

【问题讨论】:

  • 您使用 .set(...) 的代码看起来没问题。您确定是导致错误的代码吗?确保您已保存/部署该代码并重新启动服务器,并在您的问题中包含完整的回溯。
  • @Alasdair ,我很难找到这个。正如您所说,我认为它可以正常工作,因为我有类似的模型UserVideoAlbum,它们也一样。奇怪的是,这是在开发服务器中,并且经过了足够公平的测试。但是现在只有这个模型会抛出错误,而不是其他模型。 P.S 错误 use language.set() instead 有时会随着 use genre.set() instead 而变化。
  • 您问题中的form.cleaned_data 表明该错误在您保存表单时较早发生。回溯将准确显示错误发生的位置。
  • @Alasdair 我仔细检查了它。忽略self.cleaned_data['genre'] 类型(它已经是一个查询集,所以使用set(self.cleaned_data['genre']) 也可以),stacktrace 不会提供任何有用的信息。
  • 天哪,m2m 表仍在更新中。有趣到可以大声哭泣

标签: django m2m


【解决方案1】:

回溯显示错误发生在product_item = Product.objects.create() 调用中。您需要先创建实例,然后为任何多对多字段设置值:

product_item = Product.objects.create(...)
product_item.genre.set(...)

【讨论】:

  • 这就是第三眼视图的好处
  • 确保您仔细阅读了回溯,这样您就可以确定您正在查看代码的正确部分。因为Product.objects.create(...) 调用是多行的,所以回溯显示status=model_instance.status 这不是很有用,但是如果您使用行号(或者甚至在代码中搜索status=model_instance.status),您会看到问题是。
  • 谢谢,我还不得不删除 dict 的列表字段,因为分配了一个空列表
猜你喜欢
  • 1970-01-01
  • 2019-02-18
  • 2018-12-03
  • 1970-01-01
  • 2021-07-01
  • 2018-10-05
  • 2020-03-21
  • 2020-04-02
  • 1970-01-01
相关资源
最近更新 更多