簡體   English   中英

Django 通用視圖 ManyToMany 與“通過”模型

[英]Django Generic Views ManyToMany with "through" model

我的第一個 Django 項目遇到了一些麻煩,這一定是一個常見/容易解決的問題! 作為一些背景知識,我正在構建一個用於跟蹤治療預約的應用程序。 大多數數據結構都相當簡單,除了這個需要多對多的實例外,還有一個中間(直通)模型。 正如您在下面的 models.py 中看到的那樣,有三個模型與我遇到的問題相關。 Contact 模型用於存儲客戶的聯系方式。 案例模型是處理一件工作/工作的概念。 任何特定的案例都可以有多個會話,依此類推。 通常情況下,一個案例可能有兩個或多個聯系人,他們將在他們之間分攤賬單。 因此,需要使用具有中介模型的多對多來存儲特定聯系人將支付的賬單百分比。 模型.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)。

視圖.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’而導致數據丟失”。 我的假設是,由於某種原因,form.save(commit=False) 沒有返回用於 Invoicees_Members 模型保存的 ID...

有什么想法嗎? 我在這里弄錯了一定是微不足道的事情。 PS 我試過用 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'.

可能是 ManyToMany 關系導致的保存順序問題。 最好先閱讀官方文檔...

每次使用commit=False保存表單時,Django save_m2m()向 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()

通過示例閱讀保存方法的完整文檔這里

您必須在保存發票實例之前保存案例模型實例。 此錯誤是有道理的,因為 Django 無法知道案例實例的 ID,無法將其作為外鍵保存在發票模型中。 self.instance = form.save(commit=True) 並檢查此鏈接Django 文檔中有關於此錯誤的解釋。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM