Optimization

SQL๋ฌธ ์‹คํ–‰

  • Iteration

  • Slicing

    • ๊ธฐ๋ณธ์ ์œผ๋ก  x

    • step์„ ํ™œ์šฉํ•  ๋•Œ์—๋งŒ

      • [3:10:2]

  • repr

  • len

  • bool

Query ๊ฐœ์„ 

ํ•„์ˆ˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ : django debug toolbar

installation

$ pip install django-debug-toolbar

Prerequisites

settings.py

INSTALLED_APPS = [
    ...
    'debug_toolbar',
]

Setting up URLconf

urls.py in the root directory

from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static

if settings.DEBUG:
    import debug_toolbar
    urlpatterns = [
        path('__debug__/', include(debug_toobar.urls)),
        path('admin/', admin.site.urls),
        path('posts/', include('posts.urls')),
        path('accounts/', include('accounts.urls')),
    ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Enabling middleware

settings.py

MIDDLEWARE = [
    ...
    'debug_toolbar.middleware.DebugToolbarMiddleware',
    ...
]

Configuring Internal IPs

settings.py

INTERNAL_IPS = [
    ...
    '127.0.0.1',
    ...
]

0. ๊ด€๋ จ ๋ฌธ์„œ

1. ๋Œ“๊ธ€ ์ˆ˜ ์ถœ๋ ฅ - annotate() ํ™œ์šฉ

N+1 problem

๊ฐœ์„  ์ „ (11๋ฒˆ)

# views.py
posts = Post.objects.order_by('-pk')
<p>๋Œ“๊ธ€ ์ˆ˜ : {{ aritcle.comment_set.count }}</p>

๊ฐœ์„  ํ›„ (1๋ฒˆ)

# views.py
Post.objects.annotate(comment_set_count=Count('comment')).order_by('-pk')
<!-- ์ฃผ์˜! comment_set_count๋กœ ํ˜ธ์ถœ -->
<p>๋Œ“๊ธ€ ์ˆ˜ : {{ post.comment_set_count }}</p>

select_related๋Š” SQL JOIN์„ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค

1:1, 1:N ๊ด€๊ณ„์—์„œ ์ฐธ์กฐ๊ด€๊ณ„ (N -> 1, foreignkey๊ฐ€ ์ •์˜๋˜์–ด ์žˆ๋Š” ๊ณณ)

๊ฐœ์„  ์ „ (11๋ฒˆ)

# views.py
posts = Post.objects.order_by('-pk')
<h3>{{ article.user.username }}</h3>

๊ฐœ์„  ํ›„ (1๋ฒˆ)

# views.py
Post.objects.select_related('user').order_by('-pk')
<!-- ๋ณ€๊ฒฝ ์—†์Œ -->
<h3>{{ article.user.username }}</h3>

prefetch_related๋Š” python์„ ํ†ตํ•œ join์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค

M:N, 1:N ๊ด€๊ณ„์—์„œ ์—ญ์ฐธ์กฐ ๊ด€๊ณ„ (1->N)

๊ฐœ์„  ์ „ (11๋ฒˆ)

# views.py
posts = Post.objects.order_by('-pk')
{% for comment in post.comment_set.all %}
    <p>{{ comment.content }}</p>
{% endfor %}

๊ฐœ์„  ํ›„ (2๋ฒˆ)

posts = Post.objects.prefetch_related('comment_set').order_by('-pk')
<!-- ๋ณ€๊ฒฝ ์—†์Œ -->
{% for comment in article.comment_set.all %}
    <p>{{ comment.content }}</p>
{% endfor %}

4. ๊ฒŒ์‹œ๊ธ€๋งˆ๋‹ค ์ž‘์„ฑ์ž ์ด๋ฆ„๊ณผ ๋Œ“๊ธ€๋“ค ์ถœ๋ ฅ

๊ฐœ์„  ์ „ (111๋ฒˆ)

# views.py
posts = Post.objects.order_by('-pk')
{% for comment in article.comment_set.all %}
    <p>{{ comment.user.username }} : {{ comment.content }}</p>
{% endfor %}

๊ฐœ์„  ํ›„ (2๋ฒˆ)

# views.py
from django.db.models import Prefetch

posts = Post.objects.prefetch_related(
        Prefetch('comment_set'),
        queryset=Comment.objects.select_related('user')
    ).order_by('-pk')
{% for comment in article.comment_set.all %}
    <p>{{ comment.user.username }} : {{ comment.content }}</p>
{% endfor %}

SQL Join

ex)

-- ๊ฒŒ์‹œ๊ธ€(A) + ๋Œ“๊ธ€(B)
SELECT * FROM article
LEFT OUTER JOIN comment
ON article.id = comment.article_id;

-- ๊ฒŒ์‹œ๊ธ€(A) + ์‚ฌ์šฉ์ž
SELECT * FROM article
INNER JOIN user
ON article.user_id = user.id;

+

Gravata ํ™œ์šฉํ•˜์—ฌ profile photo ์„ค์ •ํ•˜๊ธฐ

https://en.gravatar.com/site/implement/

๋ฐฉ๋ฒ• 1) @property ์„ค์ •

accounts > models.py

from django.db import models
from django.conf import settings
from django.contrib.auth.models import AbstractUser
import hashlib

# Create your models here.
# model์€ ํ•„์š”์—†๋‹ค! Django package์— ์žˆ๋Š” User๋ฅผ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ!

# ์‚ฌ์šฉ์ž ์ •์˜ ๋ชจ๋ธ ๋งŒ๋“ค๊ธฐ
class User(AbstractUser):
    followers = models.ManyToManyField(
        settings.AUTH_USER_MODEL,
        related_name = 'followings'
    )

    @property
    def gravatar_url(self):
        return f"https://s.gravatar.com/avatar/{hashlib.md5(self.email.encode('utf-8').strip().lower()).hexdigest()}?s=50&d=mp"

๋ฐฉ๋ฒ• 2) templatetags ๋งŒ๋“ค๊ธฐ

accounts > templatetags > gravatar.py

import hashlib
from django import template
from django.template.defaultfilters import stringfilter

register = template.Library()

@register.filter
@stringfilter
def profile_url(email):
    return f"https://s.gravatar.com/avatar/{hashlib.md5(email.encode('utf-8').strip().lower()).hexdigest()}?s=50&d=mp"
  • templatetags directory ์•ˆ์— ___init__.py ๋งŒ๋“ค์–ด์•ผ ํ•จ!

Templates

templates > _nav.html

{% load gravatar %}

...
<!--๋ฐฉ๋ฒ• 1-->                  
<img src="{{request.user.email|profile_url}}">

<!--๋ฐฉ๋ฒ• 2-->
<img src="{{request.user.gravatar_url}}">

...

Last updated