2012-03-17 32 views
0

我有以下型号:Django的 - 渲染两款车型之间的关系作为一个单选按钮

class Profile(models.Model): 
    verified = models.BooleanField(default=False) 
    primary_phone = models.OneToOneField('Phone', related_name='is_primary', null=True, blank=True) 

class Phone(models.Model): 
    profile = models.ForeignKey(Profile) 
    type = models.CharField(choices=PHONE_TYPES, max_length=16) 
    number = models.CharField(max_length=32) 

    @property 
    def is_primary(self): 
     return profile.primary_phone == self 

而以下几种形式:

class PhoneForm(ModelForm): 
    class Meta: 
     from accounts.models import Phone 
     model = Phone 
     fields = ('type', 'number',) 

其在modelformset_factory使用。

我渲染表单集是这样的:

<div class="span-13 last"> 
    {{ formset.management_form }} 
    {% for form in Phones %} 
     <div class="span-2">{{ form.type|add_class:'dropdown' }}</div> 
     <div class="span-11 last">{{ form.number|add_class:'phone-number' }}</div> 
     <div class="clearfix"></div> 
    {% endfor %} 
</div> 

现在我要做的就是呈现在模板单选按钮,以反映Phone模型的is_primary财产。有两种方法可以通过Phone模型本身或通过Profile.primary_phone来确定这种关系。但后来我将Phone模型渲染为一个formset,因此循环遍历其实例,因此我试图在PhoneForm字段中包含'is_primary'字段,但它不起作用,因为它是属性。

任何想法如何做到这一点?

更新#1:

我已经使用JPIC方法,并试图呈现primary单选按钮:

class PhoneForm(ModelForm): 
    primary = forms.BooleanField(widget=forms.RadioSelect(choices=((0, 'False'), (1, 'True')))) 

    class Meta: 
     from accounts.models import Phone 
     model = Phone 
     fields = ('primary', 'type', 'number',) 

然而,它显示的Phone每个实例两个单选按钮,而我需要它每个实例只显示一个单选按钮。我打算玩一会儿,看看能否正确显示它。

回答

2

相反的:

class Profile(models.Model): 
    verified = models.BooleanField(default=False) 
    primary_phone = models.OneToOneField('Phone', related_name='is_primary', null=True, blank=True) 

class Phone(models.Model): 
    profile = models.ForeignKey(Profile) 
    type = models.CharField(max_length=16) 
    number = models.CharField(max_length=32) 

你应该有:

class Profile(models.Model): 
    verified = models.BooleanField(default=False) 

    def primary_phone(self): 
     return self.phone_set.get(primary=True) 

class Phone(models.Model): 
    profile = models.ForeignKey(Profile) 
    type = models.CharField(max_length=16) 
    number = models.CharField(max_length=32) 
    primary = models.BooleanField(default=False) 

    def save(self, force_insert=False, force_update=False, using=None): 
     if self.primary: 
      # clear the primary attribute of other phones of the related profile 
      self.profile.phone_set.update(primary=False) 
     self.save(force_insert, force_update, using) 

这将使您的生活更轻松。

如果您无法进行此更改:Phone formset实际上是许多Phone表单的包装。但是你之后的字段允许编辑Profile.primary_phone。

这样做的一种方式是手工做它是这样:

{% for form in Phones %} 
    <input type="radio" name="primary_phone" checked="{% if form.instance == profile.primary_phone %}checked{% endif %}" value="{{ form.instance.pk }}" /> 
    <!-- snip ... -> 

但问题是,无线电不会对空电话形式的值,因为该值{{ form.instance.pk }}

做的另一种方式是一个复选框添加到PhoneForm:

from django import forms 

from accounts.models import Phone 

class PhoneForm(forms.ModelForm): 
    primary = forms.BooleanField(required=False, default=False) 

    class Meta: 
     model = Phone 
     fields = ('type', 'number',) 

我们在这里使用BooleanField,因为每个电话的形式,主要是要设置与否。但尽管如此,你必须自己使它:

{% for form in Phones %} 
    <input type="checkbox" name="{{ form.prefix }}-primary" checked="{% if form.instance == profile.primary_phone %}checked{% endif %}" value="true" /> 
    <!-- snip ... -> 

但是,你需要JavaScript才能确保只有一个收音机的时候,例如检查使用jQuery:

$('input[type=checkbox]').change(function() { 
    $('input[type=checkbox][checked=checked]').attr('checked', ''); 
    $(this).attr('checked', 'checked'); 
}); 

当然,您应该更新在这个例子中,选择上面,以确保只有“主电话”复选框受到影响。

最后,连接复选框,这样的事情可能工作:

class PhoneForm(forms.ModelForm): 
    primary = forms.BooleanField(required=False) 

    def __init__(self, *args, **kwargs): 
     super(PhoneForm, self).__init__(*args, **kwargs) 

     if self.instance.is_primary: 
      self.data['primary'] = True 

    def save(self, *args, **kwargs): 
     super(PhoneForm, self).save(*args, **kwargs) 

     if self.cleaned_data['primary']: 
      self.profile.primary_phone = self 
      self.profile.save() 
+0

这不工作,空'Phone'形式'value'是'None'这样我就可以对其进行处理时,这是一个' POST'请求​​并检查它们是否有值。我希望尽量少用自定义编码/更多Django风格的方式。 – abstractpaper 2012-03-17 11:25:01

+0

我喜欢你的第一个方法!我很好地修改模型,但是现在当我尝试渲染每个“Phone”实例的单选按钮时,它会为每个实例显示两个单选按钮(true/false)。我将在一分钟内编辑我的帖子,向你展示我的意思。 – abstractpaper 2012-03-17 21:59:48