如何通过带有manytomany字段的Django表单编辑/更新模型?

时间:2015-09-04 11:24:47

标签: python django forms django-crispy-forms manytomanyfield

在编辑/更新具有manytomany字段的表单时,我遇到了一个问题。我不知道如何实现保存具有manytomany字段的表单的逻辑。模型Sam是一个用户,他管理不同的帐户,并且在一段时间内他管理的帐户发生变化。因此,应该灵活地添加或删除他通过Samprofileupdateform管理的帐户,其中包括Account的多个字段。你能帮我解决一下这个问题吗?

models.py

class Account(models.Model):
   accnt_nagp = models.CharField(max_length=30, unique=True, primary_key=True)
   #sam_name = models.ManyToManyField(Sam)
   def __unicode__(self):
     return  self.accnt_nagp

class Sam(models.Model):
    SUNNYVALE = 'SVL'
    NORTHCAROLINA = 'RTP'
    EUROPE = 'EMEA'
    INDIA = 'NB'
    AUSTRALIA = 'AUS'
    suppaccntmgr = 'SAM'
    MANAGER = 'SAM_MGR'
    REGION_CHOICES = (
       (SUNNYVALE, 'Sunnyvale'),
       (NORTHCAROLINA, 'RTP'),
       (EUROPE,'EMEA'),
       (INDIA,'NB'),
       (AUSTRALIA,'AUS'),
      )
    DESIGNATION_CHOICES = (
       (suppaccntmgr, 'SAM'),
       (MANAGER, 'SAM_MGR'),
      )
    user = models.OneToOneField(User)
    designation = models.CharField(max_length=8, choices=DESIGNATION_CHOICES, 
                        default=suppaccntmgr)
    mgr = models.ForeignKey(SamMgr)
    accnt = models.ManyToManyField(Account)

    def __unicode__(self):
        return u'%s' % self.user.username

Views.py:

class SamProfileUpdateView(views.LoginRequiredMixin, UpdateView):
    model = Sam
    form_class = SamProfileUpdateForm
    success_url = reverse_lazy('risklist')
    template_name = 'samrunbook/samaccntassociate.html'

forms.py

class SamProfileUpdateForm(forms.ModelForm):
    class Meta:
       model = Sam
       fields = ('accnt','mgr')
    def __init__(self, *args, **kwargs):
       super(SamProfileUpdateForm, self).__init__(*args, **kwargs)
       self.helper = FormHelper(self)
       self.helper.form_method = 'POST'
       self.helper.form_class = 'form-horizontal'
       self.helper.label_class = 'col-md-3'
       self.helper.field_class = 'col-md-6'
       self.helper.layout = Layout(
            'accnt',
            'mgr',
          FormActions(
                Submit('map', 'Map Your Account', css_class="btn-primary col-md-offset-3 col-md-6")
                )
        )

templates.py

{% extends 'samrunbook/base_risk.html' %}
{% load crispy_forms_tags %}

{% block content %}
<h3 class="col-md-offset-5">Login | Risk Register</h3>
{% csrf_token %}
{% crispy form %}
{% endblock %}

3 个答案:

答案 0 :(得分:1)

如果我正确理解您的问题:您想要显示具有ManyToMany字段的模型的表单。问题是如果Sam有3个帐户,你想要显示3个字段,但它可能更少或更多。

我最近做了类似的事情。在表单的init中,查询此模型拥有的帐户并循环结果以将每个对象添加到self.fields数组

query = ... # query Sam's accounts
for account in query:
    self.fields[account.accnt_nagp] = forms.IntegerField(...)

答案 1 :(得分:1)

您应该使用模型formset来添加/删除相关帐户。

https://docs.djangoproject.com/en/1.8/topics/forms/modelforms/#model-formsets

答案 2 :(得分:1)

我创建了此自定义视图功能,以创建/更新/编辑管理多个帐户/客户的用户配置文件。我是通过Intermediate模型来创建Sam和Account两个模型之间的ManytoMany关系。中间模型是SamAccount。请在下面找到模型,视图功能和表格的代码。这个问题现在已经解决了。

表单AccountMapForm:

class AccountMapForm(forms.Form):
    account_nagp = forms.CharField()

    def __init__(self, *args, **kwargs):
       super(AccountMapForm, self).__init__(*args, **kwargs)
       self.helper = FormHelper()
       self.helper.form_class = 'form-horizontal'
       self.helper.label_class = 'col-md-4'
       self.helper.field_class = 'col-md-6'
       self.helper.layout = Layout(
           Field('account_nagp', css_class='input-xlarge'),
           FormActions(
              Submit('save_changes', 'Map', css_class='btn-primary col-md-offset-1 col-md-4'),
              Submit('un_map', 'UnMap', css_class='btn-primary col-md-offset-1 col-md-4'),
            )
        )

查看功能:

def account_map(request, slug):
   user_id = slug
   sam = Sam.objects.get(user_id=user_id)
   sam_check = SamAccount.objects.filter(sam=sam)
   message_account_map = "Please enter the Account Nagp you want to Map to your Profile"
   message_account_unmap = "Account is succesfully UnMapped"
   message_account_map_success = 1
   message_account_unmap_success = 1
   if 'save_changes' in request.POST:
       print "yes save_changes is there"
   if 'un_map' in request.POST:
       print "Yes Unmap is there"
   if request.method == 'POST':
       form = AccountMapForm(request.POST)
       if form.is_valid():
          user_id = slug
          account_from_form = form.cleaned_data['account_nagp']
          try:
            account = Account.objects.get(accnt_nagp=account_from_form)
            try:
                if 'save_changes' in request.POST:
                    account = SamAccount.objects.get(sam=sam, account=account_from_form)
                    message_account_map = "Account is already Mapped"
                    message_account_map_success = 0 # To get the color change for the Warning
                else:
                    SamAccount.objects.get(sam=sam, account=account_from_form).delete()
                    message_account_unmap_success = 0
            except ObjectDoesNotExist:
                if 'save_changes' in request.POST:
                    SamAccount.objects.create(sam=sam, account=account)
                    message_account_map = "Account is succesfully Mapped to your profile"
                else:
                    message_account_unmap = "The requested Account was not mapped to your profile"
                    message_account_unmap_success = 1
          except ObjectDoesNotExist:
            account = Account.objects.create(accnt_nagp=account_from_form)
            SamAccount.objects.create(sam=sam, account=account)
            message_account_map = "Created the Account and succesfully Mapped to your profile"
   else:
      form = AccountMapForm()
      template = loader.get_template('book/account_map.html')
      context = RequestContext(request, {
            'form' : form,
            'message_account_map' : message_account_map,
            'message_account_unmap' : message_account_unmap,
            'message_account_map_success' : message_account_map_success,
            'message_account_unmap_success' : message_account_unmap_success,
    })
   return HttpResponse(template.render(context))

模特账号:

class Account(models.Model):
   """Each Account Can have multiple SAMs"""
   accnt_nagp = models.CharField(max_length=30, unique=True, primary_key=True)
   sam_name = models.ManyToManyField('Sam', related_name='managed_by', through='SamAccount')
   def __unicode__(self):
模特萨姆:

class Sam(models.Model):
   """Sam can have Multiple Accounts"""
   SUNNYVALE = 'SVL'
   NORTHCAROLINA = 'RTP'
   EUROPE = 'EMEA'
   INDIA = 'NB'
   AUSTRALIA = 'AUS'
   ROLE = 'SAM'
   MANAGER = 'SAM_MGR'
   REGION_CHOICES = (
    (SUNNYVALE, 'Sunnyvale'),
    (NORTHCAROLINA, 'RTP'),
    (EUROPE,'EMEA'),
    (INDIA,'NB'),
    (AUSTRALIA,'AUS'),
    )
  DESIGNATION_CHOICES = (
    (ROLE1, 'SAM'),
    (MANAGER, 'SAM_MGR'),
    )
  user = models.OneToOneField(User)
  designation = models.CharField(max_length=8, choices=DESIGNATION_CHOICES,     default=ROLE)
  mgr = models.ForeignKey(SamMgr)
  slug = models.SlugField(max_length=255)
  accnt = models.ManyToManyField(Account, related_name='accounts_managed', through='SamAccount')

  def __unicode__(self):
      return u'%s' % self.user.username

中间模型,用于处理两个模型之间的ManyToMany关系。如果必须在两个模型之间创建关系,我所要做的就是在中间模型中为相应的外键字段创建一个对象。

中级模特SamAccount:

class SamAccount(models.Model):
   account = models.ForeignKey('Account', on_delete=models.CASCADE)
   sam = models.ForeignKey('Sam', on_delete=models.CASCADE)

   def __unicode__(self):
       return u'%s' % self.account