【问题标题】:How to save a ManyToMany field with a through relationship如何保存具有直通关系的多对多字段
【发布时间】:2015-10-30 00:07:43
【问题描述】:

我有以下具有ManyToManythrough 关系的模型:

class Meeting(models.Model):
    site = models.ForeignKey(Site)
    meeting_title = models.CharField(default='', max_length=128, blank=True, null=True)
    meeting_visitors = models.ManyToManyField(Visitor, through="MeetingArrival", blank=False, null=False) 

class Visitor(models.Model):
    visitor_company = models.ForeignKey(Company)
    visitor_name = models.CharField(default='', max_length=128, blank=False, null=False)

class MeetingArrival(models.Model):
    visitor = models.ForeignKey(Visitor)
    meeting = models.ForeignKey(Meeting)
    arrival_status = models.BooleanField(default=False)

我有一个创建会议的表格:

class AddMeetingForm(forms.ModelForm):

    class Meta:
        model = Meeting
        exclude = ['site',]

以及保存表单的简单视图:

def add_meeting(request): 
    add_meeting_form = AddMeetingForm(request.POST or None)
    site = Site.objects.get(user=request.user.id)

    if request.method == "POST":
        if add_meeting_form.is_valid():

            obj = add_meeting_form.save(commit=False)
            obj.site = site
            obj.save()

这会保存表单,但不会保存 meeting_visitors 字段,即使此字段在视图中完美呈现。我该如何挽救这段关系?

编辑

如果我将add_meeting_form.save_m2m() 添加到视图中,我会得到Cannot set values on a ManyToManyField which specifies an intermediary model. Use meetings.MeetingArrival's Manager instead.。我该怎么做?

【问题讨论】:

    标签: django django-models django-forms django-views many-to-many


    【解决方案1】:

    您必须在视图中显式保存MeetingArrival 对象,以在ManyToManyField 带有through 参数的情况下保存中间模型。

    对于 Django 2.1 及以下版本,如果 ManyToManyField 带有中间模型,则不能使用普通多对多字段可用的 addcreateassignment

    根据Django 1.8 docs:

    与普通的多对多字段不同,您不能使用 add、create 或 创建关系的任务。

    创建这种关系的唯一方法是创建 中间模型的实例。

    因此,您必须在视图中显式创建 MeetingArrival 对象。

    你可以这样做:

    def add_meeting(request): 
        add_meeting_form = AddMeetingForm(request.POST or None)
        site = Site.objects.get(user=request.user.id)
    
        if request.method == "POST":
            if add_meeting_form.is_valid():
                obj = add_meeting_form.save(commit=False)
                obj.site = site
                obj.save()
    
                # create an instance of 'MeetingArrival' object
                meeting_arrival_obj = MeetingArrival(meeting=obj, visitor=<your_visitor_object_here>, arrival_status=True)
                meeting_arrival_obj.save() # save the object in the db
    

    【讨论】:

    • 谢谢,我如何获得your_visitor_object_here?表单输入是多选。
    • 我们可以编写逻辑来获取视图中的访问者对象。由于Visitor 是外键,因此您可以找到哪个MeetingArrival 与哪个Visitor 相关,然后使用该Visitor 创建一个MeetingArrival 对象。
    • 谢谢。如果我有另一个不是through 字段的ManyToMany 字段,那么我将如何保存表单?例如` meeting_team_members = models.ManyToManyField(Team, blank=False, null=False)`
    • 您只需通过.add() 即可做到这一点。假设ABCmeeting_team_members 的模型。然后你可以做abc_object.meeting_team_members.add(team_object)
    【解决方案2】:

    对于 django 1.x,正如 Rahul 所说,您不能使用 addcreate

    对于 django 2.x,您实际上可以在此处查看文档 django 2.x

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

    beatles.members.add(john, through_defaults={'date_joined': date(1960, 8, 1)})
    beatles.members.create(name="George Harrison", through_defaults={'date_joined': date(1960, 8, 1)})
    beatles.members.set([john, paul, ringo, george], through_defaults={'date_joined': date(1960, 8, 1)})
    

    【讨论】:

      【解决方案3】:

      使用表时,需要手动保存。

      MeetingArrival.objects.create( ... )
      

      【讨论】:

      • 谢谢,可以举个例子吗?
      【解决方案4】:

      不要将处理 ManyToManyField 的逻辑放在视图中,而是将其放在表单中,这样如果您在多个地方使用表单,就不必重复自己。

      为此,您需要重写ModelFormsave 方法。

      查看我对另一个问题的更全面的回答:https://stackoverflow.com/a/40822731/2863603

      【讨论】:

        【解决方案5】:

        我是这样做的,仍然试图从选择中获取多个 id 值,我认为我的 javascript 有问题

        但这里是python代码:

        class ArticuloCreateView(View):
            def __init__(self):
                self.template_name = 'articulo/formulario.html'
        
            def get(self, request):
                formulario = ArticuloForm()
                contexto = {
                    'form': formulario,
                    'operation': "Nuevo"
                }
                return render(request, self.template_name, contexto)
        
            @transaction.atomic
            def post(self, request):
                punto_transaccion = transaction.savepoint()
                formulario = ArticuloForm(request.POST)
                almacenes = request.POST.get('almacenes', 0)
                almacenes = Almacen.objects.filter(id=almacenes)
        
                if formulario.is_valid():
                    datos_formulario = formulario.cleaned_data
                    articulo = Articulo()
                    articulo.clave = datos_formulario.get('clave')
                    articulo.descripcion = datos_formulario.get('descripcion')
                    articulo.tipo = datos_formulario.get('tipo')
                    articulo.udm = datos_formulario.get('udm')
                    articulo.clave_jde = datos_formulario.get('clave_jde')
                    articulo.save()
        
                    for almacen in almacenes:
                        Stock.objects.create(articulo=articulo, almacen=almacen)
                    if punto_transaccion:
                        transaction.savepoint_commit(punto_transaccion)
        
                    return redirect(
                        reverse('inventarios.articulos_lista')
                    )
                contexto = {
                    'form': formulario,
                }
        
                return render(request, self.template_name, contexto)
        

        【讨论】:

          【解决方案6】:

          user_profiles = UserProfile.objects.all()

          NotificationUser.objects.bulk_create([NotificationUser(user=user_profile, notification=notification) for user_profiles in user_profiles])

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-03-19
            • 2019-04-24
            • 2015-08-02
            • 2015-04-27
            相关资源
            最近更新 更多