我有以下型号:
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
。
我正在渲染这样的formset:
<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>
现在我要做的是在模板中渲染一个单选按钮,以反映is_primary
模型的Phone
属性。有两种方法可以通过Phone
模型本身或Profile.primary_phone
来确定这种关系。但后来我将Phone
模型渲染为formset,因此循环遍历其实例,因此我尝试在'is_primary'
字段中包含PhoneForm
,但由于它是属性,因此无效。
知道怎么做吗?
更新#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
实例显示两个单选按钮,而我需要它每个实例只显示一个单选按钮。我打算玩一会儿,看看我能不能正确显示它。
答案 0 :(得分: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,因为对于每个Phone表单,都要设置primary。但是,你仍然必须自己渲染它:
{% 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()