How do I collect all my Django data from the database before invoking my serializer?
I'm using Python 3.9 and Django 3.2. I have a Django model with a couple of many-to-many relationsips
class Coop(models.Model):
objects = CoopManager()
name = models.CharField(max_length=250, null=False)
types = models.ManyToManyField(CoopType, blank=False)
addresses = models.ManyToManyField(Address, through='CoopAddressTags')
enabled = models.BooleanField(default=True, null=False)
phone = models.ForeignKey(ContactMethod, on_delete=models.CASCADE, null=True, related_name='contact_phone')
email = models.ForeignKey(ContactMethod, on_delete=models.CASCADE, null=True, related_name='contact_email')
web_site = models.TextField()
description = models.TextField(null=True)
approved = models.BooleanField(default=False, null=True)
proposed_changes = models.JSONField("Proposed Changes", null=True)
reject_reason = models.TextField(null=True)
I can search for my model using a manager class that builds a query like so ...
def find(
self,
partial_name,
types_arr=None,
enabled=None,
city=None,
zip=None,
street=None,
state_abbrev=None
):
"""
Lookup coops by varying criteria.
"""
q = Q()
if partial_name:
q &= Q(name__icontains=partial_name)
if enabled != None:
q &= Q(enabled=enabled)
if types_arr != None:
filter = Q(
*[('types__name', type) for type in types_arr],
_connector=Q.OR
)
q &= filter
if street != None:
q &= Q(addresses__raw__icontains=street)
if city != None:
q &= Q(addresses__locality__name__iexact=city)
if zip != None:
q &= Q(addresses__locality__postal_code=zip)
if state_abbrev != None:
q &= Q(addresses__locality__state__code=state_abbrev)
q &= Q(addresses__locality__state__country__code="US")
queryset = Coop.objects.filter(q)
print(queryset.query)
return queryset
In my view, I invoke and return the data using
coops = Coop.objects.find(...)
serializer = CoopSearchSerializer(coops, many=True)
in which the serializer looks like
class CoopSearchSerializer(serializers.ModelSerializer):
...
def to_representation(self, instance):
rep = super().to_representation(instance)
rep['coopaddresstags_set'] = CoopAddressTagsSerializer(instance.coopaddresstags_set.all(), many=True).data
return rep
What I'm noticing is when I search for a result set that contains 6 results, and each one is serialized using the logic above, I get a proportional number of queries run for each result ...
SELECT "directory_coopaddresstags"."id", "directory_coopaddresstags"."coop_id", "directory_coopaddresstags"."address_id", "directory_coopaddresstags"."is_public" FROM "directory_coopaddresstags" WHERE "directory_coopaddresstags"."coop_id" = 271; args=(271,)
(0.000) SELECT "directory_coopaddresstags"."id", "directory_coopaddresstags"."coop_id", "directory_coopaddresstags"."address_id", "directory_coopaddresstags"."is_public" FROM "directory_coopaddresstags" WHERE "directory_coopaddresstags"."coop_id" = 271; args=(271,)
type of instance: <class 'directory.models.CoopAddressTags'>
(0.000) SELECT "address_address"."id", "address_address"."street_number", "address_address"."route", "address_address"."locality_id", "address_address"."raw", "address_address"."formatted", "address_address"."latitude", "address_address"."longitude" FROM "address_address" WHERE "address_address"."id" = 263 LIMIT 21; args=(263,)
(0.000) SELECT "address_locality"."id", "address_locality"."name", "address_locality"."postal_code", "address_locality"."state_id" FROM "address_locality" WHERE "address_locality"."id" = 16 LIMIT 21; args=(16,)
(0.000) SELECT "address_state"."id", "address_state"."name", "address_state"."code", "address_state"."country_id" FROM "address_state" WHERE "address_state"."id" = 19313 LIMIT 21; args=(19313,)
(0.000) SELECT "address_country"."id", "address_country"."name", "address_country"."code" FROM "address_country" WHERE "address_country"."id" = 484 LIMIT 21; args=(484,)
So if there are 6 results, the above gets run 6 times with different IDs. Is there a way to only have a single set of queries run so taht regardless of whether there are 1, 10, or 100 results, the same number of queries gets run to return the data?
Comments
Post a Comment