代码之家  ›  专栏  ›  技术社区  ›  bchhun

在Django中,使ModelForm与许多中介模型的关系一起工作的步骤是什么?

  •  30
  • bchhun  · 技术社区  · 16 年前
    • 我有一个 顾客 集团 模型。
    • 顾客 可以是多个的一部分 .
    • 客户 这是一个集团的一部分,可以随时使用其集团的免费租金,但只能使用一次。这就是中介模式( 客户群 )提供额外的数据。

    现在,当我试图保存M2M数据时,它就死了,并说我应该使用ClientGroupe管理器……那么缺少什么呢?

    以下是我的模型:

    class Groupe(models.Model):
        nom = models.CharField(max_length=1500, blank=True)
    
    class Client(models.Model):
        nom = models.CharField(max_length=450, blank=True)
        prenom = models.CharField(max_length=450, blank=True)
        groupes = models.ManyToManyField(Groupe, null = True, blank = True, through='ClientGroupe')
    
    class ClientGroupe(models.Model):
        client = models.ForeignKey(Client)
        groupe = models.ForeignKey(Groupe)
        dt = models.DateField(null=True, blank=True) # the date the client is using its group's free rental rate    
    
        class Meta:
            db_table = u'clients_groupes'
    

    我的观点是:

    def modifier(request, id):
        client = Client.objects.get(id=id)    
        form = ClientForm(instance = client)
    
        dict = {
            "form": form
            , "instance" : client
        }
    
        if request.method == "POST":
            form = ClientForm(request.POST, instance = client)
    
            if form.is_valid():
                client_mod = form.save()
    
                id = client_mod.id
                return HttpResponseRedirect(
                    "/client/%(id)s/?err=success" % {"id" : id}
                )
            else:
                return HttpResponseRedirect(
                    "/client/%(id)s/?err=warning" % {"id" : id}
                )
    
        return render_to_response(
            "client/modifier.html"
            , dict
            , context_instance=RequestContext(request)
        )
    

    编辑 :

    这是客户表单代码:

    class ClientForm(ModelForm):
        class Meta:
            model = Client
    

    编辑第2页 : 以下是错误消息:

    AttributeError at /client/445/
    
    Cannot set values on a ManyToManyField which specifies an intermediary model. Use ClientGroupe's Manager instead.
    
    Request Method:     POST
    Request URL:    http://localhost/client/445/
    Exception Type:     AttributeError
    Exception Value:    Cannot set values on a ManyToManyField which specifies an intermediary model.  Use ClientGroupe's Manager instead.
    
    Exception Location:     C:\Python25\lib\site-packages\django\db\models\fields\related.py  in __set__, line 574
    Python Executable:  C:\xampp\apache\bin\apache.exe
    Python Version:     2.5.2
    
    5 回复  |  直到 11 年前
        1
  •  10
  •   Anber    14 年前
    …
    if form.is_valid():
        client_mod = form.save(commit=False)
        client_mod.save()
        for groupe in form.cleaned_data.get('groupes'):
            clientgroupe = ClientGroupe(client=client_mod, groupe=groupe)
            clientgroupe.save()
        …
    
        2
  •  18
  •   Ross Light    16 年前

    如果您现在使用保存方法,Django将尝试使用管理器保存(Django不允许这样做)。不幸的是,你想要的行为比 ModelForm 默认为。你需要做的是创建一个 形式集 .

    首先,您需要更改 ClientForm 这样它就不会显示 groupes 属性。

    class ClientForm(ModelForm):
        class Meta:
            model = Client
            exclude = ('groupes',)
    

    接下来,必须更改视图以显示表单集:

    from django.forms.models import inlineformset_factory
    
    def modifier(request, id):
        client = Client.objects.get(id=id)    
        form = ClientForm(instance = client)
        # Create the formset class
        GroupeFormset = inlineformset_factory(Client, Groupe)
        # Create the formset
        formset = GroupeFormset(instance = client)
    
        dict = {
            "form": form
            , "formset" : formset
            , "instance" : client
        }
    
        if request.method == "POST":
            form = ClientForm(request.POST, instance = client)
            formset = GroupeFormset(request.POST, instance = client)
    
            if form.is_valid() and formset.is_valid():
                client_mod = form.save()
                formset.save()
    
                id = client_mod.id
                return HttpResponseRedirect(
                    "/client/%(id)s/?err=success" % {"id" : id}
                )
            else:
                return HttpResponseRedirect(
                    "/client/%(id)s/?err=warning" % {"id" : id}
                )
    
        return render_to_response(
            "client/modifier.html"
            , dict
            , context_instance=RequestContext(request)
        )
    

    显然,您还必须调整模板以呈现表单集。

    如果您需要有关表单集的任何其他建议,请参阅以下文章:

    Model formsets
    Formsets

        3
  •  4
  •   SingleNegationElimination    16 年前

    您可能需要从客户机模型中删除manytomany字段,或者小心地将其从表单中排除。不幸的是,manyToMany字段的默认小部件无法正确填充ClientGroupe模型(即使丢失的字段dt已设置为autonow=true)。这是您要么需要分解成另一种形式,要么在视图中处理的内容。

        4
  •  0
  •   Vladimir Prudnikov    16 年前

    保存表单时,保存客户端对象。现在,如果要将客户机分配给组,则应执行以下操作:

    clientgroupe = ClientGroupe.objects.create(client=client_instance, groupe=groupe_instance, dt=datetime.datetime.now())
    

    其中client_instance和groupe_instance您的client和groupe objets。

        5
  •  0
  •   hcliff    11 年前

    我提供了一个替代的解决方案,因为我遇到了与表单“无效”不被调用的问题:

    class SplingCreate(forms.ModelForm):
    class Meta:
        model = SplingModel
        fields = ('Link', 'Genres', 'Image', 'ImageURL',)
    
    def save(self, commit=True):
        from django.forms.models import save_instance
    
        if self.instance.pk is None:
            fail_message = 'created'
        else:
            fail_message = 'changed'
        fields = set(self._meta.fields) - set(('Genres',))
        instance = save_instance(self, self.instance, fields,
                                 fail_message, commit, construct=False)
    
        genres = self.cleaned_data.get('Genres')
        for genre in genres:
            SplingGenreModel.objects.get_or_create(spling=instance, genre=genre)
    
        return instance
    

    我已经从djangos forms/models.py复制了逻辑,我的字段类型是许多带有中间表的字段类型-我将其从save_实例中排除,然后单独保存。