AlexW
AlexW

Reputation: 2591

Django Query a query?

Trying to speed up the performance of my app, and post some analysis with debug toolbar I can see I am doing 68 queries.

I query the circuits for every showroom (68 of), I thought if I just query the circuits once, could I then requery the existing query instead of calling the DB again for each Circuit?

something like adding:

crData = Circuits.objects.only('circuit_preference','site_data__id')

then how to query crData again? to match each statement?

Current code below

# get shworoom data
srData =  SiteData.objects.only('location','subnet').filter(is_live=True).exclude(site_type='Major Site')

for sr in srData:
    site = SiteType()
    site.type = checkRoute(sr.subnet)
    site.location = sr.location

    if 'MPLS' in site.type:
        mpls = site.type.split('-')
        try:

            d = Circuits.objects.only('circuit_preference','site_data').filter(site_data__id=sr.id,provider=mpls[0],circuit_type__icontains=mpls[1]) 
            site.preference = d[0].circuit_preference
        except:
            pass
    elif site.type == '4G':
        try:
            d = Circuits.objects.only('circuit_preference','site_data').filter(site_data__id=sr.id,provider='EE',circuit_type__icontains=site.type)
            site.preference = d[0].circuit_preference
        except:
            pass    
    elif site.type == 'DSL' or site.type == 'FIBRE':
        try:
            d = Circuits.objects.only('circuit_preference','site_data').filter(site_data__id=sr.id,circuit_type__icontains=site.type) 
            site.preference = d[0].circuit_preference
        except:
            pass 

**EDIT: models below

class SiteData(models.Model):
    location = models.CharField(max_length=50)
    site_type = models.CharField(max_length=20, verbose_name="Site Type", \
                choices=settings.SITE_TYPE)
    subnet = models.GenericIPAddressField(protocol='IPv4')
    bgp_as = models.CharField(max_length=6, verbose_name="BGP AS Number")
    opening_date = models.DateField(verbose_name="Showroom opening date")
    last_hw_refresh_date = models.DateField(verbose_name="Date of latest hardware refresh", \
                           blank=True, null=True)
    is_live = models.BooleanField(default=False, verbose_name="Is this a live site?")
    tel = models.CharField(max_length=20, blank=True, null=True)
    notes = models.TextField(blank=True)
    class Meta:
        verbose_name = "Site Data"
        verbose_name_plural = "Site Data"
        ordering = ('location',)

    def __unicode__(self):
        return self.location

class Circuits(models.Model):
    site_data = models.ForeignKey(SiteData, verbose_name="Site", on_delete=models.PROTECT)
    order_no = models.CharField(max_length=200, verbose_name="Order No")
    install_date = models.DateField(blank=True, null=True)
    circuit_type = models.CharField(max_length=100, choices=settings.CIRCUIT_CHOICES)
    circuit_preference = models.CharField(max_length=20, verbose_name="Circuit Preference", \
                         choices=settings.CIRCUIT_PREFERENCE, blank=True, null=True)
    circuit_speed_down = models.DecimalField(max_digits=10, decimal_places=1, blank=True, null=True)
    circuit_speed_up = models.DecimalField(max_digits=10, decimal_places=1, blank=True, null=True)
    circuit_bearer = models.IntegerField(blank=True, null=True)
    provider = models.CharField(max_length=200, choices=settings.PROVIDER_CHOICES)
    ref_no = models.CharField(max_length=200, verbose_name="Reference No")
    cost_per_month = models.DecimalField(decimal_places=2, max_digits=8)
    contract_length = models.IntegerField(verbose_name="Contact length in years")
    service_contacts = models.ForeignKey(ServiceContacts, on_delete=models.PROTECT)
    subnet = models.GenericIPAddressField(protocol='IPv4', verbose_name="Subnet", \
             blank=True, null=True)
    default_gateway = models.GenericIPAddressField(protocol='IPv4', \
                      verbose_name="Default Gateway", blank=True, null=True)
    subnet_mask = models.CharField(max_length=4, verbose_name="Subnet Mask", \
                  choices=settings.SUBNET_MASK_CHOICES, blank=True, null=True)
    internet_device = models.ForeignKey(ConfigTemplates, \
                      verbose_name="is this circuit the active internet line for a device?", \
                      default=6, on_delete=models.PROTECT)
    decommissioned = models.BooleanField(default=False, verbose_name="Decomission this circuit?")

Upvotes: 0

Views: 147

Answers (1)

Greg Sebastian
Greg Sebastian

Reputation: 201

I was going to point you toward Pickling, but I suppose that doesn't make sense unless you need to cache the querysets to re-use in another location.

Actually I'm pretty sure querysets are pretty good for only hitting the database when they need to, which is when they're first evaluated. However, I think redeclaring the queryset would cause it to be re-evaluated, but if you create a list/dictionary of querysets I imagine you should be able to just re-use them without hitting the database again (unless you need to run new filters on them.) So I don't think you have much choice than to hit the database for each time you fetch a crData queryset, but you should at least be able to store the querysets and reuse them without it hitting the database for each one again.

Something like this should work I think. Would love to know if I'm wrong.

crData = []
for sr in srData:
    # ...
    crData.append(d)

for cr in crData:
    # Do stuff

EDIT: Here's another relevant question: Django ORM and hitting DB


Upvotes: 1

Related Questions