Amandeep Singh
Amandeep Singh

Reputation: 1431

Reduce the execution time of django view

I have a django view which returns all the products of Product model. Situation is discount is dependent on product as well as user so it has to be calculated every time at runtime. I have added only 3500 products yet and server is taking 40-50 seconds to respond. I wonder how much time will it take when i will add 100,000 products. How can i optimize this?

def apply_discount(product_obj,user_obj):
    discount1 = product_obj.brand.discount
    try:
        discount2 = user_obj.special_discount.all().filter(brand=product_obj.brand.name)[0].discount
    except IndexError:
        discount2 = 0
    total_discount = discount1 + discount2
    discount_apply_on = product_obj.brand.discount_on
    price= getattr(product_obj, discount_apply_on)
    final= round(price - (price*total_discount)/100.00,3)
    return (product_obj,price,final,total_discount)


@login_required
def product_list(request):
    context = {}
    product_qs = Product.objects.all()

    product_list = []

    for product in product_qs:
        discount_applied_product = apply_discount(product,request.user)
        product_list.append(discount_applied_product)

    context['products'] = product_list

    return render(request,"myapp/products.html",context)

models.py

class BrandDiscount(models.Model):
    name = models.CharField(max_length=255)
    discount_on = models.CharField(max_length=25,default="retail_price")
    discount = models.FloatField(default=0)

    def __str__(self):
        return self.name



class Product(models.Model):
    brand = models.ForeignKey(BrandDiscount,on_delete=models.SET_NULL, null=True)
    part_number = models.CharField(max_length=255)
    description = models.TextField(null=True)
    pack_price  = models.FloatField(null=True)
    units_per_pack = models.IntegerField(null=True)
    single_price = models.FloatField(null=True)
    retail_price = models.FloatField(null=True)
    map_price = models.FloatField(null=True)
    jobber_price = models.FloatField(null=True)
    upc = models.CharField(max_length=255)
    stock = models.IntegerField(default=0)
    created_at = models.DateTimeField(auto_now_add=True)

app.yaml

runtime: python37
entrypoint: gunicorn -b :$PORT myProject.wsgi --timeout 120 
instance_class: F4
handlers:
  - url: /static
    static_dir: static/

  - url: /.*
    secure: always
    redirect_http_response_code: 301
    script: auto

I have deployed website on Google App engine standard. If i increase gunicorn workers, is it going to help?

Upvotes: 0

Views: 412

Answers (2)

Jan Hernandez
Jan Hernandez

Reputation: 4640

In your local environment you receive a response in 3 seconds with 400 elements

If you do the math

(400 items / 3s) = ~ 133 items/s
(4500 items / 133 items/s) = ~ 33.83s

This performance is very similar to what you are getting in App Engine, as was mentioned in the other answer, you could paginate your results.

But also you could send a JSON object with the information of all the elements to the interface and let a JavaScript function draw the elements (instead use render to draw all your page) as the user needs them.

Upvotes: 1

Ethan
Ethan

Reputation: 311

try paginating the response. I think that would be your best bet.

https://docs.djangoproject.com/en/3.0/topics/pagination/

Upvotes: 2

Related Questions