我的第一个Django项目遇到了一些麻烦,这个项目必须是一个普通/易于解决的项目!作为一个背景,我正在构建一个用于跟踪治疗预约的应用程序。大多数数据结构都相当简单,除了这一个需要ManyToMany的实例,还有一个intemediary(through)模型。正如您在下面的models.py中所看到的,有三种与我遇到的问题相关的模型。 Contact模型用于存储客户的联系详细信息。案例模型是处理一项工作/工作的概念。任何特定情况都可以有多个会话,依此类推。通常情况下,案例可能有两个或更多个联系人,他们将在它们之间拆分账单。因此,ManyToMany需要使用中介模型来存储特定联系人将支付的账单百分比。 models.py
class Contact(models.Model):
first_name = models.CharField(max_length=200)
last_name = models.CharField(max_length=200)
class Case(models.Model):
invoicees = models.ManyToManyField(Contact, through='Invoicees_Members', through_fields=('case','contact'),null=True, blank=True)
class Invoicees_Members(models.Model):
contact = models.ForeignKey(Contact, on_delete=models.CASCADE)
case = models.ForeignKey(Case, on_delete=models.CASCADE)
invoice_percentage = models.IntegerField(validators = [MinValueValidator(1), MaxValueValidator(100)],null=True, blank=True)
我已经在stackoverflow和其他网站上搜索了很多关于如何处理保存表单提交的内容。最常见的解决方案似乎是我在下面尝试实现的。你会注意到我试图使用基于通用类的视图(在这种情况下是CreateView)。
views.py
class CaseCreate(CreateView):
model = Case
success_url = '/cases/'
fields = '__all__'
def form_valid(self, form):
self.instance = form.save(commit=False)
for contact in form.cleaned_data['invoicees']:
invoicee = Invoicees_Members()
invoicee.case = self.instance
invoicee.contact = contact
invoicee.save()
return super(ModelFormMixin, self).form_valid(form)
不幸的是,表单提交会导致以下错误:"异常值:禁止save()以防止由于未保存的相关对象'案例""而导致数据丢失。我的假设是,由于某种原因,form.save(commit = False)没有返回一个用于Invoicees_Members模型的ID保存...
有什么想法?在这里我犯了错误一定是微不足道的。附:我尝试使用self.object代替self.instance并遇到同样的错误。
错误&堆栈跟踪:
Traceback:
File "C:\Python27\lib\site-packages\django\core\handlers\base.py" in get_response
149. response = self.process_exception_by_middleware(e, request)
File "C:\Python27\lib\site-packages\django\core\handlers\base.py" in get_response
147. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Python27\lib\site-packages\django\views\generic\base.py" in view
68. return self.dispatch(request, *args, **kwargs)
File "C:\Python27\lib\site-packages\django\views\generic\base.py" in dispatch
88. return handler(request, *args, **kwargs)
File "C:\Python27\lib\site-packages\django\views\generic\edit.py" in post
256. return super(BaseCreateView, self).post(request, *args, **kwargs)
File "C:\Python27\lib\site-packages\django\views\generic\edit.py" in post
222. return self.form_valid(form)
File "C:\Users\danie\Documents\django-projects\office_management\officeman\views.py" in form_valid
40. invoicee.save()
File "C:\Python27\lib\site-packages\django\db\models\base.py" in save
651. "unsaved related object '%s'." % field.name
Exception Type: ValueError at /cases/add
Exception Value: save() prohibited to prevent data loss due to unsaved related object 'case'.
答案 0 :(得分:1)
可能是由ManyToMany关系引起的保存顺序问题。最好先从官方文档中读一读......
每次使用
commit=False
保存表单时,Django都会添加一个 ModelForm子类的save_m2m()
方法。手动后 保存了表单生成的实例,您可以调用save_m2m()
保存多对多表单数据。
示例:强>
# Create a form instance with POST data.
>>> f = AuthorForm(request.POST)
# Create, but don't save the new author instance.
>>> new_author = f.save(commit=False)
# Modify the author in some way.
>>> new_author.some_field = 'some_value'
# Save the new instance.
>>> new_author.save()
# Now, save the many-to-many data for the form.
>>> f.save_m2m()
使用示例Here
阅读save方法的完整文档答案 1 :(得分:0)
您必须在保存发票实例之前保存案例模型实例。这个错误是有道理的,因为Django无法知道案例实例的ID能够将其作为外键保存在发票模型上。 self.instance = form.save(commit=True)
。并查看此链接,Django documentation上有关于此错误的说明。