Django 泛型视图 ManyToMany 与"through"模型



我的第一个Django项目遇到了一些问题,这一定是一个常见/易于解决的项目!作为一个背景,我正在构建一个用于跟踪治疗预约的应用程序。除了这一个实例之外,大多数数据结构都相当简单,其中需要一个ManyToMany,并带有一个中介(直通)模型。正如你在下面的models.py中看到的,有三个模型与我遇到的问题有关。联系人模型用于存储客户的联系人详细信息。案例模型是处理一件工作/工作的概念。任何特定案例都可以有多个会话,依此类推。通常情况下,一个案例可能有两个或多个联系人,他们将在他们之间分摊账单。因此,需要使用智能模型的ManyToMany来存储特定联系人将要支付的账单百分比。型号.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()被禁止,以防止由于未保存的相关对象'case'而导致数据丢失"。我的假设是,由于某种原因,表单.save(commit=False)没有返回用于Invoicees_Members模型保存的ID。。。

有什么想法吗?我在这儿弄错了,一定是小事。附言:我试过用self.object代替self.instance,但也遇到了同样的错误。

错误&Stacktrace:

Traceback:
File "C:Python27libsite-packagesdjangocorehandlersbase.py" in get_response
  149.                     response = self.process_exception_by_middleware(e, request)
File "C:Python27libsite-packagesdjangocorehandlersbase.py" in get_response
  147.                     response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:Python27libsite-packagesdjangoviewsgenericbase.py" in view
  68.             return self.dispatch(request, *args, **kwargs)
File "C:Python27libsite-packagesdjangoviewsgenericbase.py" in dispatch
  88.         return handler(request, *args, **kwargs)
File "C:Python27libsite-packagesdjangoviewsgenericedit.py" in post
  256.         return super(BaseCreateView, self).post(request, *args, **kwargs)
File "C:Python27libsite-packagesdjangoviewsgenericedit.py" in post
  222.             return self.form_valid(form)
File "C:UsersdanieDocumentsdjango-projectsoffice_managementofficemanviews.py" in form_valid
  40.           invoicee.save()
File "C:Python27libsite-packagesdjangodbmodelsbase.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'.

可能是ManyToMany关系导致的保存顺序问题。最好先从官方医生那里读一读。。。

每次使用commit=False保存表单时,Django都会添加一个save_m2m()方法添加到ModelForm子类中。手动完成后保存了表单生成的实例,可以调用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

在保存发票实例之前,必须先保存案例模型实例。这个错误是有意义的,因为Django无法知道案例实例的ID,也无法将其作为外键保存在发票模型中。self.instance = form.save(commit=True)。检查这个链接,Django文档中有关于这个错误的解释。

相关内容

  • 没有找到相关文章

最新更新