1

我的问题是:有没有办法创建自定义模型表单,该表单将使用相关模型中的指定字段而不是相关模型的 id?

澄清一下,如果我有以下两个模型:

class ModelOne(models.Model):
  id = models.AutoField(primary_key = True)
  name = models.CharField(unique = True, blank = False, null = False)

class ModelTwo(models.Model):
  id = models.AutoField(primary_key = True)
  parent = models.ForeignKey(ModelOne, blank = False, null = False)
  attribute_1 = models.CharField(blank = False, null = False)
  attribute_2 = models.IntegerField(blank = False, null = False)

现在,如果我使用 ModelForm 在 ModelTwo 上创建一个 UpdateView,那么父字段将预填充来自 ModelOne 的相应 id。但是我希望它显示 ModelOne 的 name 属性,然后在表单提交时将唯一名称(ModelOne)解析为 ModelOne 的相应实例。我想这样做的原因是,我相信从用户的角度来看,处理 ModelOne 的名称(更新 ModelTwo 实例时)而不是它的“id”更直观。

关于我如何做到这一点的任何建议?

4

2 回答 2

1

首先,尝试在 ModelOne 上定义unicode方法。它可能不适用于解决方案,但值得拥有 - 它将驱动表单选择小部件中的文本值......

def __unicode__(self):
    '''Warning: be careful not to use related objects here,
    could cause unwanted DB hits when debugging/logging
    '''
    return self.name

如果这还不够,这样的事情可能会起作用(它改编自我拥有的更新用户名附加到个人资料的表格)......

class M2Form(forms.ModelForm):
    m1_name = forms.CharField()

    class Meta:
        model = ModelTwo

    def save(self, *args, **kw):
        # Update your name field here, something like
        if self.cleaned_data.get('m1_name'):
            self.instance.parent = ModelOne.objects.get(name=self.cleaned_data.get('m1_name'))
            return super(M2Form, self).save(*args, **kw)

这是未经测试的,您可能需要对其进行调整以验证名称是否存在并确保原始父字段不会出现在表单上。运气好的话,第一个答案涵盖了我认为您的问题。

于 2012-06-20T00:59:48.323 回答
0

以 Rog 的回答为起点,深入研究 Django 的一些内部结构,我最终找到了一个可行的解决方案。鉴于我的 Django 知识水平,我想有更好的方法来做到这一点;因此,如果您有其他方法,请添加它。

所以基于以上两种模型,我创建了如下表单类:

class CustomForm(forms.ModelForm):
    parent = models.CharField(label='Name')

    class Meta:
       model = ModelTwo
       exclude = ['parent']

    def __init__(self,*args,**kwargs):
       # The line of code below is the one that I was looking for. It pre-populates 
       # the "parent" field of the form with the "name" attribute of the related 
       # ModelOne instance.
       kwargs['initial']['parent'] = kwargs['instance'].parent.name
       super(CustomForm,self).__init__(*args,**kwargs)
       # The next line is for convenience and orders the form fields in our desired 
       # order. I got this tip from: 
       # http://stackoverflow.com/questions/913589/django-forms-inheritance-and-order-of-form-fields
       self.fields.keyOrder = ['parent','attribute_1','attribute_2']

    def save(self, *args, **kwargs):
       if self.cleaned_data.get('parent'):
       # This section of code is important because we need to convert back from the 
       # unique 'name' attribute of ModelOne to the corresponding instance so that
       # ModelTwo can be saved. Thanks goes to Rog for this section of code.
           self.instance.parent = ModelOne.objects.get(name=self.cleaned_data.get('parent'))
           return super(CustomForm, self).save(*args, **kwargs)
于 2012-06-21T01:33:05.510 回答