Search code examples
pythondjangodatabasedjango-modelsforeign-keys

How can I assign multiple Model in One Foreign Key Model as a Parent Model [ database design ]


I have 3 separate Models

1. InitialBills
    id uuid
    name varchar

2. CurrentBills
    id uuid
    name varchar

3. BillPaymentInfo
    id uuid
    name varchar

Now I have one another table which is Document attachment table

BillPaymentDocument
    id uuid
    biil_data FK [ models either from InitialBills, currentBill or BillPaymentInfo ]
    doc_name varchar
    doc_type choice field

I want it to be like 

BillPaymentDocument
       project = models.ForeignKey(InitialBills,currentBill,BillPaymentInfo   on_delete=models.SET_NULL, blank=False, null=True,
                                related_name='bill_payment_detail')

I do not want to give seperate table for this how can I do this???


Solution

  • In Django, you can use generic foreign key to relate one table to one of many.

    from django.db import models
    from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
    from django.contrib.contenttypes.models import ContentType
    
    
    
    class InitialBills(models.Model):
        uuid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=255)
    
    
    class CurrentBills(models.Model):
        uuid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=255)
    
    
    class BillPaymentInfo(models.Model):
        uuid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=255)
    
    
    class BillPaymentDocument(models.Model):
        uuid = models.AutoField(primary_key=True)
    
        # content_type tells Django which model this object will link to
        content_type = models.ForeignKey(
            ContentType, 
            limit_choices_to = {
                "model__in": ('InitialBills', 'CurrentBills', 'BillPaymentInfo')
            },
            on_delete=models.CASCADE
        )
        # object_id is the id of the object in the linked model
        object_id = models.PositiveIntegerField(null=False)
        # this is the actual foreign key object itself, rather than the id
        project = GenericForeignKey("content_type", "object_id")
        
        # ... then add some more fields if you wish ...
        document_name = models.CharField(max_length=255)
    
    # Now you need to add the relation manually onto the FK'ed models, 
    # as Django doesn't do this for you, 
    # in case you ever want to query this relationship backwards
    InitialBills.add_to_class("bill_payment_documents", GenericRelation('BillPaymentDocument', content_type_field='content_type', object_id_field='object_id'))
    CurrentBills.add_to_class("bill_payment_documents", GenericRelation('BillPaymentDocument', content_type_field='content_type', object_id_field='object_id'))
    BillPaymentInfo.add_to_class("bill_payment_documents", GenericRelation('BillPaymentDocument', content_type_field='content_type', object_id_field='object_id'))
    

    The content_type and object_id fields are more for Django's internal use. You will most often be referring to content_object in your code, as that is the equivalent of a ForeignKey field for this use case.