django 无法在指定中间模型的 ManyToManyField 上设置值。改用管理器

Posted

技术标签:

【中文标题】django 无法在指定中间模型的 ManyToManyField 上设置值。改用管理器【英文标题】:django Cannot set values on a ManyToManyField which specifies an intermediary model. Use Manager instead 【发布时间】:2011-03-06 16:49:41 【问题描述】:

我正在努力在同一张表格上保存两个表格 - 具有 m2m 关系。 我没有成功,我的错误仍然存​​在,例如:无法在指定中间模型的 ManyToManyField 上设置值。改用会员管理器 其中 Membership 是我的“通过表”。

我的代码:

def save_clas-s-room(request):
   clas-s-room_instance = Clas-s-room()
   if request.method == 'POST':
        form = Clas-s-roomForm(request.POST, request.FILES, user = request.user) 
        if form.is_valid():
           new_obj = form.save(commit=False)
           new_obj.user = request.user 
           new_obj.save()
           membership = Membership(member = request.user,clas-s-room=new_obj)
           membership.save() 
           form.save_m2m()
           return HttpResponseRedirect('.')    
   else:
           form = Clas-s-roomForm(user = request.user)     
   return render_to_response('clas-s-room/clas-s-room_form.html', 
           'form': form,

           , 
          context_instance=RequestContext(request))  

我的模型:

class Clas-s-room(models.Model):
     user = models.ForeignKey(User, related_name = 'clas-s-room_creator')
     classname = models.CharField(max_length=140, unique = True)
     date = models.DateTimeField(auto_now=True)
     open_class = models.BooleanField(default=True)
     members = models.ManyToManyField(User,related_name="list of invited members", through = 'Membership')

class Membership(models.Model): 
      accept = models.BooleanField(default=False)
      date = models.DateTimeField(auto_now = True) 
      clas-s-room = models.ForeignKey(Clas-s-room, related_name = 'clas-s-room_membership')
      member = models.ForeignKey(User, related_name = 'user_membership')

我哪里错了?

【问题讨论】:

我现在正在编辑,并添加模型。谢谢! 相关问题在ORM级别有解决方案:***.com/questions/22964448/… 这个问题好像问了两次,看我对另一个的回答:***.com/a/40822731/2863603 【参考方案1】:

如果允许修改class Membership,添加auto_created = True可能会解决您的问题,

class Membership(models.Model): 
    class Meta:
        auto_created = True

在 Django 1.7 中,错误消息更改为“无法在指定中间模型的 ManyToManyField 上设置值”。解决方法是一样的。

注意:这将完全删除您的中间模型,以及所有附加字段。

【讨论】:

这对我有用,但在重置数据库后,出现一个奇怪的错误:关系“app_membership”不存在 当我在添加“自动创建”属性后执行“makemigrations”时,django 想要删除我自己的中间模型类。为什么? @Raphael,这并没有发生在我身上。这可能完全是另一个问题。 (对不起,我的回答可能不是很有帮助,但我想至少给你一个快速的答复。) Django 在使用 auto_created 时确实删除了中间模型。此外,它没有记录在案 - 所以使用它可能不明智。【参考方案2】:

如上所示:

http://docs.djangoproject.com/en/dev/topics/db/models/#intermediary-manytomany

与普通的多对多字段不同,您不能使用添加、创建或赋值(即 beatles.members = [...])来创建关系

我猜您的代码在“form.save_m2m()”行上出错了,这是不必要的,因为您已经手动创建了会员资格。

【讨论】:

如何保存到直通表?我有一个类似的问题,即 save() 不起作用。 我使用的是 Django 1.8,经过将近 2 天的调整,没有任何效果。我已遵循文档中提到的所有步骤(docs.djangoproject.com/en/1.8/topics/db/models/…)。但是没有任何效果,所以最后我决定从源模型(即您的案例中的教室)中删除 M2M 关系,并创建一个中间模型。现在它工作正常,我可以保存和检索相关数据。【参考方案3】:

我在另一个问题上收到了类似的错误消息。我把它贴在这里以防万一它帮助别人。

我在现有模型上添加了一个新的ManyToManyField。此模型用于使用exclude 字段构建的ModelForm

我通过在排除的字段中添加新字段来解决问题。

【讨论】:

【参考方案4】:

从Django 2.2 release 开始,您还可以在字段上指定through_defaults 以便使用添加、创建和赋值:

RelatedManager.add()create()remove()set()get_or_create()、 和 update_or_create() 方法现在允许在多对多上 与中间模型的关系。新的through_defaults 参数用于指定新中间模型的值 实例。

在您的情况下,由于所有字段都已具有默认值,因此它可能仅适用于 2.2。

【讨论】:

有什么使用例子吗?到处都找不到 文档的这一部分有一些例子:docs.djangoproject.com/en/2.2/topics/db/models/…【参考方案5】:

在https://docs.djangoproject.com/en/2.1/topics/db/models/中指定

“与普通的多对多字段不同,您不能使用 add()、create() 或 set() 来创建关系”

这意味着对于 django 2.1 版本,这些方法是不可能的。但是 django 2.2 文档https://docs.djangoproject.com/en/2.2/topics/db/models/ 的同一页告诉我们:

"您也可以使用 add()、create() 或 set() 来创建关系,只要您为任何必填字段指定 through_defaults"

所以只需将 django 更新到 2.2 或更新版本以使用上述方法,并在创建对象时将参数 'through_defaults' 作为 python 字典,其中键作为额外字段名称,值作为默认值。

【讨论】:

以上是关于django 无法在指定中间模型的 ManyToManyField 上设置值。改用管理器的主要内容,如果未能解决你的问题,请参考以下文章

将不在模型中的字段添加到 Django REST 框架中的序列化程序

django模型系统--多对多,一对一以及跨表查询

Django 中间模型中的访问字段

Django - 如何构建适合的中间 m2m 模型? / 最佳实践

如何从中间件中的 Django 请求对象获取视图中使用的模型名称?

Django dumpdata 和 loaddata 不适用于多对多中间模型