Search code examples
djangoserializationdjango-related-manager

Serializing Related Data in Django using Natural Foregin Keys (Three Models, Two Layers)


I've got three models, Product, ProductRelease, and ReleaseNote that all inherit from an abstract model factory (with common fields) with the following relationships:

class Product(abstract_base_model_factory()):
    <additional fields>

class ProductRelease(abstract_base_model_factory()):
    <additional fields>
    product = models.ForeignKey(Product, on_delete=models.CASCADE,
                                related_name='product_releases')

class ReleaseNote(abstract_base_model_factory()):
    <additional fields>
    product_release = models.ForeignKey(ProductRelease, on_delete=models.CASCADE,
                                        related_name='release_notes')

I've followed the documentation to serialize these for returning JSON. I used the docs here to set up serialization of natural keys.

I can add the additional code, if needed, but it's mostly boilerplate and works with two models in play (ProductRelease and Product or ReleaseNote and ProductRelease). But it's not working with three models in play.

For example, if I serialize ProductRelease objects, I can see the Product and fields I specify:

{
  "product_releases": [
    {
      "model": "products.productrelease", 
      "pk": 7, 
      "fields": {
          "name": "Product Release A",
          "product": "prod1"
      }
    },
    { . . . },
  ]
}

However, I want to be able to serialize ReleaseNote objects, but then show the ProductRelease (first foreign key relation) and the Product (second foreign key relation) objects.

Can this be done in a single JSON response without using a package like Django REST Framework? I'd like to achieve this without requiring additional packages.

UPDATE

After some time, I realized that @oleksii was right. I ended up implementing Django REST Framework and got the nesting I needed. Works great.


Solution

  • You can use nested model serializers for your purposes like this:

    class ProductSerializer(serializers.ModelSerializer):
        class Meta:
            model = Product
            fields = "__all__"
    
    class ProductReleaseSerializer(serializers.ModelSerializer):
        product = ProductSerializer(many=True)
    
        class Meta:
            model = ProductRelease
            fields = "__all__"
    
    
    class ReleaseNoteSerializer(serializers.ModelSerializer):
        product_release = ProductReleaseSerializer()
    
        class Meta:
            model = ReleaseNote
            fields = "__all__"
    
    release_note_model_instance = ReleaseNote.objects.all()
    print(ReleaseNoteSerializer(release_note_model_instance, many=True).data)