"'BillInvoice' instance needs to have a primary key value before this relationship can be used"
Контекст:
У меня есть представление формы (CreateInvoiceView), который обрабатывает создание счетов и их позиций с использованием набора форм. Соответствующие части моего кода следующие:
Это мой model.py
Профиль пользователя< /strong>
class UserProfile(models.Model):
ROLE = [
('Select Role', 'Select Role'),
('Admin', 'Admin'),
('CBUMT', 'CBUMT'),
('Pharmacist', 'Pharmacist'),
('Doctor', 'Doctor'),
('Nurse', 'Nurse'),
('Referral Provider', 'Referral Provider'),
('Member', 'Memeber'),
('Dependent', 'Dependent'),
]
GENDER = [
('None', 'None'),
('Male', 'Male'),
('Female', 'Female'),
]
user = models.OneToOneField(User, on_delete=models.CASCADE)
id_number = models.CharField(max_length=30, blank=True, null=True)
is_medical_staff = models.BooleanField(default=False)
role = models.CharField(max_length=50, choices=ROLE, default='CBUMT')
gender = models.CharField(max_length=20, choices=GENDER, default='None')
date_of_birth = models.DateField(blank= False, null=False, default=timezone.now)
phone = models.CharField(max_length=20, blank=True, null=True)
qualification = models.CharField(max_length=100, blank=True, null=True)
bio = models.TextField(blank=True, null=True)
profile_pic = models.ImageField(null=True, blank=True, upload_to='images/', default='img/placeholder.jpg')
@property
def age(self):
today = date.today()
age = today.year - self.date_of_birth.year - ((today.month, today.day) < (self.date_of_birth.month, self.date_of_birth.day))
return age
def __str__(self):
return str(self.user) + ' | ' + self.role
**BillInvoice**
class BillInvoice(models.Model):
TYPE_CHOICES = [
('Medicine', 'Medicine'),
('Auxillary', 'Auxillary'),
('Mixed', 'Mixed'),
]
patient = models.ForeignKey(UserProfile, on_delete=models.CASCADE, related_name='invoices', null=True)
invoice_type = models.CharField(max_length=50, choices=TYPE_CHOICES, default='Medicine')
reference = models.ForeignKey(Referral, on_delete=models.CASCADE, related_name='invoice_references', null=True)
amount = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=True)
date = models.DateField(auto_now_add=True)
due_date = models.DateField(null=True, blank=True)
status = models.BooleanField(default=False)
prepared_by = models.ForeignKey(UserProfile, on_delete=models.CASCADE, related_name='prepared_invoices', null=True, blank=True)
def __str__(self):
return f'Invoice for {self.patient} on {self.date}'
def update_amount(self):
total_amount = sum(item.amount for item in self.lineitems.all())
self.amount = total_amount
def get_status(self):
return self.status
def save(self, *args, **kwargs):
if not self.id and not self.due_date:
self.due_date = datetime.now() + timedelta(days=30)
self.update_amount() # Update the amount before saving
super().save(*args, **kwargs)
BillLineItem
class BillLineItem(models.Model):
patient = models.ForeignKey(BillInvoice, on_delete=models.CASCADE, related_name='lineitems')
service = models.TextField()
description = models.TextField()
quantity = models.IntegerField()
rate = models.DecimalField(max_digits=9, decimal_places=2)
amount = models.DecimalField(max_digits=9, decimal_places=2)
def __str__(self):
return str(self.patient)
Mviews.py
CreateInvoiceView
class CreateInvoiceView(FormView):
template_name = 'referral/invoice_create.html'
form_class = BillInvoiceForm
success_url = reverse_lazy('ereferral:invoice-list') # Adjust as needed
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
if self.request.POST:
context['formset'] = LineItemFormset(self.request.POST)
else:
context['formset'] = LineItemFormset()
context['title'] = "Invoice Generator"
context['heading_message'] = 'Formset Demo'
return context
def form_valid(self, form):
context = self.get_context_data()
formset = context['formset']
if formset.is_valid():
# Retrieve the UserProfile instance
patient_profile = form.cleaned_data.get("patient") # Assuming this returns a UserProfile instance
# Save the BillInvoice instance to get the primary key
invoice = BillInvoice(
patient=patient_profile, # Assuming 'patient' is a ForeignKey to UserProfile
invoice_type=form.cleaned_data["invoice_type"],
reference=form.cleaned_data["reference"],
amount=0 # Initial total_amount, will update later
)
invoice.save() # Now the invoice instance has a primary key
total = 0
for item_form in formset:
if item_form.cleaned_data: # Ensure the form is not empty
service = item_form.cleaned_data.get('service')
description = item_form.cleaned_data.get('description')
quantity = item_form.cleaned_data.get('quantity')
rate = item_form.cleaned_data.get('rate')
if service and description and quantity and rate:
amount = float(rate) * float(quantity)
total += amount
BillLineItem.objects.create(
invoice=invoice, # Associating the line item with the invoice
service=service,
description=description,
quantity=quantity,
rate=rate,
amount=amount
)
# Update the total amount of the invoice after creating all line items
invoice.total_amount = total
invoice.save()
try:
generate_PDF(self.request, id=invoice.id)
except Exception as e:
logger.error(f"PDF generation error: {e}")
return super().form_valid(form)
else:
return self.form_invalid(form)
def form_invalid(self, form):
context = self.get_context_data()
formset = context['formset']
logger.error("Form or formset is invalid")
logger.error("Form errors: %s", form.errors)
logger.error("Formset errors: %s", formset.errors)
return self.render_to_response(self.get_context_data(form=form))
# Define the formset outside the view class to avoid redefinition
LineItemFormset = formset_factory(LineItemForm, extra=1)
Сведения об ошибке:
Я столкнулся с ошибкой при попытке сохранить BillLineItem экземпляры. Кажется, что BillInvoiceЭкземпляру не назначен первичный ключ перед попыткой создания BillLineItem экземпляров.
Запрос:
Может кто-нибудь помочь мне определить, что может пойти не так? В частности:
- Есть ли проблема с тем, как я сохраняю BillInvoice экземпляр?
- Необходимы ли какие-либо корректировки в моем представлении или определениях модели, чтобы обеспечить BillInvoiceЭкземпляр сохраняется с первичным ключом перед связыванием BillLineItem экземпляры?
Немедленное сохранение счета: я обязательно сохранил BillInvoice экземпляр сразу после его создания, поэтому ему назначается первичный ключ перед попыткой создания любого BillLineItem экземпляры. Это должно гарантировать, что invoice имеет идентификатор, когда на него ссылаются позиции.
CreateInvoiceView
class CreateInvoiceView(FormView):
template_name = 'referral/invoice_create.html'
form_class = BillInvoiceForm
success_url = reverse_lazy('ereferral:invoice-list')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
if self.request.POST:
context['formset'] = LineItemFormset(self.request.POST)
else:
context['formset'] = LineItemFormset()
context['title'] = "Invoice Generator"
context['heading_message'] = 'Formset Demo'
return context
def form_valid(self, form):
context = self.get_context_data()
formset = context['formset']
if formset.is_valid():
try:
# Save the BillInvoice instance
invoice = form.save(commit=False)
patient_profile = form.cleaned_data.get("patient")
invoice.patient = patient_profile
invoice.total_amount = 0 # Initialize total amount
invoice.save()
# Log the invoice primary key to ensure it is saved
logger.debug(f"Invoice saved with ID: {invoice.id}")
total = 0
for item_form in formset:
if item_form.cleaned_data:
service = item_form.cleaned_data.get('service')
description = item_form.cleaned_data.get('description')
quantity = item_form.cleaned_data.get('quantity')
rate = item_form.cleaned_data.get('rate')
if service and description and quantity and rate:
amount = float(rate) * float(quantity)
total += amount
BillLineItem.objects.create(
invoice=invoice,
service=service,
description=description,
quantity=quantity,
rate=rate,
amount=amount
)
# Update the total amount of the invoice after creating all line items
invoice.total_amount = total
invoice.save()
try:
generate_PDF(self.request, id=invoice.id)
except Exception as e:
logger.error(f"PDF generation error: {e}")
return super().form_valid(form)
except Exception as e:
logger.error(f"Error saving invoice or line items: {e}")
return self.form_invalid(form)
else:
logger.error("Formset is invalid")
logger.error(formset.errors)
return self.form_invalid(form)
def form_invalid(self, form):
context = self.get_context_data()
formset = context['formset']
logger.error("Form or formset is invalid")
logger.error("Form errors: %s", form.errors)
logger.error("Formset errors: %s", formset.errors)
return self.render_to_response(self.get_context_data(form=form))
Подробнее здесь: https://stackoverflow.com/questions/785 ... relationsh
Мобильная версия