django-polymorphic icon indicating copy to clipboard operation
django-polymorphic copied to clipboard

hacks for getting around the `select_related` issue from parent on inherited models to avoid n+1 queries?

Open drivelous opened this issue 4 years ago • 0 comments

So I've read this issue extensively and tried some things out which don't work -- https://github.com/django-polymorphic/django-polymorphic/issues/198

So I'm trying to see if I can come to a middle ground where maybe I don't get the free select_related query but can add a prefetch_related and avoid n+1s. I have some models defined like this

class Message(PolymorphicModel):
    body = models.TextField
    # fields

class SMSMessage(Message)
    from_phone = models.CharField
    to_phone = models.ForeignKey(FooPhoneNumberModel)

class EmailMessage(Message):
    from_email = models.CharField
    to_email = models.ForeignKey(FooEmailModel)

class InstantMessage(Message):
    from_username = models.CharField
    to_username = models.ForeignKey(FooUser)

I'm writing a django testcase for a view that serializes all instances of subclassed messages for a particular user and this part of the test fails when adding more instances

        _create_messages()

        num_queries = 25
        with self.assertNumQueries(num_queries):
            response = self.client.get(url)
            payload = json.loads(response.content)
            self.assertEqual(response.status_code, 200)
            self.assertEqual(payload['has_more'], False)

        _create_messages()

        # fails -- does 45 queries
        with self.assertNumQueries(num_queries):
            response = self.client.get(url)

I was trying to mess around and see if I could run some type of prefetch? Something like:

messages = Message.objects.prefetch_related(
    Prefetch('smsmessage', queryset=SMSMessage.objects.filter(user=user), to_attr='through__smsmessage'),
    Prefetch('emailmessage', queryset=EmailMessage.objects.filter(user=user), to_attr='through__emailmessage'),
)

so that the query can execute the same amount of queries whether it's 20 messages or 1000 messages.

Any help is appreciated including explanations of the internals. I've been trying to do things like call select_related('smsmessage') and select_related('message_ptr__smsmessage') and the like and my mind is mush right now

drivelous avatar May 20 '20 19:05 drivelous