SQL๋ฌธ ์คํ
Slicing
step์ ํ์ฉํ ๋์๋ง
Query ๊ฐ์
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. ๊ด๋ จ ๋ฌธ์
๋ฐ์ดํฐ๋ฒ ์ด์ค ์ต์ ํ
lazyํ์ฌ, evaluated ๋๋ ์์ ์ ์คํ๋๋ฉฐ, cache๋ฅผ ํ์ฉํ ์ ์์. (๊ฐ๊ฐ ๋ฌธ์ ํ์ธํ ๊ฒ)
count
, exists
์ผ๋ฐ์ ์ผ๋ก ํ์ฉํ๋ ๊ฒ์ด ์ข์ผ๋, ์์์ ์ฝ๋์ ์ํฉ์์๋ cache๋ ๊ฐ์ ๋ฐํ์ผ๋ก length๋ฅผ ๊ตฌํ๋ ๋ฐฉ์์ผ๋ก ํ์ด๋๊ฐ ์ ์์
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')
<div data-gb-custom-block data-tag="for">
<p>{{ comment.content }}</p>
</div>
๊ฐ์ ํ (2๋ฒ)
posts = Post.objects.prefetch_related('comment_set').order_by('-pk')
<!-- ๋ณ๊ฒฝ ์์ -->
<div data-gb-custom-block data-tag="for">
<p>{{ comment.content }}</p>
</div>
4. ๊ฒ์๊ธ๋ง๋ค ์์ฑ์ ์ด๋ฆ๊ณผ ๋๊ธ๋ค ์ถ๋ ฅ
๊ฐ์ ์ (111๋ฒ)
# views.py
posts = Post.objects.order_by('-pk')
<div data-gb-custom-block data-tag="for">
<p>{{ comment.user.username }} : {{ comment.content }}</p>
</div>
๊ฐ์ ํ (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')
<div data-gb-custom-block data-tag="for">
<p>{{ comment.user.username }} : {{ comment.content }}</p>
</div>
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 ์ค์ ํ๊ธฐ
๋ฐฉ๋ฒ 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"
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
<div data-gb-custom-block data-tag="load"></div>
...
<!--๋ฐฉ๋ฒ 1-->
<img src="{{request.user.email|profile_url}}">
<!--๋ฐฉ๋ฒ 2-->
<img src="{{request.user.gravatar_url}}">
...