TIL - Django
๐ย ๊ณต๋ถ ๋ด์ฉ
Django์ ๋์์ธ ํจํด
MVC
๊ตฌ์ฑ ์์๋ฅผ Model-View-Controller๋ก ๊ตฌ๋ถํ๋ ๋์์ธ ํจํด
๊ฐ ๊ตฌ์ฑ ์์๊ฐ ๋ค๋ฅธ ์์์๊ฒ ์ํฅ์ ๋ฏธ์น์ง ์์์ผ ํจ
Model
- ๋ฐ์ดํฐ๋ฅผ ๊ฐ๊ณ , ์ฒ๋ฆฌํ๋ ๋ก์ง์ ๊ฐ์ง
View
- ์์ฒญ์ ๋ํ ๊ฒฐ๊ณผ๋ฅผ ํ๋ฉด์ ๋ณด์ฌ์ฃผ๋ ์ญํ . ์ ์ ์์ ์ธํฐํ์ด์ค
Controller
- Model๊ณผ View๋ฅผ ์ด์ด์ฃผ๋ ์ญํ
MTV
Model-Template-View
MVC ํจํด์ ๋์๋๋ Django์ ๋์์ธ ํจํด
Model
- DB์ ์ ์ฅ๋๋ ๋ฐ์ดํฐ๋ฅผ ์๋ฏธํ๋ฉฐ, ํด๋์ค ํ๋๊ฐ table ํ๋์ ๋์๋จ
Template
- MVC ํจํด์ View ์ญํ ์ผ๋ก, ์ ์ ์๊ฒ ๋ณด์ฌ์ง๋ ํ๋ฉด์ ์๋ฏธ
View
- MVC ํจํด์ Controller ์ญํ ์ผ๋ก, ์์ฒญ์ ๋ฐ๋ฅธ ๋ก์ง์ ์ํํ๋ฉฐ ๊ฒฐ๊ณผ๋ฅผ Template์ผ๋ก ๋ ๋๋งํ๋ฉฐ ์๋ตํ๊ฑฐ๋ ๋ฐ์ดํฐ๋ฅผ ์ฃผ๊ณ ๋ฐ์
+URLConf
- URL pattern์ ์ ์ํ๊ณ URL๊ณผ View๋ฅผ ๋งคํํจ
View
1
2
3
4
5
| from .models import *
from django.http import HttpResponse, HttpResponseRedirect #, Http404
from django.shortcuts import render, get_object_or_404
from django.urls import reverse
from django.db.models import F
|
1
2
3
4
5
6
7
8
9
| # ์น ์๋ฒ๋ ์์ฒญ์ ์๋ตํ๋ ์ญํ ์ด๊ธฐ ๋๋ฌธ์, ์์ฒญ์ ๋ฐ๊ณ ์๋ต์ ๋ฐํํ๋ ๊ธฐ๋ฅ์ด ํ์
def index(request):
# '-pub_date' : pub_date ๊ธฐ์ค "์ญ์"์ผ๋ก
latest_question_list = Question.objects.order_by("-pub_date")[:5]
# context = {"{Template ๋ณ์(?) ์ด๋ฆ}": ๊ฐ}
context = {"questions": latest_question_list}
# request์ ๋ํด context๋ฅผ ๋๊ฒจ 'polls/index.html' template๋ฅผ ๋ ๋๋งํ๋ค.
return render(request, "polls/index.html", context)
|
1
2
3
4
5
6
7
8
9
10
| def detail(request, question_id):
""" Http404๋ฅผ ํ์ฉํ๋ ๋ฐฉ๋ฒ
try:
question = Question.objects.get(pk=question_id)
except Question.DoesNotExist:
raise Http404("Question does not exist")
"""
# Django์์ ์ ๊ณตํ๋ 404 Shortcut
question = get_object_or_404(Question, pk=question_id)
return render(request, "polls/detail.html", {"question": question})
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| def vote(request, question_id):
question = get_object_or_404(Question, pk=question_id)
try:
selected_choice = question.choice_set.get(pk=request.POST["choice"])
except (KeyError, Choice.DoesNotExist):
return render(
request,
"polls/detail.html",
{
"question": question,
"error_message": f"์ ํ์ด ์์ต๋๋ค. id={request.POST['choice']}",
},
)
else:
# ๋์์ ๋ ์๋ฒ์์ ๊ฐ์ ์ ํ์ ํ ๊ฒฝ์ฐ, ๊ฐ์ ์ ๋๋ก ๋ณ๊ฒฝํ๊ธฐ ์ํด
# db์์ ๊ฐ์ ์ฝ์ด ๊ณ์ฐ ์งํ
selected_choice.votes = F("votes") + 1 # F : django db
selected_choice.save()
# vote template๋ฅผ renderํ์ง ์๊ณ , result page๋ก redirect
return HttpResponseRedirect(reverse("polls:result", args=(question_id,)))
|
1
2
3
| def result(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, "polls/result.html", {"question": question})
|
Template
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| {% if questions %}
<ul>
{% for question in questions %}
<li>
<a href="{% url 'polls:detail' question.id %}">
{{question.question_text}}
</a>
</li>
{% endfor %}
</ul>
{% else %}
<p>no questions</p>
{% endif %} {% comment %} template์์๋ ์ธ๋ฑ์ฑ์ . ์ฌ์ฉ questions[0] : X
questions.0 : O appname ์ค์ ํ์ง ์์ ๊ฒฝ์ฐ : url 'detail' appname ์ค์ ํ ๊ฒฝ์ฐ :
url 'polls:detail' '{app_name : name}' in urls.py {% endcomment %}
|
detail.html
: Using form
to get input from User
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| <form action={% url 'polls:vote' question.id %} method='post'>
{# django์์ ์๋์ผ๋ก ํ ํฐ ์์ฑ #}
{% csrf_token %}
<h1>{{ question.question_text }}</h1>
{% if error_message %}
<p>
<strong>{{ error_message }}</strong>
</p>
{% endif %}
{% for choice in question.choice_set.all %}
<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{choice.id}}">
<lable for="choice{{ forloop.counter }}">
{{ choice.choice_text }}
</lable>
<br>
{% endfor %}
<input type="submit" value="Vote">
</form>
|
1
2
3
4
5
6
| <h1>{{ question.question_text }}</h1>
<br />
{% for choice in question.choice_set.all %}
<lable> {{ choice.choice_text }} -- {{ choice.votes }} </lable>
<br />
{% endfor %}
|
URL Config
1
2
3
4
5
6
7
8
9
10
11
12
| from django.urls import path
from . import views
app_name = "polls" # app_name์ด ์ค์ ๋ ๊ฒฝ์ฐ, polls:detail, polls:vote ๋ฑ app_name์ ํ์์ ์ผ๋ก ํฌํจํ์ฌ ํธ์ถํด์ผ ํจ
urlpatterns = [
path("", views.index, name="index"),
# <int:question_id>/ : ์ฌ์ฉ์๊ฐ ์
๋ ฅํ๋ ์ฃผ์๋ฅผ ํตํด question_id๊ฐ ์ ๋ฌ๋จ
path("<int:question_id>/", views.detail, name="detail"),
path("<int:question_id>/vote/", views.vote, name="vote"),
path("<int:question_id>/result/", views.result, name="result"),
]
|
Customizing Admin page
1
2
3
4
5
6
7
8
9
10
| class Question(models.Model):
# verbose_name ์ผ๋ก ๋๊ฒจ์ค ๋ฌธ์์ด์ด admin page์์ ์ ๋ชฉ์ผ๋ก ํ์๋๋ค.
question_text = models.CharField(max_length=200, verbose_name="์ง๋ฌธ")
pub_date = models.DateTimeField(auto_now_add=True, verbose_name="์์ฑ์ผ")
# admin page display๋ฅผ ํ์ํ๋ ๋ฐฉ์์ ๋ณ๊ฒฝํ๋ค.
@admin.display(boolean=True, description="์ต๊ทผ์์ฑ(ํ๋ฃจ๊ธฐ์ค)")
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
...
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| from django.contrib import admin
from .models import *
# StackedInline, TabularInline
# Question admin page์์ ์ฐ๊ฒฐ๋ Choice๋ฅผ Inline ํํ๋ก ์ถ๋ ฅํ๊ธฐ ์ํ class
class ChoiceInline(admin.TabularInline):
model = Choice
extra = 2 # ์ถ๊ฐ ๋ฑ๋ก ์นธ
# Question admin page customizing
class QuestionAdmin(admin.ModelAdmin):
fieldsets = [
("์์ฑ์ผ", {"fields": ["pub_date"], "classes": ["collapse"]}), # collapse : ์จ๊น์ฒ๋ฆฌ
("์ง๋ฌธ ์น์
", {"fields": ["question_text"]}),
]
list_display = ["question_text", "pub_date", "was_published_recently"]
readonly_fields = ["pub_date"] # cannot modify.
inlines = [ChoiceInline]
list_filter = ["pub_date"] # filter records by pub_date
search_fields = ["question_text", "choice__choice_text"]
# register Question to admin site with customized page "QuestionAdmin"
admin.site.register(Question, QuestionAdmin)
|
๐ย CHECK
(์ด๋ ต๊ฑฐ๋ ์๋กญ๊ฒ ์๊ฒ ๋ ๊ฒ ๋ฑ ๋ค์ ํ์ธํ ๊ฒ๋ค)
โ ๋๋ ์
์ค๋์ ์ ์ผ ๋ง์ ๋ค์ง ์๋ TIL ์ธ ๊ฒ ๊ฐ๋ค. ์ผ๋จ ์ ๋ฆฌ๋ ์ ๋๋ก ์๋๊ณ , ์ฉ์ด๋ ์ ๋๋ก ๊ธฐ์ต์ ๋ชปํ๋ค. ๊ฐ์๋ฅผ ๋ค์ ๋ณด๋ฉด์ ๊ฐ์ฌ๋์ด ์ฌ์ฉํ๋ ์ฉ์ด๋ฑ์ ์ฒดํฌํ๊ณ ์์ฑํ์ผ๋ฉด ์ข์๊ฒ ์ง๋ง ์๊ฐ์ด ๋น ๋ฏํ๊ธฐ๋ ํ๊ณ ์ง์ค๋ ์ ์๋ผ์ ์ ๋๋ก ๋ชป ์ ์๋ค.
๋ด์ผ ์ค์ ์๊ฐ์ด ๋๋ฉด ์ค๋ ๊ฐ์๋ฅผ ๋ค์ ๋ค์ผ๋ฉด์ ์์ ์ ์ข ํ๊ณ ์ถ๋ค. ๋ด์ผ ๋ชปํ๋๋ผ๋ ์ฃผ๋ง์๋ ๊ผญ ํ ์๊ฐ์ด๋ค.
์ด์ ์ค๋ ๋ฐฐ์ด ๋ด์ฉ๋ค์ ์๋ฌด๋๋ ํ๋ก์ ํธ๋ฅผ ํ๋ฉด์ ์ง์ ๋ ์ฐพ์๋ณด๊ณ ์ฌ์ฉํด๋ด์ผ ์ ๋๋ก ์ดํดํ ๊ฒ ๊ฐ๋ค. View์ Template, URL Config๊ฐ ํ๋ ์ญํ ์ ์ดํด๋ ๊ฐ๊ณ ํ์ฉํด์ ๋ค๋ฅธ ํ์ด์ง๋ฅผ ๋ง๋ค์ด๋ณด๋๊ฒ๋ ํ ์ ์๋ค. ๊ทธ๋ฐ๋ฐ ๊ฐ๊ฐ์ ํ๋๋ ํ์ฉ ๊ฐ๋ฅํ ๋ฉ์๋ ๋ฑ ๊น๊ฒ ๋ค์ด๊ฐ๊ธฐ ์์ํ๋ฉด ๋ง์ด๋ ๊ธ๋ก ํ์ด์ ์ค๋ช
ํ๋๊ฒ ๋๋ฌด ์ด๋ ต๋ค. ๊ทธ๋ฆฌ๊ณ ํ๊ต๋ฅผ ๋ค๋๋ฉด์ ์์ด๋ก ๋ term์ ๋ ์์ฃผ ์ ํด์ ๊ทธ๋ฐ๊ฐ.. TIL์ ์ ์ ๋์๋ ํ๊ตญ์ด๋ก ์ค๋ช
ํ๊ธฐ ์ ๋งคํ๊ณ ์ด๋ ค์ด ์ฉ์ด๋ค์ ๋ฌด์กฐ๊ฑด ์์ด๋ก ์ ๋ ์ต๊ด์ด ์๋ค.
์์ฆ ๊ฐ์๋ค์ ์ค์ต ์์ฃผ๋ผ ๊ทธ๋ฐ์ง TIL์ ์ฝ๋์ ์ฃผ์ ์์ฃผ๋ก๋ง ์ ๋ ๊ฒฝํฅ์ด ์๋๋ฐ, ๋ค๋ฅธ ๋ฐฉ์์ผ๋ก ์ ์ด๋ณด๊ณ ์ถ๋ค. ์์ ์ ์ฐพ์๋ TIL ์ฐธ๊ณ ๋งํฌ์, ๋ถํธ์บ ํ๋ฅผ ์ฐธ๊ฐ์๋ค ๋ธ๋ก๊ทธ๋ฅผ ๋ณด๋ฉด์ ์ ์ด TIL๋ค์ ์ฐธ๊ณ ํด๋ด์ผ๊ฒ ๋ค.