我想创建一个表单,允许我从这些模型中为供应商分配服务。由于我使用其他程序使用的DB,因此没有定义M2M关系,因此似乎无法更改它。我也可能错了。
class Service(models.Model):
name = models.CharField(max_length=30L, blank=True)
class ServiceUser(models.Model):
service = models.ForeignKey(Service, null=False, blank=False)
contact = models.ForeignKey(Contact, null=False, blank=False)
class SupplierPrice(models.Model):
service_user = models.ForeignKey('ServiceUser')
price_type = models.IntegerField(choices=PRICE_TYPES)
price = models.DecimalField(max_digits=10, decimal_places=4)
我已创建此表单:
class SupplierServiceForm(ModelForm):
class Meta:
services = ModelMultipleChoiceField(queryset=Service.objects.all())
model = ServiceUser
widgets = {
'service': CheckboxSelectMultiple(),
'contact': HiddenInput(),
}
以下是我开始研究的观点,但没有取得任何成功:
class SupplierServiceUpdateView(FormActionMixin, TemplateView):
def get_context_data(self, **kwargs):
supplier = Contact.objects.get(pk=self.kwargs.get('pk'))
service_user = ServiceUser.objects.filter(contact=supplier)
form = SupplierServiceForm(instance=service_user)
return {'form': form}
我觉得我尝试这样做的方式出了问题。我显示了正确的表单,但没有使用联系人进行实例化,即使供应商已经在service_user中有一些条目,也不会检查复选框。
答案 0 :(得分:0)
您正在Meta类中定义服务。在SupplierServiceForm开始之后立即将它放在外面。至少它应该出现在那里。
编辑:
我误解了你的目标。您似乎想要显示一个只能有1个值的字段的多重选择。您的服务字段将无法存储多个服务。 因此,根据定义,您的ServiceUser只能有一个服务。 如果由于其他应用程序使用它而不想修改数据库,则可以创建与Service有多对多关系的另一个字段。这可能会导致使用旧字段与应用程序的其他部分发生冲突,但如果不修改关系,我就看不到其他方式了。
答案 1 :(得分:0)
我的问题的解决方案确实是在oder中重新定义我的模型,以使用through参数整合缺少的m2m关系。然后我必须使用特殊的init方法调整表单以在复选框中显示所有选定的服务,并使用特殊的save()方法使用m2m关系保存表单。
class Supplier(Contact):
services = models.ManyToManyField('Service', through='SupplierPrice')
class Service(models.Model):
name = models.CharField(max_length=30L, blank=True)
class ServiceUser(models.Model):
service = models.ForeignKey(Service, null=False, blank=False)
supplier = models.ForeignKey(Supplier, null=False, blank=False)
price = models.Decimal(max_digits=10, decimal_places=2, default=0)
这个表格改编自关于浇头和披萨的非常着名的帖子。
class SupplierServiceForm(ModelForm):
class Meta:
model = Supplier
fields = ('services',)
widgets = {
'services': CheckboxSelectMultiple(),
'contact_ptr_id': HiddenInput(),
}
services = ModelMultipleChoiceField(queryset=Service.objects.all(), required=False)
def __init__(self, *args, **kwargs):
# Here kwargs should contain an instance of Supplier
if 'instance' in kwargs:
# We get the 'initial' keyword argument or initialize it
# as a dict if it didn't exist.
initial = kwargs.setdefault('initial', {})
# The widget for a ModelMultipleChoiceField expects
# a list of primary key for the selected data (checked boxes).
initial['services'] = [s.pk for s in kwargs['instance'].services.all()]
ModelForm.__init__(self, *args, **kwargs)
def save(self, commit=True):
supplier = ModelForm.save(self, False)
# Prepare a 'save_m2m' method for the form,
def save_m2m():
new_services = self.cleaned_data['services']
old_services = supplier.services.all()
for service in old_services:
if service not in new_services:
service.delete()
for service in new_services:
if service not in old_services:
SupplierPrice.objects.create(supplier=supplier, service=service)
self.save_m2m = save_m2m
# Do we need to save all changes now?
if commit:
self.save_m2m()
return supplier
这改变了我的第一个模型,并且会在我的旧数据库中弄得一团糟,但至少它可以工作。