Django customization of loading a foreign key

Issue

Assume I have three related classes such as:

class A:
  ...

class B:
  ...
  a = models.ForeignKey(A, ...)

class C:
  ...
  b = models.ForeignKey(B, ...)

I want to customize accessing b on C object to load a immediately. It means whenever I called c.b a select_related query call a too. There are also other scenario which I need to be able to use prefetch_related.

I am using django 3.1.1

Solution

You can do this if you want to reuse some select_related() with foreign keys :

from django.db import models
from django.db.models.fields.related_descriptors import ForwardManyToOneDescriptor


class FullBForwardManyToOneDescriptor(ForwardManyToOneDescriptor):
    def get_object(self, instance):
        qs = self.get_queryset(instance=instance).select_related("a")
        # Assuming the database enforces foreign keys, this won't fail.
        return qs.get(self.field.get_reverse_related_filter(instance))


class FullBForeignKey(models.ForeignKey):
    forward_related_accessor_class = FullBForwardManyToOneDescriptor


class C:
  ...
  b = FullBForeignKey(B, ...)

class D:
  ...
  b = FullBForeignKey(B, ...)

class E:
  ...
  b = FullBForeignKey(B, ...)

You can create other classes inheriting ForwardManyToOneDescriptor and ForeignKey for each of your use cases, if you have many use cases for B foreign key.

class F:
  ...
  b = SomeExtraBForeignKey(B, ...)

class G:
  ...
  b = SomeExtraBForeignKey(B, ...)  

Answered By – Laurent Lyaudet

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published