Django中如何将Services模型数据复制到ServiceSelect并关联Proposal?
问题解决方案
核心错误原因
ServiceSelect模型的save方法错误调用了Services类的父类方法,导致实例保存逻辑异常。- 表单尝试将
Services实例(或其ID)直接赋值给Proposal的services字段,但该字段要求关联ServiceSelect实例,类型不匹配。 - 表单的验证方法命名错误,未正确处理选中的服务数据。
1. 修复ServiceSelect模型的save方法
原代码中父类调用错误,需替换为对应ServiceSelect类的父类方法:
class ServiceSelect(models.Model): # 字段定义保持不变 title = models.CharField(null=True, blank=True, max_length=100) discription = models.TextField(null=True, blank=True) category = models.CharField(choices=CATEGORY, blank=True, max_length=100) quantity = models.FloatField(null=True, blank=True) price = models.FloatField(null=True, blank=True) paymentTerms = models.CharField(choices=PAYMENT, blank=True, max_length=100) salesTax = models.CharField(choices=SALESTAX, blank=True, max_length=100) uniqueId = models.CharField(null=True, blank=True, max_length=100) slug = models.SlugField(max_length=500, unique=True, blank=True, null=True) date_created = models.DateTimeField(blank=True, null=True) last_updated = models.DateTimeField(blank=True, null=True) def __str__(self): return '{} {}'.format(self.title, self.uniqueId) def get_absolute_url(self): return reverse('product-detail', kwargs={'slug': self.slug}) def save(self, *args, **kwargs): if self.date_created is None: self.date_created = timezone.localtime(timezone.now()) if self.uniqueId is None: self.uniqueId = str(uuid4()).split('-')[4] self.slug = slugify('{} {}'.format(self.title, self.uniqueId)) self.slug = slugify('{} {}'.format(self.title, self.uniqueId)) self.last_updated = timezone.localtime(timezone.now()) # 修复父类调用 super(ServiceSelect, self).save(*args, **kwargs)
2. 重构ServiceSelectForm表单
调整表单逻辑,专注于选择服务模板并创建ServiceSelect实例:
class ServiceSelectForm(forms.Form): services = forms.ChoiceField( label='Choose services to add:', widget=forms.Select(attrs={'class': 'form-control mb-3'}), ) def __init__(self, *args, **kwargs): self.request = kwargs.pop('request') super().__init__(*args, **kwargs) # 动态生成服务选项 service_list = Services.objects.filter(team=self.request.team) service_choices = [('-----', '--Select Services--')] + [(s.uniqueId, s.title) for s in service_list] self.fields['services'].choices = service_choices def clean_services(self): selected_id = self.cleaned_data['services'] if selected_id == '-----': raise forms.ValidationError('Please select a service template') try: return Services.objects.get(uniqueId=selected_id) except Services.DoesNotExist: raise forms.ValidationError('Invalid service selected') def save(self, proposal): # 从模板复制数据创建ServiceSelect实例 service_template = self.cleaned_data['services'] service_select = ServiceSelect.objects.create( title=service_template.title, discription=service_template.discription, category=service_template.category, quantity=service_template.quantity, price=service_template.price, paymentTerms=service_template.paymentTerms, salesTax=service_template.salesTax, ) # 关联到Proposal proposal.services = service_select proposal.save() return service_select
3. 调整视图逻辑
修改视图中表单处理流程,调用重构后的表单方法:
# GET请求初始化表单 if request.method == 'GET': service_form = ServiceSelectForm(request=request) # POST请求处理表单提交 elif request.method == 'POST': service_form = ServiceSelectForm(request.POST, request=request) if service_form.is_valid() and 'service' in request.POST: service_form.save(proposal) messages.success(request, "Service added to Proposal") return redirect('proposals:build_proposal', team_slug=team.slug, slug=slug)
补充说明
- 确保
Proposal模型的services字段为ForeignKey(ServiceSelect, on_delete=models.CASCADE, ...)类型,才能正确关联ServiceSelect实例。 - 若需支持批量添加服务,可将
Proposal的services字段改为ManyToManyField(ServiceSelect, ...),并调整表单和视图逻辑处理批量创建。
内容的提问来源于stack exchange,提问作者Woodhack
相关产品推荐
相关产品推荐

