Search code examples
djangomodel-view-controllerinline-formset

Django Foreignkey with edit fields and select field how to put in form


I apologize if that question was raised before. But I have been struggling with this for weeks and couldn't find anything useful.

I have the following problem (it is simplified a lot but essentially my problem is presented)

I have a Model that has a lot of fields. It's called

class DocAide(models.Model):
    id = models.AutoField(primary_key=True)
    pulse = models.DecimalField('Pulse', max_digits=3, decimal_places=0)
    weight = models.DecimalField('Weight (kg)', max_digits=3, decimal_places=0)
    bp_sys = models.DecimalField('BP Sys', max_digits=3, decimal_places=0)
    bp_dia = models.DecimalField('BP Dia', max_digits=3, decimal_places=0)
    temperature = models.DecimalField('Temp. deg C', max_digits=2, decimal_places=1)
    drugs = models.ManyToManyField(Drug, blank=True)    
    date = models.DateField(editable=False, default=timezone.now)
    doctors_notes = models.TextField('Patient is complaining about:', default='')
    note = models.TextField(max_length=100, default='')

The ForeignKey Drugs has Names of drugs with quantity I would like to have the possibility to select multiple drugs but with edit fields that show what dosage needs to be taken and when, it should be like a prescription. The Model looks like this:

class Drug(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=100, default='')
    QUANTITY_STR = ['Bottle', 'Tablet' 'Injection', 'Capsules', 'other']
    QUANTITY = ((str, str) for str in QUANTITY_STR)
    quantity = models.CharField(max_length=2, choices=QUANTITY, default='Bottle')
    category = models.CharField(max_length=150, default='')
    strength = models.CharField(max_length=150, default='')
    in_supply_stock = models.PositiveIntegerField(default=0)
    in_main_stock = models.PositiveIntegerField(default=0)
    date = models.DateField(editable=False, default=timezone.now)
    charge = models.PositiveIntegerField(default=0)
    morning = models.CharField(validators=[int_list_validator], max_length=3, default=0)
    midday = models.CharField(validators=[int_list_validator], max_length=3, default=0)
    evening = models.CharField(validators=[int_list_validator], max_length=3, default=0)
    night = models.CharField(validators=[int_list_validator], max_length=3, default=0)
    days = models.CharField(validators=[int_list_validator], max_length=3, default=0)
    tablets = models.CharField(validators=[int_list_validator], max_length=3, default=0)

How can I accomplish that in a form or template. I tried with Inlineformset it doesn't work. Also later I would like to have them preselected as well.

But for now I would like to have a button that produces a line with a dropdown list of the drugs and the edit fields of the model.

Thank you in advance.


Solution

  • As others have said, a Drug object should not have a quantity associated with it, but a prescription "entry" should.

    I think this is the Model structure you need:

    QUANTITY_STR = ['Bottle', 'Tablet' 'Injection', 'Capsules', 'other']
    
    class DocAide(models.Model):
        # same properties but remove `drugs` from this model
    
    
    class Drug(models.Model):
        # same properties but remove `quantity` property
    
    
    class Prescription(model.Model):
        drug = model.ForeignKey(to=Drug, related_name='prescriptions')
        doc_aide = model.ForeignKey(to=DocAide, related_name='prescriptions')
        quantity = models.IntegerField()
        qty_container = models.CharField(max_length=10, choices=QUANTITY_STR, default=QUANTITY_STR[0])
    

    I changed a few things for you assuming I understood your business logic correctly. Such as how the quantity field works.

    I created two fields to describe the quantity. quantity holds the numerical value, and qty_container holds the container's name if you will, like "Bottle", "Injection" and so on.

    qty_container has a max_length equal to the number of characters in the word "Injection" since it is the largest word that might fit in this field. You had the default of that field be greater than the max_length which would cause an error.

    Now I'm not sure why you wanted to save a tuple of two strings in the quantity field so I ignored that, but if you can comment on your intended logic here I might be able to edit the answer.

    Anyway, the Prescription model.

    This model will act as an intermediary between Drug and DocAide, and it is the one that will hold the quantity information. I've linked it with Drug and DocAide using foreign keys and set the related_name to suitable names. These "related_names" you'll find show up in the referenced model. So for example if you can do

    doc_aide = DocAide.objects.get(pk=1)
    for presc in doc_aide.prescriptions:
        print(presc.drug.name)
        print(presc.quantity)
    

    This means that one DocAide object will be linked with one or many Prescription objects, each of those holds quantity info and is linked with a Drug object:

    DocAide (id, etc) >> Prescription (doc_aide_id, drug_id, qty_info) >> Drug (id, etc) 
    

    As a side note, after you're sure everything works and you're good to go, you might need to look into query optimization in Django, because as it is written now, it's pretty unoptimized. But don't worry about optimization until you've finished and your code works correctly.