Общие виды Django ManyToMany со сквозной моделью

У меня возникли проблемы с моим первым проектом Django, который должен быть простым / легко решаемым! В качестве предыстории я создаю приложение, которое используется для отслеживания назначений терапии. Большая часть структуры данных довольно проста, за исключением одного случая, когда требуется ManyToMany, с промежуточной (сквозной) моделью. Как вы можете видеть в моем файле models.py ниже, есть три модели, которые имеют отношение к моей проблеме. Модель Contact используется для хранения контактных данных клиентов. Модель Case предназначена для работы с понятием работы / работы. В любом конкретном случае может быть несколько сессий и т. Д. Часто в сценариях дела может быть два или более контактов, которые разделят счет между ними. Отсюда необходимость для 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)

Я провел довольно много поисков на stackru и других сайтах о том, как обрабатывать сохранение отправленных форм. Наиболее распространенным решением, по-видимому, является то, что я пытался реализовать ниже. Вы заметите, что я пытаюсь использовать общие представления на основе классов (в данном случае 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 "". Я предполагаю, что по какой-то причине form.save(commit=False) не возвращается с идентификатором, который используется для сохранения модели Invoicees_Members...

Какие-нибудь мысли? Это должно быть что-то тривиальное, что я здесь ошибся. PS Я попытался использовать self.object вместо self.instance и столкнулся с той же ошибкой.

Ошибка и Stacktrace:

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'.

2 ответа

Может быть проблема с последовательностью сохранения, вызванная отношением ManyToMany. Лучше сначала почитать из официального документа...

Каждый раз, когда вы сохраняете форму, используя commit=FalseДжанго добавляет 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()

Читайте полную документацию метода сохранения с примером здесь

Вы должны сохранить экземпляр модели случая перед сохранением экземпляра счета. Эта ошибка имеет смысл, потому что Django не может знать идентификатор экземпляра дела, чтобы иметь возможность сохранить его в модели накладной в качестве внешнего ключа. self.instance = form.save(commit=True), И проверить эту ссылку есть объяснение этой ошибки в документации Django.

Другие вопросы по тегам