Django-将两个模型之间的关系呈现为单选按钮

Django-将两个模型之间的关系呈现为单选按钮,django,django-models,django-forms,Django,Django Models,Django Forms,我有以下型号: 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(Pro

我有以下型号:

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\u工厂中使用的

我以如下方式呈现表单集:

<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
的每个实例显示两个单选按钮,而我需要它为每个实例只显示一个单选按钮。我要玩一会儿,看看是否能正确显示出来。

而不是:

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)
那会让你的生活更轻松

如果您无法进行此更改:电话表单集实际上是许多电话表单的包装器。但您要查找的字段允许编辑Profile.primary\u 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 ... ->
我们在这里使用一个布尔字段,因为对于每个电话表单,主字段是要设置还是不设置。但是,您仍然必须自己渲染它:

{% for form in Phones %}
    <input type="checkbox" name="{{ form.prefix }}-primary" checked="{% if form.instance == profile.primary_phone %}checked{% endif %}" value="true" />
    <!-- snip ... ->
当然,您应该更新上述示例中的选择器,以确保只影响“主电话”复选框

最后,要连接复选框,类似这样的操作可能会起作用:

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()

这确实有效,对于空的
Phone
表单
value
None
,因此我可以在发出
POST
请求时处理它们,并检查它们是否有值。我希望少一些自定义编码/多一些django风格的方式。我喜欢你的第一种方式!我可以更改模型,但是现在当我尝试渲染每个
手机
实例的单选按钮时,它会为每个实例显示两个单选按钮(true/false)。我会在一分钟内编辑我的帖子,告诉你我的意思。
{% for form in Phones %}
    <input type="checkbox" name="{{ form.prefix }}-primary" checked="{% if form.instance == profile.primary_phone %}checked{% endif %}" value="true" />
    <!-- snip ... ->
$('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()