- Iteration
- Slicing
- 기본적으론 x
- step을 활용할 때에만
- [3:10:2]
- repr
- len
- bool
필수 라이브러리 : django debug toolbar
pip install django-debug-toolbar
settings.py
INSTALLED_APPS = [
...
'debug_toolbar',
]
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)
settings.py
MIDDLEWARE = [
...
'debug_toolbar.middleware.DebugToolbarMiddleware',
...
]
settings.py
INTERNAL_IPS = [
...
'127.0.0.1',
...
]
-
: https://docs.djangoproject.com/en/3.0/topics/db/optimization/
-
QuerySet 실행에 관한 이해 : https://docs.djangoproject.com/en/3.0/topics/db/optimization/#understand-queryset-evaluation
- lazy하여, evaluated 되는 시점에 실행되며, cache를 활용할 수 있음. (각각 문서 확인할 것)
-
-
- https://docs.djangoproject.com/en/3.0/topics/db/optimization/#don-t-overuse-count-and-exists
- 일반적으로 활용하는 것이 좋으나, 예시의 코드의 상황에서는 cache된 값을 바탕으로 length를 구하는 방식으로 풀어나갈 수 있음
-
: https://docs.djangoproject.com/en/3.0/ref/models/querysets/#prefetch-related
N+1 problem
# views.py
posts = Post.objects.order_by('-pk')
<p>댓글 수 : {{ aritcle.comment_set.count }}</p>
# 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가 정의되어 있는 곳)
# views.py
posts = Post.objects.order_by('-pk')
<h3>{{ article.user.username }}</h3>
# 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)
# views.py
posts = Post.objects.order_by('-pk')
{% for comment in post.comment_set.all %}
<p>{{ comment.content }}</p>
{% endfor %}
posts = Post.objects.prefetch_related('comment_set').order_by('-pk')
<!-- 변경 없음 -->
{% for comment in article.comment_set.all %}
<p>{{ comment.content }}</p>
{% endfor %}
# views.py
posts = Post.objects.order_by('-pk')
{% for comment in article.comment_set.all %}
<p>{{ comment.user.username }} : {{ comment.content }}</p>
{% endfor %}
# 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 %}
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;
+
https://en.gravatar.com/site/implement/
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 > _nav.html
{% load gravatar %}
...
<!--방법 1-->
<img src="{{request.user.email|profile_url}}">
<!--방법 2-->
<img src="{{request.user.gravatar_url}}">
...