[Django]-Django: Cannot create model with a Field that maps to different models

2👍

You could consider to use django-polymorphic.

If you do this, just let Resource inherit from PolymorphicModel like this:

from polymorphic.models import PolymorphicModel

class Supplier(models.Model):
    delivery_time = models.CharField(max_length=255, blank=True, null=True)
    minimum_order_quantity = models.FloatField(blank=True, null=True)


class Resource(PolymorphicModel):
    code = models.CharField(max_length=255, unique=True, blank=True, null=True)
    country = models.CharField(max_length=255, blank=True, null=True)


class Part(Resource):
    some_attr = models.CharField(max_length=255, blank=True, null=True)


class Fuel(Resource):
    some_other_attr = models.CharField(max_length=255, blank=True, null=True)

And then you can create the SupplierResource model like the following:

class SupplierResource(models.Model):
    supplier = models.ForeignKey(Supplier, on_delete=models.CASCADE)
    resource = models.ForeignKey(Resource, on_delete=models.CASCADE)

Or, a many to many relations between Supplier and Resource:

class Supplier(models.Model):
    delivery_time = models.CharField(max_length=255, blank=True, null=True)
    minimum_order_quantity = models.FloatField(blank=True, null=True)
    resources = models.ManyToManyField(Resource, related_name="suppliers")

1👍

As mentioned by C14L you can use a GenericForeignKey to create a relationship with another model. However GenericForeignKeys come with their own issues. They don’t create reverse relationships. So you wouldn’t be able to do, for example, [sr.supplier for sr in Part.supplier_resources], however it would allow you to get rid of your Resource parent model. What you’ve got with the Resource parent model is the right idea I believe. I would suggest in the
resource model, you add a field a field called child_model_name

class Resource(models.Model):
    child_model_name = models.TextField()
    some_attr = models.CharField(max_length=255, blank=True, null=True)

where child_model_name = 'part' etc..

Then in your SupplierResource Model you have

class SupplierResource(models.Model):
    supplier = models.ForeignKey(Supplier, ..., related_name="supplier_resources")
    resource = models.ForeignKey(Resource, ..., related_name="supplier_resources")

Here what django is doing for you is creating a table called Resource that contains all the fields for a Resource. It also creates a table for you called Part with fields specific to a part that has a OneToOne relationship to Resource.

Now can you do this:

parts = Part.objects.filter(supplier_rescources__supplier=supplier)

Or to get different types of resource in one list (Part, fuel etc).

resources = Resource.objects.filter(supplier_resources__supplier=supplier)

[getattr(resource, resource.child_model_name) for resource in resources]

0👍

Could you use Generic Foreign Keys? They use content_type and object_id to map the same field to different models:

https://docs.djangoproject.com/en/4.0/ref/contrib/contenttypes/#generic-relations

👤C14L

Leave a comment