skip to Main Content

I have a Django app in my project I am currently working on called pharmcare, and I kind of getting into a unique constraint issue whenever I want to override the save() method to insert/save the total payment made by the patient so that the pharmacist that is creating the form or updating the patient’s record won’t perform the math manually. Whenever I used the form from CreateView on the view.py without overriding the save method with the function I created dynamically to solve the math, it performed the work perfectly well, but in the admin panel, the answer wouldn’t appear there. However, if I tried using the save() in my models.py of the app I’d get that error. If I remove the save() method in the model, the error will disappear, and that’s not what I want, since I want it to be save in the db immediately the pharmacists finished creating or modifying the form. I had used the get_or_create method to solve it but it remains abortive, and another option which I don’t want to use (since I want the site owner to have the option of deleting the pharmacist/organizer creating the record at ease same with the records s/he created) is the SET_NULL for the on_delete function of the foreign key. The database I am using is PostgreSQL btw.

Here is my pharmcare model of the patient table:


class Patient(models.Model):
   
    medical_charge = models.PositiveBigIntegerField(blank=True, null=True,
                             verbose_name="amount paid (medical charge if any)")
    notes = models.TextField(null=True, blank=True)

    pharmacist = models.ForeignKey(
        "Pharmacist", on_delete=models.SET_NULL, null=True, blank=True)
    organization = models.ForeignKey(
        'leads.UserProfile', on_delete=models.CASCADE)

    user = models.ForeignKey(
        'songs.User', on_delete=models.CASCADE)
    patient = models.ForeignKey(
        'PatientDetail', on_delete=models.CASCADE,
        verbose_name='Patient-detail')

    medical_history = models.ForeignKey(
        'MedicationHistory',
        on_delete=models.CASCADE)

    total = models.PositiveBigIntegerField(editable=True, blank=True,
                                   null=True, verbose_name="Total (auto-add)")

    slug = models.SlugField(null=True, blank=True)
    date_created = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ['id', '-date_created']

    def __str__(self):
        return self.patient.first_name

    def get_total_charge(self) -> int:
        total = 0
        # check whether there is additional charges like drug price to be added
        # if yes, then add medical charges to the total
        if self.medical_charge:
            amount_charged = self.patient.consultation + self.medical_charge
            total += amount_charged
            return total
        total += self.patient.consultation

        return total

     # where the error is coming from
    def save(self, *args, **kwargs):
        """ override the save method to dynamically save the 
        total and slug in the db whenever form_valid() of the patient is 
        checked. """
        
        self.total = self.get_total_charge()
        self.slug = slug_modifier()
        return super().save(self, *args, **kwargs)

My View:



class PatientCreateView(OrganizerPharmacistLoginRequiredMixin, CreateView):
    """ Handles request-response cycle made by the admin/pharmacists to create
    a patient"""

    template_name = 'pharmcare/patients/patient-info-create.html'
    form_class = PatientModelForm
    # queryset = Patient.objects.all()

    def get_queryset(self):

        organization = self.request.user.userprofile
        user = self.request.user
        if user.is_organizer or user.is_pharmacist:
            queryset = Patient.objects.filter(
                organization=organization)
        else:
            queryset = Patient.objects.filter(
                pharmacist=user.pharmacist.organization
            )
            queryset = queryset.filter(pharmacist__user=user)

        return queryset

    def form_valid(self,  form: BaseModelForm) -> HttpResponse:
        user = self.request.user

        form = form.save(commit=False)
        form.user = user
        form.organization = user.userprofile
        form.save()

        # Patient.objects.get_or_create(pharmacist=user.pharmacist.organization)
        return super(PatientCreateView, self).form_valid(form)

    def get_success_url(self) -> str:
         return reverse('pharmcare:patient-info')


The error message from my dev environment:


IntegrityError at /pharmcare/patient-info-create/
UNIQUE constraint failed: pharmcare_patient.id
Request Method: POST
Request URL:    http://127.0.0.1:8000/pharmcare/patient-info-create/
Django Version: 4.2
Exception Type: IntegrityError
Exception Value:    
UNIQUE constraint failed: pharmcare_patient.id
Exception Location: C:UsersUSERDesktopdj-testsenvLibsite-packagesdjangodbbackendssqlite3base.py, line 328, in execute
Raised during:  pharmcare.views.patients.PatientCreateView
Python Executable:  C:UsersUSERDesktopdj-testsenvScriptspython.exe
Python Version: 3.12.0
Python Path:    
['C:\Users\USER\Desktop\dj-tests',
 'C:\Users\USER\AppData\Local\Programs\Python\Python312\python312.zip',
 'C:\Users\USER\AppData\Local\Programs\Python\Python312\DLLs',
 'C:\Users\USER\AppData\Local\Programs\Python\Python312\Lib',
 'C:\Users\USER\AppData\Local\Programs\Python\Python312',
 'C:\Users\USER\Desktop\dj-tests\env',
 'C:\Users\USER\Desktop\dj-tests\env\Lib\site-packages',
 'C:\Users\USER\Desktop\dj-tests\env\Lib\site-packages\win32',
 'C:\Users\USER\Desktop\dj-tests\env\Lib\site-packages\win32\lib',
 'C:\Users\USER\Desktop\dj-tests\env\Lib\site-packages\Pythonwin']
Server time:    Sat, 30 Dec 2023 18:02:51 +0000

I had also tried using self.object provided by Django CBV as well and I had tried looking at previous issues relating to my problem here in stackoverflow but none was able to sort my problem out, which 80% of them were using SET_NULL on their foreign key which I don’t want.

Please I need your answer on making this work because it kinda stuck my progress on my work for a day now. Thank you!

2

Answers


  1. Chosen as BEST ANSWER

    I used the answer provided above, and it didn't work however it really gave me a clue on what to do, so I had to dig more in the django documentation (when to use save, update,delete methods. The error I got was AttributeError:'super' object has no attribute 'update'.

    This works instead:

    def update(self, *args, **kwargs):
        """ override the save method to dynamically save the 
        total and slug in the db whenever form_valid() of the patient is 
        checked. """
            
        self.total = self.get_total_charge()
        self.slug = slug_modifier()
        return super(Patient, self).update(*args, **kwargs)
    
    

    Thanks a bunch @Pycm


  2. Use the below code. Use update, not save.

    def save(self, *args, **kwargs):
        """ override the save method to dynamically save the 
        total and slug in the db whenever form_valid() of the patient is 
        checked. """
            
        self.total = self.get_total_charge()
        self.slug = slug_modifier()
        obj = super(Patient, self).update(*args, **kwargs)
        return obj
    
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search