Общие виды 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.