Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Make your pony fly!

Make your pony fly!

Tips and best practices to get your Django site to fly

Benjamin Wohlwend

June 02, 2015
Tweet

Other Decks in Programming

Transcript

  1. Hi, my name is Benjamin and I'm a lazy programmer.

    I like my code to be lazy. In other words, I like my code to not do too much work.
  2. Piece of , right? class Question(models.Model): user = models.ForeignKey('auth.User') title

    = models.CharField(max_length=100) body = models.TextField() tags = models.ManyToManyField('Tag') class Answer(models.Model): question = models.ForeignKey(Question) user = models.ForeignKey('auth.User') title = models.CharField(max_length=100) body = models.TextField() class Tag(models.Model): name = models.CharField(max_length=30)
  3. Piece of , right? class Question(models.Model): user = models.ForeignKey('auth.User') title

    = models.CharField(max_length=100) body = models.TextField() tags = models.ManyToManyField('Tag') class Answer(models.Model): question = models.ForeignKey(Question) user = models.ForeignKey('auth.User') body = models.TextField() class Tag(models.Model): name = models.CharField(max_length=30)
  4. Piece of , right? class Question(models.Model): user = models.ForeignKey('auth.User') title

    = models.CharField(max_length=100) body = models.TextField() tags = models.ManyToManyField('Tag') class Answer(models.Model): question = models.ForeignKey(Question) user = models.ForeignKey('auth.User') body = models.TextField() class Tag(models.Model): name = models.CharField(max_length=30)
  5. Some views... class QuestionsList(ListView): paginage_by = 20 model = Question

    class QuestionDetail(DetailView): model = Question
  6. and templates <ul> {% for question in object_list %} <li>

    <h3>{{ question.title }} by {{ question.user.username }}</h3> {{ question.body|markdown }} <p>{{ question.answer.all|length }} answers</p> <p>{{ question.tags.all|join:", "}}</p> </li> {% endfor %} </ul>
  7. select_related() Use it to "preload" objects related by ForeignKey a.k.a.

    "JOIN" class Question(models.Model): user = models.ForeignKey('auth.User') {% for question in object_list %} <li> <h3>by {{ question.user.username }}</h3>
  8. prefetch_related() Use it to prefetch objects related via reverse ForeignKey

    or ManyToMany relationships {% for question in object_list %} <li> <p>{{ question.tags.all|join:", " }}</p> </li> {% endfor %} class Question(models.Model): tags = models.ManyToManyField('Tag')
  9. Do less work Only fetch data that you really need

    (e.g. use QuerySet.defer() to not load unneeded large columns)
  10. Do less work Let others do the work (e.g. do

    calculations in the database with annotate / aggregate)
  11. Do less work <p>{{ question.answers.all|length }} answers</p> We fetch all

    answers, just to count them. That's kinda stupid.... let the database count!
  12. annotate() class QuestionsList(ListView): model = Question queryset = Question.objects.select_related( 'user'

    ).prefetch_related( 'tags', ).annotate(answer_count=models.Count('answer')) <p>{{ question.answer_count }} answers</p>
  13. Caching Proper caching can make your site withstand thousands of

    concurrent users. But... caching is hard!
  14. Caching Proper caching can make your site withstand thousands of

    concurrent users. But... caching cache invalidation is hard!
  15. Let's say there is a need One of the easiest

    ways to start with caching is the cache_page decorator from django.views.decorators.cache import cache_page question_list = cache_page(60)(QuestionsList.as_view())
  16. Further caching Template caching with {% cache %} ORM caching

    with johnny-cache or django-cache-machine Caching HTTP proxy like Varnish
  17. In retrospect Watch out for those SQL queries! Being lazy

    is good, don't let your code do too much work. If everything else fails, bring out the big caching guns.