ํ์คํ ์น๐ ๊ฐ๋ฐ์ ์ง๋ง์ ๐ง๐ฝโ๐ป
โ ์ธ๊ณต์ง๋ฅ ๊ด์ฌ ๐ค
Categories
-
โฃ
โถ COMPUTER_SCIENCE
๐: 7 -
โฃ
โถ WEB
๐: 3 -
โฃ
โถ ETC
๐: 3-
โ
โฃ
ETCS
๐: 10 -
โ
โฃ
SUBBRAIN ๊ฐ๋ฐ๊ธฐ
๐: 5 -
โ
โ
YOS ๊ฐ๋ฐ๊ธฐ
๐: 1
-
โ
โฃ
-
โ
โถ AI
๐: 9-
โฃ
AITOOLS
๐: 3 -
โฃ
CV
๐: 2 -
โฃ
DEEP_LEARNING
๐: 1 -
โฃ
DATA_VIS
๐: 2 -
โฃ
GRAPH
๐: 1 -
โฃ
LIGHTWEIGHT
๐: 1 -
โฃ
MATH
๐: 1 -
โฃ
NLP
๐: 3 -
โ
STRUCTURED_DATA
๐: 2
-
โฃ
Django ๊ธฐ๋ณธ
- django์ ๊ฐ๋
- MVC(Model View Controller), MTV(Model Template View) ํจํด
- django ์์ฑ๋ฒ๊ณผ ๊ฐ์ํ๊ฒฝ์ค์
- django ์ฑ ์ถ๊ฐ ๋ฐฉ๋ฒ
- url๋ก ์ฑ์ ๋ณ์ ๋๊ฒจ์ฃผ๊ธฐ (variable routing)
- DTL (django template language)
- ERD ( Entity Relationship Diagram)
- if ๋ฌธ์ ์ด์ฉํ restfullํ ์น์ฝ๋ฉ
django ํ๋ ์์ํฌ
django์ ๊ฐ๋
django ํด๋ ์ฐธ์กฐ
- ๋ค์ ๋ ์ ์
- ๊ด์ฉ์
- ์ ์ ์ธ ์น์ ๋์ ์ธ ์น์ผ๋ก ๋ฐ๊ฟ
- ๊ธฐ๋ณธ์ ์ธ ๊ตฌ์กฐ, ํ์ํ ์ฝ๋๋ฅผ ์ ๊ณตํด์ค
- ์ ํ๋ธ, ๋์ฌ, ์ธ์คํ๊ทธ๋จ ๋ฑ
MVC(Model View Controller), MTV(Model Template View) ํจํด
- MVC(model view controller) ํจํด : ๋ชจ๋ ์น ์๋น์ค๋ผ๋ฉด ๋ชจ๋ ๊ฐ์ง๊ณ ์๋ ๋์์ธ ํจํด
- MTV(model template view) : ํ์ด์ฌ์ด ๋ฐ๊พผ ์ด๋ฆ, ํ์คํฐ ์ ใ
- ๋ชจ๋ธ: ๋ฐ์ดํฐ๋ฅผ ๊ด๋ฆฌ, ๋ฐ์ดํฐ ๋ฒ ์ด์ค ๊ทธ ์์ฒด
- ํ ํ๋ฆฟ : ์ฌ์ฉ์๊ฐ ๋ณด๋ ํ๋ฉด,
- ๋ทฐ : ์ค๊ฐ ๊ด๋ฆฌ์ ์์ฒญ์ ๋ฐ์์ ๋ชจ๋ธ์๊ฒ ๋ฐ์ดํฐ ์ฐพ์ผ๋ผ๊ณ ๋ช ๋ นํ๊ณ ๋ชจ๋ธ์๊ฒ์ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์๋ค ํ ํ๋ฆฟ์ผ๋ก ๋ณด๋
## django_intro ํด๋ (ํ๋ก์ ํธ ํด๋) ๋ด๋ถ ํ์ผ
__init__.py : ํจํค์ง๋ก ์ธ์ํ๊ฒ ํด์ค
wsgi.py : ์น์๋ฒ ๊ฒ์ดํธ์จ์ด ์ธํฐํ์ด์ค
settings.py : ์ฌ๋ฌ๊ฐ์ง ์ค์ ์ ๊ด๋ จ๋ ๊ฒ
urls.py : flask์ app.route ์ญํ
django-admin startapp pages : pages ํด๋๋ฅผ ๋ง๋ฌ ๋ด๋ถ ๊ตฌ์กฐ๋ ์๋นํ ์ ์ฌํจ
admin.py : ๊ด๋ฆฌํ๋ ๊ณต๊ฐ
apps.py : ์ก์๋ํ ์ค์
models.py : ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๊ด๋ จ๋ ๊ฒ Mใ
TV ๊ด๋ จ
testsp.py : ํ
์คํ
์ฉ
views.py : ์ค๊ฐ๊ด๋ฆฌ์ MTV ๊ด๋ จ
์ฅ๊ณ ๋ ํ๋ก์ ํธ ๋ด๋ถ์ ์ฌ๋ฌ๊ฐ์ง ์ฑ์ ๋ง๋๋ ํ์
settings.py์ Installed_Apps ๋์ pages๋ฅผ ๋ฑ๋กํ๋ฉด ์ฑ์ ๋ฑ๋กํ๋ ํ์์ (์ปค์คํ ์ ๋งจ์์ ๋์ ๊ฒ์ ๊ถ์ฅ, ์ด๋ฆ์ด ๊ฐ์ผ๋ฉด ๋งจ์ ๋ฆฌ์คํธ์ ์๋ ๊ฒ์ ๊ฐ์ ธ์ด)
USE_I18N = ์์์๋ Lanugate_code ๋ฅผ ์ฌ์ฉํ ๊ฒ์ธ๊ฐ?
django ์์ฑ๋ฒ๊ณผ ๊ฐ์ํ๊ฒฝ์ค์
1. mkdir 13workshop
2. cd 13workshop
3. python -m venv venv
4. source venv/Scripts/activate
5. pip install django
6. django-admin startproject classroom . (. ์์ฐ์ผ๋ฉด ๊ฐ์ ์ด๋ฆ์ ํด๋๋ฅผ ์ถ๊ฐ ํ ์์ฑ)
7. python manage.py runserver
์ ํ:
.gitignore ํ์ผ ์์ ์ค์
django-admin startapp pages๋ก pages ์ฑ ์์ฑ (ํ๋ก์ ํธ ํด๋ ๋ฐ๊นฅ์์?)
python manage.py startapp your_app_name (์ฑ ์์ฑ 2)
๊ฐ์ ํ๊ฒฝ ์ค์ : ์น ๋๋ฒจ๋กํ์ ํ์ํ ๋ชจ๋๋ง python์ ์๋๊ฒ (์๋ฅผ๋ค์ด jupyter ๊ฐ์๊ฑฐ ํ์ ์์)
python -m venv ํด๋์ด๋ฆ : ์ฒ์ venv๋ ๋ฒ์ ํ๊ฒฝ(version environment)์ ์ค๋ง ํด๋น ๋๋ ํ ๋ฆฌ์ ํด๋์ด๋ฆ์ด ๋์ด์๋ ๊ฐ์ํ๊ฒฝ์ ๋ง๋ค์ด์ค
๋๋ ํ ๋ฆฌ ์์์ source ํด๋์ด๋ฆ/Scripts/activate ํ๋ฉด (๋๋ ๊ฑฐ๊ธฐ์ ๊ทธ ํ์ผ์ ํด๋ฆญ) (venv)๋ผ๋ ํค์๋๊ฐ ํฐ๋ฏธ๋์ ๋ธ
์์์ ์ธ๋ชจ์๋ ํจํค์ง๊ฐ ์์ด์ง
deactivate ํ๋ฉด ๋ค์ ์ฌ๋ผ์ง
๋๋ vscode์์ f1์ผ๋ก select interpreter์ ๊ณ ๋ฅธํ, venv ํ๊ฒฝ์ ํ์ด์ฌ์ ๊ณ ๋ฅด๋ฉด ํฐ๋ฏธ๋์์ (venv)๊ฐ ํ์ฑํ ๋์ด์์
django-admin startproject django_intro . ๋ก ํ์ฌ ํด๋์ ํ๋ก์ ํธ ์์ฑ
python manage.py runserver ๋ก ์๋ฒ ๋๋ฆฌ๊ธฐ
django-admin startapp pages๋ก pages ์ฑ ์์ฑ
python manage.py startapp your_app_name (์ฑ ์์ฑ 2)
django ์ฑ ์ถ๊ฐ ๋ฐฉ๋ฒ
๋๋ต์ ์ธ ํ๋ฆ :
1. urls.py์์ urlpatterns ๋ฆฌ์คํธ์ path("url์ด๋ฆ/", views.url์ด๋ฆ), ์ ๋ฑ๋ก , 2๋ฒ์งธ views.url์ด๋ฆ์ views.py์ ์ฌ๋ผ๊ฐ๋ ํจ์ ์ด๋ฆ์, 1๋ฒ์งธ url ์ด๋ฆ ๋ค์ / ํ์ (django๊ฐ ์๋์ผ๋ก ๋ง์ง๋ง์ /๋ฅผ ๋ถ์ด๋ฏ๋ก ์์ผ๋ฉด ์ ๋ ์ ๊ทผํ ์ ์์)
2. views.py์ url์ด๋ฆ๊ณผ ๊ฐ์ ํจ์(๋๋ 1๋จ๊ณ์ ์ ์ํ 2๋ฒ์งธ ์ธ์)๋ฅผ ์ ์ (request๋ ๋ฌด์กฐ๊ฑด ์ฒ์ ์ธ์์ ํฌํจ),
3. return์ผ๋ก render(request, 'html์ด๋ฆ', context), context๋ ๋๊ฒจ์ค ์ธ์๋ค์ dictionary,
4. pages ํด๋์ templatesํด๋๋ด์ url์ด๋ฆ.html์ ํ์ผ ๋ง๋ค๊ณ html ์ฝ๋ ๊ตฌ์ฑ,
5. ์ธํฐ๋ท์ ํด๋น url๋ก ๊ฐ๋ณด๋ฉด ์์ฑ
url๋ก ์ฑ์ ๋ณ์ ๋๊ฒจ์ฃผ๊ธฐ (variable routing)
https://์๋ฒ์ฃผ์/greeting/์ค์ค์/
path(โgreeting/
path(โmul/
url namespacing
- url์ html ํ์ผ์ ํ์ดํผ๋งํฌ๋ก ๋๊ฒจ์ค ๋, DTL์ ์ด์ฉํ์ฌ ๋ณ์ํํด์ ๋๊ฒจ์ค ์ ์๋ค.
namspacing ์์์ ๊ธฐ์กด์ url ํ ๋น๋ฒ(๋ฐ)
```html
<a href="{% url 'todos:index' %}">์ ์ฒด๊ธ๋ณด๊ธฐ</a>
<a href="/todos/new/">์๋ก ๊ฒ์๊ธ ์์ฑํ๊ธฐ</a>>
- ๊ธฐ์กด์ url ํ ๋น ๋ฒ์์๋ /๋ฅผ ๋งจ ์์ ์ถ๊ฐํ๋ฉด root ์ฃผ์ ์์ ํด๋น ์ฃผ์๋ฅผ ์ถ๊ฐํ๋ค๋ ์๋ฏธ์ด๋ค
- /๊ฐ ์๋ค๋ฉด ํ์ฌ ์ฃผ์์ ์ถ๊ฐ๋ก /๋ฅผ ๋ถ์ฌ์ ์ถ๊ฐํ๋ค๋ ์๋ฏธ์ด๋ค
> ์ ๊ธฐ์กด url ํ ๋น๋ฒ์ /๊ฐ ์๋ ์์
```html
&#60;a href="new/"&#62;์๋ก ๊ฒ์๊ธ ์์ฑํ๊ธฐ&#60;/a&#62;
-
์ด๋ ๊ฒ ํ๋ฉด ๊ธฐ์กด์ ๊ฒฝ๋ก์ ์ถ๊ฐ๋๋ ํ์, ์ด๊ฒ์ ์ ๊ฒฝ ์ฐ๊ธฐ ํ๋๋ฏ๋ก ๋ณ์ํ (namespacing)ํ๋ค.
-
๋ค์ ์คํ์ด์ฑ์ ์ํด ๋จผ์ ํด๋น ์ฑ์ ์ฑ ๋ค์์ ์ ์ธํ๋ค
์ฑ๋ค์ ์ ์ธ ์์(urls.py)
```python
from django.urls import path
from . import views
app_name = 'todos' # ์ผ๋ฐ์ ์ผ๋ก ์ฑ ์ด๋ฆ๊ณผ ๊ฐ์ ์ด๋ฆ์ ๋ฃ์
urlpatterns = [
path('', views.index, name="index"),
path('new/', views.new, name="new"),# ํผ ๋ณด์ฌ์ฃผ๊ธฐ
path('create/', views.create, name="create"), # ๋ฐ์ ํผ์ ์ ๋ณด๋ฅผ ์ ์ฅํ๊ธฐ
path('<int:id>/delete/', views.delete, name="delete"), # ๋ณ์๋ก ์ด์ฉํ๋ฉด ์ฌ๊ธฐ์๋ง / ์ ๊ฒฝ์ฐ๋ฉด ๋จ
# ๋์ /๋ฅผ ๊ผญ ๋ถ์ฌ์ฃผ์.
]
- ์ด๋ฅผ ํด์ฃผ๋ฉด ๋ค๋ฅธ ์ฑ์์ url ๋ณ์๊ฐ ๊ฒน์ณ๋ ๋ฌธ์ ๊ฐ ์๊ธฐ์ง ์๋๋ค.
- ๋ํ ๋ณ์ํํ path ํจ์์ name์ ๋ณ์๋ช
์ ๋ฃ์ด์ฃผ๋ฉด ๋๋ค.
> variable routing ์ด ์ ์ฉ๋ namespacing ์์
```html
&#60;a href="{% url 'todos:delete' todo.id %}"&#62;์ญ์ &#60;/a&#62;
- ํ๋ฐ์ดํ ์๋ฐ์ดํ๋ฅผ ๋ฒ๊ฐ์๊ฐ์ ์ฐ์ง ์์๋ ๋๋, ๊ทธ๋ฌ๋ฉด python ๋ฌธ๋ฒ์ผ๋ก ์ธํด ๋ณด๊ธฐ ํํด์ง๋ค.(๊ถ์ฅ)
- โ{% url โ์ฑ์ด๋ฆ:url๋ณ์๋ช โ ๋งค๊ฐ๋ณ์1๊ฐ, ๋งค๊ฐ๋ณ์ 2๊ฐ..%}โ๋ฅผ ํ์ดํผ๋งํฌ๋ก ๋ฃ์ด์ฃผ๋ฉด ๋๋ค.
- variable routing์ผ ๊ฒฝ์ฐ url ๋ณ์ ๋ฃ๊ธฐ ์์๋ณด๊ธฐ (todos์ index.html)
DTL (django template language)
: jinja๋ ๋ฌธ๋ฒ์ด ์๋นํ ๋น์ทํจ
for๋ฌธ ์์
```html
{% for menu in menus %}
<li>{{forloop.counter}} : {{menu}}</li>
{% empty %}
<p>๋ฆฌ์คํธ๊ฐ ๋น์ด์์ต๋๋ค.</p>
{% endfor %}
<!โforloop.counter:for๋ด๋ถ์์๋ง ์ฌ์ฉ๊ฐ๋ฅํจ ๋ฐ๋ณต ์ซ์ ํ์ํด์ค enumerate ์ฒ๋ผ ์ธ์ ์์, ๋ฌธ์ฅ์ {% ์ฌ์ด์ ์คํ์ด์ค๋ฐ๋ก ๋์ด์ %}, ๋ณ์๋ {%์๋์%}
{% empty %}๋ ๋ง์ฝ ํด๋น ๋ฆฌ์คํธ๊ฐ ๋น์ด์๋ค๋ฉด ์๋ ์ฝ๋๊ฐ ์คํ๋จโ>
- ๋ง์ฝ ๋ฆฌ์คํธ์ ์์์ ์ธ๋ฑ์ค๋ก ์ ๊ทผํ๊ณ ์ถ์ผ๋ฉด {{๋ณ์.์ธ๋ฑ์ค}}๋ก ์ ๊ทผํ ์ ์๋ค.
- ex) student.0
- forloop + first๋ last๋ฅผ ์น๋ฉด ์ฒ์ ์์๋ ๋ง์ง๋ง ์์์ผ๋ true๋ฅผ ๋ฐํํ๋ค.
> ์กฐ๊ฑด๋ฌธ ์์
```html
&#60;h3&#62;์กฐ๊ฑด๋ฌธ&#60;/h3&#62;
{% if 'ํ์' in menus %}
&#60;p&#62;์ญ์ ํ๊ตญ์ด๋ผ๋ฉด ํ์์ด์ง&#60;/p&#62;
{% endif %}
์กฐ๊ฑด๋ฌธ๊ณผ else๋ฌธ, elif๋ฌธ, for๋ฌธ๊ณผ์ ์ค์ฒฉ ์์
```html
{% for menu in menus %}
<p>{{forloop.counter}}๋ฒ์งธ ๋ฐ๋ณต๋ฌธ ๋๋์คโฆ</p>
{% if 'ํ์' == menu %}
<p>์ญ์ ํ๊ตญ์ธ์ ํ์์ด์ง</p>
{% elif '์ผ์' == menu %}
<p>์ด๊ฒ๋ ๋ถ๋งค ์ด๋ ํด์ผํ๋?</p>
{% else %}
<p>{{menu}}</p>
{% endif %}
{% endfor %}
- DTL ๋ด๋ถ์์๋ ๊ดํธ()๋ฅผ ์ธ ์ ์๋ค.
- ์ ๋งํ๋ฉด ํ๋จ์ views์์ ๋จผ์ ํ์
1) ํจ์ ์์์ ๋ค๋ฅธ ํ์ด์ง์ ํผ์์ ์
๋ ฅํ ๋ฐ์ดํฐ ๋ฐ๊ธฐ (๋์
๋๋ฆฌ ํํ)
request.GET.get('name')
- queryDict๋ผ๋ ์๋ก์ด ํ์์ด๋ฏ๋ก GET์ ํตํ์ฌ ํ๋ฒํ dict๋ก ๋ง๋ ๋ค, get() ๋ฉ์๋๋ก ๋ฐ๋๊ฒ
- url์๋ _(์ธ๋๋ฐ)๋ฅผ ์ฐ๋ฉด ํ์ดํผ๋งํฌ ์ ์ฉ์ ํ๋ ์๋ซ์ค ๋๋ฌธ์ ์๋ณด์ด๋ฏ๋ก ์ ๋งํ๋ฉด -(ํ์ดํ)์ ์ฐ์
<form action="/post-pong/" method="POST">
{% csrf_toekn %}
<input> ์ด์ฉ๊ตฌ ์ ์ฉ๊ตฌ
</form>
- method ์๋ฃ์ผ๋ฉด ๊ธฐ๋ณธ GET ๋ฐฉ์, ๋์๋ฌธ์ ๊ตฌ๋ถ ์ํจ
- POST๋ฅผ ๋ฃ์ผ๋ฉด ์ข๋ ์์ ํ๊ณ CSRF์ ๋๋นํ๋ฏ๋ก csrf_token ํ์,
- ์ด๋๋ requset.POST.get('name') ๋ฐฉ์์ผ๋ก ๋ฐ์์์ผํจ
- {% csrf_token %}์ ํผ์์ ๋ฃ์ด์ ํ ํฐ ๋ถ์ฌ ํ๋ฉด ์ํธํ? ๊ฐ์๊ฒ ๋จ
- csrf_token = ๋๋คํ ๋ฌธ์์ด์ ์์ฑํด์ค type="hidden"์ด ๋์ด์ ๋๋ค ๋ฌธ์์ด์ ์ธ์ฆํด์ค
- ์ด๋ฌ๋ฉด URL์ ํด๋น ๋ฐ์ดํฐ๋ค์ด ๋ณด์ด์ง ์์, ๊ฐ๋ฐ์๋๊ตฌ ํค๋์ค์์์ formdata์์ ํ์ธ ๊ฐ๋ฅ
- GET์ ๋ณด๋ด์ฃผ์ธ์, POST๋ ์ฒ๋ฆฌํด์ฃผ์ธ์ ๋ผ๋ ์๋ฏธ
- GET : ์๋ฒ์ ๋ฐ์ดํฐ๋ฅผ ๋ณํ์ํค์ง ์์
- POST : ์๋ฒ์ ๋ฐ์ดํฐ๋ฅผ ๋ณํ์ํด (๋๋ถ๋ถ์ ๋ฐ์ดํฐ ์ด์ฉ์ ์ ํฉ)
CSRF : ์ฌ์ดํธ๊ฐ ์์ฒญ ์์กฐ ๊ณต๊ฒฉ,
## static ํค์๋๋ก ํ์ผ๊ฐ์ ธ์ค๊ธฐ, static ํ๋ค : ๋ณํ๊ฐ ์๋ค
> base.html block ์ค์
```html
&#60;!DOCTYPE html&#62;
&#60;html lang="en"&#62;
&#60;head&#62;
&#60;meta charset="UTF-8"&#62;
&#60;meta name="viewport" content="width=device-width, initial-scale=1.0"&#62;
&#60;meta http-equiv="X-UA-Compatible" content="ie=edge"&#62;
&#60;title&#62;Document&#60;/title&#62;
&#60;/head&#62;
&#60;body&#62;
&#60;h1&#62;Base is everywhere!&#60;/h1&#62;
{% block body1 %}
{% endblock %}
{% block body2 %}
{% endblock %}
&#60;/body&#62;
&#60;/html&#62;
- ํ๋น์ฝ(favicon) : ์นํ์ด์ง ์ด๋ฆ ์์ ์๋ ์์ ์์ด์ฝ
ํ๋น์ฝ ์ถ๊ฐ ๋ฐฉ๋ฒ
```html
์ฑ ๋ด๋ถ์ static ํด๋ ์์ฑ, ๊ทธ ๋ด๋ถ์ ํ๋น์ฝ์ผ๋ก ์ธ ์ด๋ฏธ์ง ํ์ผ ์ถ๊ฐ
html ํ์ผ ๋งจ ์์ ๋งจ ์์ค์{% load static %} ์ถ๊ฐ
html header์ <link rel="icon" href="{% static 'staticํด๋ ๋ด์ ํ์ผ ์ด๋ฆ.ํ์ผํ์ฅ์' %}"> ์ถ๊ฐ(ico, png ํ์ฅ์ ์ง์)
> static ํค์๋์ ์ฌ์ฉ๊ณผ block ์ฌ์ฉ
```html
{% extends 'base.html' %} # base.html์์ block์ ๊ฐ์ ธ์จ๋ค๋ ์๋ฏธ ํ ํ์ผ์ 1๊ฐ๋ง ํ์ฉ
{% load static %}
&#60;!--ํด๋ ๊ฒฝ๋ก๋ ์ฑ ๋ด์ staticํด๋์ cssํด๋ ๋ด๋ถ--&#62;
{% block body1 %} # body1 block ๊ฐ์ ธ์ค๊ธฐ
&#60;link rel="stylesheet" href="{% static 'css/style.css' %}"&#62;
&#60;h1&#62;๋ณธ์ค๋ณธ์ค&#60;/h1&#62;
&#60;img src="{% static 'image/feelthethunder.jpeg' %}" alt=""&#62;
{% endblock %} # body1 block ๋ซ๊ธฐ
{% block body2 %}# body2 block ๊ฐ์ ธ์ค๊ธฐ
{% endblock %}# base.html์ 2๊ฐ์ด์ ์ ์ํ์ ๊ฒฝ์ฐ
- ์ฅ๊ณ ๋ฌธ๋ฒ์์ static์ ๋ณํ์ง ์์ ์ ๋ณด์ ๋ถ์ฌ์ ๊ฐ์ ธ์ค๋๋ฐ ์ด๋ค.
- ๋๋ถ๋ถ ์๋ฒ๋ฅผ ๊ป๋ค ์ผ์ผ์ง ๋ณํ๊ฐ ์ ์ฉ๋จ, ์์ธ๋ ์์
- load static์ extends ๋ฐ์ ์จ์ ํค์๋๋ฅผ ์ฌ์ฉํ ์ ์๊ฒ ๊ฐ์ ธ์์ผํ๋ค.
- ๋ณดํต ๊ด๋ก์ ํด๋ ์ด๋ฆ์ static์ผ๋ก ํ๋ค.
3) ๋ง์ฝ ๋ค๋ฅธ ์ฑ์๋ ๊ฐ์ URL์ path๊ฐ ์๋ค๋ฉด ์ด๋ป๊ฒ ํ ๊ฒ์ธ๊ฐ?
master urls.py, ํ๋ก์ ํธ ํด๋์ ์๋ urls.py
```
from django.contrib import admin
from django.urls import path, include # django.urls ํจํค์ง์ include ๊บผ๋ด์ด
from pages import views
path('pages/', include('pages.urls')), # pages ํด๋์ ์๋ธ urls.py์ url๋ค์ ๊ฐ์ ธ์จ๋ค, include๋ ํด๋น ํด๋์ ํด๋น ํ์ผ์ ๊ฐ์ ธ์ค๋ ํจ์
path('utilities/', include('utilities.urls')), # utilities ํด๋์ ์๋ธ urls.py์ url๋ค์ ๊ฐ์ ธ์จ๋ค
> sub urls.py, pages ํด๋(์ฑ)์์ ์๋ urls.py
from django.urls import path
from . import views # . ํ์ฌ ํด๋
urlpatterns = [
path('ping/', views.ping),
path('pong/', views.pong),
path('post-ping/', views.post_ping),
path('post-pong/', views.post_pong),
path('static-example/', views.static_example),
]
- ๋ง์ฝ pages์ ping url์ ์ ๊ทผํ๊ณ ์ถ์ผ๋ฉด https://์๋ฒ ์ฃผ์/pages/ping/ ์ผ๋ก ์ ๊ทผ ๊ฐ๋ฅํ๋ค.
- ๋ง์คํฐ urls.py๊ฐ pages์ urls.py๋ก ๊ถํ๊ณผ ์์ฒญ์ ๋๊ธฐ๋ ํ์
### SQL ORM
#### DB
- ๋ฐ์ดํฐ๋ค์ ๋ชจ์
- ์ด, ์นผ๋ผ, ๊ฐ ์ด์๋ ๊ณ ์ ํ ๋ฐ์ดํฐ ํ์์ด ์ง์ ๋จ, ๋ฐ์ดํฐ์ ์์ฑ
- ํ, ๋ ์ฝ๋, 1๊ฐ์ ๋ฐ์ดํฐ
- ์คํค๋ง, ํ ๊ฐ ์ด์ ์์, ์ฆ ๋ค์ด๊ฐ ๋ฐ์ดํฐ์ ๋ด์ฉ์ ์ ์ํจ
#### ORM(Object-Relational Mapping)
- SQL์ด ๋ชฐ๋ผ๋ ํ์ด์ฌ ๋ฌธ๋ฒ์ผ๋ก ํ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ธ์ด, ํ์ด์ฌ ์ธ์ด(์ด์, ์ฒญ์ฌ์ง)์ SQL ๋ฌธ์ผ๋ก ํด์ํด์ค, ์ค๊ฐ ๋ฒ์ญ์
### CRUD
- C: CREATE, ๋ฐ์ดํฐ ์์ฑ
- R: READ, ๋ฐ์ดํฐ ์ฝ๊ธฐ
- U: UPDATE, ๋ฐ์ดํฐ ๋ณ๊ฒฝ
- D: DELETE, ๋ฐ์ดํฐ ์ง์ฐ๊ธฐ
- ๋ฐ์ดํฐ๋ก ํ ์ ์๋ 4๊ฐ์ง
#### ORM ์ฌ์ฉ๋ฒ๊ณผ GIT BASH ๋ช
๋ น์ด
django-admin startapp posts : ์ฑ ์์ฑ
> Student ๋ชจ๋ธ ์์ฑ ์์ (์ฑ ๋ด๋ถ์ models.py)
```python
from django.db import models
# Create your models here.
{: #create-your-models-here}
class Student(models.Model):
# ๊ฐ๊ฐ colum ์ ์
{: #๊ฐ๊ฐ-colum-์ ์}
name = models.CharField(max_length=64)
email = models.CharField(max_length=128) # ํ ๋นํ ๋ฉ๋ชจ๋ฆฌ(max_length) ์ค์
birthday = models.DateField()
age = models.IntegerField()
def __str__(self): # str ์ค๋ฒ๋ก๋ฉํ๋ฉด ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ณด์ฌ์ค
return f'์ด ํ์์ ์ด๋ฆ์ {self.name}'
- model์ ๋ฐ๊พธ๋ฉด ๋ค์ migrate๋ฅผ ํด์ค์ผ ์ ๋ฐ์ดํธ ๋๋ฉฐ ์ ๋งํ๋ฉด ๋ฐ๊ฟ์ฃผ์ง๋ง์ (๊ธฐ์กด์ ์ด๋ฏธ ์ถ๊ฐ๋ ๋ฐ์ดํฐ๋ค์ด ๋ง์ฝ์ ๋ถ๋ฆฐ๋ค. ๋ณดํต ๋ค ๋ ๋ฆฌ๊ณ ๋ค์ ๋ง๋ฆ ๋จผ์ ๋ชจ๋ธ๋ง ํ์!)
python manage.py makemigrations : ๋ชจ๋ธ์ 0001_initial.py ์์ฑ (๋ฒ์ญ๊ธฐ๋ก ๋ฒ์ญ ๋ณด๋ด๊ธฐ) (์ผ์ข ์ ๋ฐ์ดํฐ ํ์ ํค๋ ๋ง๋ค๊ธฐ)
Migrations for 'posts':
posts\migrations\0001_initial.py
- Create model Post
# ์ด๋ ๊ฒ ๋ธ
`
python manage.py migrate: ํ์ด์ฌ ์ฝ๋๋ฅผ SQL ์ธ์ด๋ก ํด์ํจ (๋ฒ์ญ๋ณธ DB๋ก ๋ณด๋ด ๋ช
๋ นํ๊ธฐ) (์ผ์ข
์ ๋ฐ์ดํฐ ์์
ํ ๋ง๋ค์ด ๋๊ธฐ ๊ณต๊ฐ๋ง๋ค๊ธฐ)
python manage.py shell (์์ IDE? exit()๋ก ๋๊ฐ) ์์ ๋ง๋ ํด๋์ค๋ฅผ ์ธ์คํด์คํ
๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ฐ์ดํฐ ์ถ๊ฐ ๊ตฌ๋ฌธ
```
post1 = class์ด๋ฆ() ๋๋ post1 = class์ด๋ฆ(์ด์์="๋ด์ฉ",์ด์์2="๋ด์ฉ2")
> ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ฐ์ดํฐ ์ถ๊ฐ ๋ฐ ๋ณ๊ฒฝ ๊ตฌ๋ฌธ
class์ธ์คํด์ค.save()
ํ๋ฉด SQL์ ํด๋น ์ธ์คํด์ค ์ ์ฅ, ๋๋ ๋ฐ์ดํฐ ์์ ์ดํ ๊ทธ ๊ฐ์ฒด๋ ์์ ์ด ์ค์ ํ๋งํผ ๋ฐ์ดํฐ์์ฑ์ ๊ฐ์ง
> ๋ฐ์ดํฐ ์ญ์ ๊ตฌ๋ฌธ
class์ธ์คํด์ค.delete() ํ๋ฉด, ํด๋น ๋ฐ์ดํฐ ์ญ์ ๋จ
Post.objects.all() : Post ํด๋์ค์ ๋ชจ๋ ๊ฐ์ฒด๋ฅผ ์ถ๋ ฅ all(1)ํ๋ฉด QuerySet์ 1๋ฒ์งธ ์์๋ฅผ ๊ฐ์ ธ์ด
Post.objects.get() : 1๊ฐ์ ๋ฐ์ดํฐ ๊ฐ์ฒด๋ง ๊ฐ์ ธ์ด, get()๋งค๊ฐ๋ณ์์ id=1ํ๋ฉด id๊ฐ 1์ธ ๊ฐ์ฒด, title="๋ด์ฉ" ํ๋ฉด title์์ "๋ด์ฉ"์ธ ๋ฐ์ดํฐ ๊ฐ์ฒด, ์ผ์นํ๋ ๊ฐ์ฒด๊ฐ 2๊ฐ ์ด์ ์์ผ๋ฉด ์๋ฌ๋
Post.objects.filter() : ๊ดํธ์์ ์กฐ๊ฑด๊ณผ ์ผ์นํ๋ ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ด ex) title="hello", ์ธ ๋ชจ๋ ๊ฐ์ฒด ๊ฐ์ ธ์ด
SQlite ์ต์คํ
์
๊น๊ณ SQLite explorer์์ ํด๋ฆญํ์ฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ํด๋ฆญํ ์ ์์
django_extensions ํจํค์ง = ์์์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ๋ณด๋ฅผ ์ํฌํธ ํด์ด
id๋ ์ง์์ ธ๋ ํด๋น ์์ด๋๋ ๋ค์ ์ฐ์ด์ง ์์,
query= list์ ์ฑ์ง๊ณผ ๊ฑฐ์ ๋น์ทํจ
### admin ์์ฑํ๊ธฐ
python manage.py createsuperuser
์ ์ ๋ค์, ์ด๋ฉ์ผ ์ด๋๋ ์ค, ํจ์ค์๋ ์
๋ ฅ, ํจ์ค์๋ ํ์ธ ํ
http://์๋ฒ์ฃผ์/admin
์ด ๊ณณ์์ ๋ค์ด๊ฐ์ ๋ก๊ทธ์ธ ํ๋ฉด ๊ด๋ฆฌ์ ํ์ด์ง๋ก ๊ฐ
from .models import ๋์ ๋ชจ๋ธ
```python
# admin.py์์
admin.site.register(๋์ ๋ชจ๋ธ)
์ดํ ๋ค์ ๊ด๋ฆฌ์ ํ์ด์ง๋ก ๋ค์ด๊ฐ๋ฉด ๋์ ๋ฐ์ดํฐ ๋ฒ ์ด์ค๊ฐ ์ฌ๋ผ๊ฐ ์๊ณ , ๋ด์ฉ ํ์ธ ๊ฐ๋ฅ
from django.shortcuts import redirect
return redirect('/url/')
# ๊ฐ๊ณ ์ถ์ ์๋ฒ๋ด ์นํ์ด์ง๋ก ๋ณด๋
MODEL.objects.order_by(โ์์โ).all() : ํด๋น ์์์ ์ ๋ ฌ ์์ผ๋ก, ๋ฐ๋๋ก ์ํ ๊ฒฝ์ฐ โ-์์โ๋ก ๋ฃ๊ธฐ
QnA ๋ฌ๊ธฐ
foreign key = ๋๊ธ์ด ๊ฐ์ง๊ณ ์๋ ์ธ๋ ์์ด๋, ์ง๋ฌธ์ id๋ฅผ ๊ฐ์ง๊ณ ์์ด์ ํด๋น ์ง๋ฌธ์ ์ํ๊ฒ ๋ง๋ค ์ ์๋ค
answer ๋ชจ๋ธ ์์
```
class Answer(models.Model):
content = models.CharField(max_length=100)
# CASCADE : question์ด ์ฌ๋ผ์ง๋ฉด ๊ทธ ๋ฐ์๋ ๋ชจ๋ ์ง์ฐ๊ฒ ๋ค๋ ์๋ฏธ
question = models.ForeignKey(Question, on_delete=models.CASCADE)
- restfullํ url : ํ์ฌ ๊ฒฝ๋ก์ ์์์ด ํ์๋์ด์๋ url
> main ํ์ด์ง
```html
{% extends 'base.html' %}
{% block body %}
{% for question in questions %}
&#60;h1&#62;{{question.title}}&#60;/h1&#62;
&#60;p&#62;{{question.user}}&#60;/p&#62;
&#60;p&#62;{{question.content}}&#60;/p&#62;
&#60;form action="/questions/{{question.id}}/answers/create/"&#62;
&#60;input type="text" name="content"&#62;
&#60;input type="submit"&#62;
&#60;/form&#62;
{% for answer in question.answer_set.all %} &#60;!--models.ForeignKey๊ฐ ๋ง๋ค์ด์ค answer_set ํจ์, ์ด๋ฅผ ํตํด ์ด question ๋ชจ๋ธ์ foreignkey๋ก ๊ฐ์ง๊ณ ์๋ ๋ชจ๋ answer ๋ชจ๋ธ์ ์ฐพ์์ฌ ์ ์๋ค.--&#62;
&#60;p&#62;{{answer.content}}&#60;/p&#62;
{% endfor %}
&#60;hr&#62;
{% endfor %}
{% endblock %}
ERD ( Entity Relationship Diagram)
vscode = U ์์ง ๊น์ ์์ฌ๋ผ๊ฐ๋ค. M : ๋ฌด์ธ๊ฐ ๋ฐ๋์๋ค. A: add ๋ฌ๋ค.
git add (์ฌ๋ฆดํ์ผ์ด๋ ํด๋)
git status (commitํ ์ํ ๋ณด๊ธฐ)
git restore โstaged (add ์ทจ์ํ ํ์ผ)
Nosql :
if ๋ฌธ์ ์ด์ฉํ restfullํ ์น์ฝ๋ฉ
urls.py
```python
โฆ
path('add/', views.add, name="add" ), # if ๋ถ๊ธฐ๋ก ํ๋์ ๊ฒฝ๋ก๋ก 2๊ฐ์ง ๋ฐฉ์์ ์ผ์ ์ฒ๋ฆฌ(์ค์)
path('<int:id>/update/', views.update, name="update"),
> restfull code ์์ (create์ new path๋ฅผ ํฉ์น add path)
```python
def add(request): # if ๋ถ๊ธฐ๋ก ํ๋์ ๊ฒฝ๋ก๋ก 2๊ฐ์ง ๋ฐฉ์์ ์ผ์ ์ฒ๋ฆฌ, form์ action=''์ด๋ฉด ์๊ธฐ์๋ฆฌ๋ก ๋์๊ฐ๋ ๊ฒ์ ์ด์ฉ(restfullํ ์ฝ๋))(์ค์)
if request.method == "POST": # method๊ฐ post๋ก ๋ณด๋ด์ง๋ฉด create๋ก
author = request.POST.get('author')
title = request.POST.get('title') # url๋ก ๋ณด๋ด๋ ๊ฒ์ ๋ฌด์กฐ๊ฑด get ๋ฐฉ์
content = request.POST.get('content')
due_date = request.POST.get('due-date')
todo = Todo.objects.create(author=author, title=title, content=content, due_date=due_date)
return redirect('todos:index') # /์์ผ๋ฉด ๋ฃจํธ์ฃผ์์ ์ถ๊ฐ, ์์ผ๋ฉด ํ์ฌ ์ฃผ์ ์์ ์ถ๊ฐ
else: # Get๋ฐฉ์์ด๋ฉด ๋ฐ์ดํฐ๋ฅผ form์ผ๋ก ๋ฐ๋ new๋ก
return render(request, 'add.html')
- django๋ ๋ณด๋ด๋ method๋ก delete์ put์ ์ง์ ์ํจ(HTTP5๋ ์ง์ ์ํจ)
- ๋ค๋ฅธ ํ๋ ์์ํฌ์์ ์ผ๋จ post๋ก ๋ณด๋ด๊ณ delete put์ ๋ฃ์ ๋๋ input type= hidden์ name=โ_methodโ, value=โDELETEโ ๋ก ์จ๊ฒจ์ ๋ณด๋ (HTTP5๊ฐ ์ง์ ์ํ๋ฏ๋ก)
- restfullํ ์ฝ๋ฉ์ ํ๋ ค๋ฉด ์ฃผ์์ฐฝ์ ๋์ฌ๋ ๋นผ๊ณ ๋ช ์ฌ๋ก๋ง ์ฐ๋ฉฐ, ๋์ฌ๋ method ๋ฐฉ๋ฒ์ ๋ฐ๊ฟ์ ํด๊ฒฐ
- ๋ค๋ฅธ ํ๋ ์ ์ํฌ๋ http verb๋ผ๋ ๊ฐ๋
๋ ์๋ค.
add.html
```html
{% extends 'base.html' %}
{% block body %}
<form action="" method="POST">
{% csrf_token %}
์์ฑ์ : <input type="text" name="author">
์ ๋ชฉ : <input type="text" name="title">
๋ด์ฉ : <input type="text" name="content">
๋ง๊ฐ์ผ : <input type="date" name="due-date">
<input type="submit" value="์ ์ฅ">
</form>
{% endblock %}
<!โ๋จ์ฝ ๊ธฐ๋ณธ๊ฐ value๋ฅผ ์ ํ๊ณ ์ถ์ผ๋ฉด <input type="date" name="due-date" value="{{todo.due_date|date:'Y-m-d'}}"> ์ด๋ฐ์์ผ๋ก โ>
- post, get ๋ฐฉ์์ ์ด์ฉํด ์ด ํผ(add.html) ํ๋๋ฅผ ์์ ํ ๋ ์ฐ๋ ํผ์ผ๋ก๋ ์ฌ์ฉํ ์ ์๋ค.
## django ์ด๋ฏธ์ง ์
๋ก๋ฉ๊ณผ ์ด๋ฏธ์ง ๋ฆฌ์ฌ์ด์ง
### ์ด๋ฏธ์ง ๋ณด์ฌ์ฃผ๊ธฐ
1. ์ static ๋ถ๋ถ์ favicon ๋ถ๋ถ ์ฐธ์กฐ
#### fontawesome ์ด์ฉํ๊ธฐ
1. ๋จผ์ fontawesome ํํ์ด์ง์๊ฐ์ ๋ก๊ทธ์ธํ๋ค.
2. ํค๋ฅผ ๋ฐ๊ธ๋ฐ๊ณ script๋ฅผ html ํด๋์ header์์ ๋ฃ๋๋ค.
```html
&#60;script src="https://kit.fontawesome.com/e87731a046.js" crossorigin="anonymous"&#62;&#60;/script&#62;
- ์ํ๋ ๊ณณ์ ์ํ๋ ์์ด์ฝ ํ๊ทธ๋ฅผ ์ฝ์
ํ๋ค.
```html
<i class="fas fa-chess-knight">
### ์ด๋ฏธ์ง ์
๋ก๋ฉ
1. ๋จผ์ ์ฑ ๋ด๋ถ์ models.py์์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ชจ๋ธ์ ๋ง๋ ๋ค.
> models.py ํ์ผ
```python
from django.db import models
# Create your models here.
class Feed(models.Model):
content = models.CharField(max_length=150);
created_at = models.DateTimeField(auto_now_add=True) # ์๋์ผ๋ก ํ์ฌ ๋ ์ง ์
๋ ฅ
image = models.ImageField()
-์ด๋ฅผ makemigrationsํ๋ คํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ์ค๋ฅ๊ฐ ๋ฐ ์ ๋ ์๋ค.
```git bash
You are trying to add a non-nullable field โimgโ to todo without a default; we canโt do that (the database
needs something to populate existing rows).
Please select a fix:
1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
2) Quit, and let me add a default in models.py
Select an option:
- ์ด ๋๋ db์์ ํด๋น ๋ชจ๋ธ์ ๋ ๋ฆฌ๊ณ ๋ค์ makemigrationsํ๋ฉด ๋๋ค. ์ฑ ๋ด๋ถ์ migrations ํด๋ ๋ด๋ถ์ (ex)0001_initial.py)
1)
2.
### ์ด๋ฏธ์ง ๋ฆฌ์ฌ์ด์ง
์ธ์คํจ ํ์ํ ํจํค์ง : django-imagekit, Pillow, IPython
## django form์ ์ด์ฉํ ์๋ ํผ ์์ฑ
### django form ์ ์ธ
#### models.py
```python
from django.db import models
# Create your models here.
class Movie(models.Model):
title = models.CharField(max_length=50)
title_en = models.CharField(max_length=50)
audience = models.IntegerField()
open_date = models.DateField()
genre = models.CharField(max_length=50)
watch_grade = models.CharField(max_length=50)
score = models.FloatField()
poster_url = models.TextField()
description = models.TextField()
class Comment(models.Model):
content = models.TextField()
movie = models.ForeignKey(Movie,on_delete=models.CASCADE)
class Meta:
ordering = ('-id',) # ์ ๋ ฌ์ id์ ์ญ์(-)์ผ๋ก ์ถ๋ ฅ , ,๊ผญ ํ์
form.py
from django import forms
from .models import Movie, Comment
class MovieForm(forms.Form): # forms.Form ์์
title = forms.CharField(max_length=50)
title_en = forms.CharField(
max_length=50,
label="์๋ฌธ ์ ๋ชฉ", # ๊ธฐ๋ณธ๊ฐ์์ ์ํ๋ ๋ผ๋ฒจ์ด๋ฆ ๋ฐ๊ฟ์ค
widget=forms.TextInput(
attrs={
'placeholder': '์๋ฌธ์ ๋ชฉ์ ์
๋ ฅํด์ฃผ์ธ์',
}
)
)
audience = forms.IntegerField()
open_date = forms.DateField(widget=forms.DateInput(attrs={'type':'date'}))
genre = forms.CharField(max_length=50)
watch_grade = forms.CharField(max_length=50)
score = forms.FloatField()
poster_url = forms.CharField(widget=forms.Textarea) # textarea๋ก ๋ฐ๊ฟ์ค, django๊ฐ charfield๋ฅผ ๊ธฐ๋ณธ์ผ๋ก ์ก๊ณ ์์ด์ ์ด๊ฑฐ ์จ์ผํจ
description = forms.CharField(widget=forms.Textarea)
# widget: ์ฌ๋ฌ๊ฐ์ง ์ปค์คํฐ๋ง์ด์ง์ ํ๊ฒ ํด์ค attrs, html tag์ ๊ฐ์ ์ถ๊ฐํด์ค
class MovieModelForm(forms.ModelForm): # Model์ ๊ด๊ณ์๋ Form์ผ๋ก ์์, ์๋์ผ๋ก ๋ชจ๋ธ ๋ด๋ถ์ column ๋งํผ ํผ์ ๋ง๋ค์ด์ค
open_date = forms.DateField(widget=forms.DateInput(attrs={'type':'date'})) # ์ด๋ฐ ๋ฐฉ๋ฒ์ผ๋ก ์ผ๋ถ๋ ๋ค๋ฅธ ๋ฐฉ์์ผ๋ก ๋ง๋ค์ด๋ผ ์ ์์ ์ค๋ฒ๋ผ์ด๋ฉ?
class Meta: # ์์ฑ์ผ๋ก ๋ง๋ค๋ฉด column์ผ๋ก ์ธ์งํ๋ฏ๋ก class ๊ฐ์ฒด๋ก ๋ง๋ค์ด์ผ ํจ
model = Movie # ๋ชจ๋ธ ์
๋ ฅ
fields = '__all__' # ์ ๋ถ
class CommentModelForm(forms.ModelForm):
class Meta:
model = Comment
fields = ('content',) # ์ถ๋ ฅํ ๋ถ๋ถ๋ง tuple๋ก ๋ฃ์ด์ฃผ๋ฉด ๋จ, ๋์ ',' ๋ฌด์กฐ๊ฑด ๋ฃ์ด์ผํจ
- ์ด๊ฒ์ ์ด์ฉํ์ฌ form์ ์๋ ์์ฑํ ์ ์๋ค.
- ModelForm์ ์ด์ฉํ๋ฉด form input ์์ ๋ํ ์๋์ผ๋ก ๋ง๋ค์ด ์ค๋ค.
django form ์ด์ฉ
form.html
```html
{% extends 'base.html' %}
{% load bootstrap4 %}
{% block body %}
{% if request.resolver_match.url_name == "create_model_form" %} {% comment %} ํ์ฌ ์ฌ์ดํธ๋ก ์ ๋ณด๋ฅผ ๋ณด๋ธ views.py์์ ์ ์ํ ํจ์ ์ด๋ฆ์ ๊ฐ์ ธ์ด {% endcomment%}
<h1>Create</h1>
{% else %}
<h1>Update</h1>
{% endif %}
<form action="" method="POST">
{% csrf_token %}
{% bootstrap_form form %}
{% buttons submit="์ ์ถ" %}
{% endbuttons %}{% comment %}
# html {{form.as_p}}ํ๋ฉด pํ๊ทธ๋ก ๋ฌถ์ฌ์ ์ถ๋ ฅ๋จ
# as_ul ํ๋ฉด ul ํ๊ทธ๋ก ๋ฌถ์ฌ์ ์ถ๋ ฅ๋จ
# as_table * table ํ๊ทธ์์ ๋ฃ์ผ๋ฉด * ํ ์ด๋ธ ํํ๋ก ์ถ๋ ฅ
# {{form.title.label_tag}} ํ๋ฉด ํด๋น ์์ ์ด๋ฆ์ label์ด ์๊น<table>
{{form.as_table}}
</table>
<input type="submit">
{% endcomment %}</form>
{% endblock %}
#### base.html
```python
{% load bootstrap4 %} {% comment %} ํ์ฌ ํ์ด์ง์์๋ง ๋์ํจ ๋ค๋ฅธ block์ extends ์๋ block์์์ ํ ๊ฒ {% endcomment%}
&#60;!DOCTYPE html&#62;
&#60;html lang="ko"&#62;
&#60;head&#62;
&#60;meta charset="UTF-8"&#62;
&#60;meta name="viewport" content="width=device-width, initial-scale=1.0"&#62;
&#60;meta http-equiv="X-UA-Compatible" content="ie=edge"&#62;
&#60;title&#62;formmovie&#60;/title&#62;
{% bootstrap_css %}
&#60;/head&#62;
&#60;body&#62;
&#60;a href="{% url 'movies:index' %}"&#62;ํ&#60;/a&#62;
&#60;a href="{% url 'movies:create' %}"&#62;๊ธ์ฐ๊ธฐ&#60;/a&#62;
&#60;a href="{% url 'movies:create_model_form' %}"&#62;๊ธ์ฐ๊ธฐ(๋ชจ๋ธํผ)&#60;/a&#62;
&#60;div class="container"&#62;
{% block body %}
{% endblock %}
&#60;/div&#62;
{% bootstrap_javascript jquery='full' %}
&#60;/body&#62;
&#60;/html&#62;
- pip install django-bootstrap4 ์ดํ, settings.py์ INSTALLED_APPS์ โbootstrap4โ,๋ฅผ ์ถ๊ฐํ๊ณ , {% load bootstrap4 %}๋ฅผ ์ถ๊ฐํ์ฌ ์ฌ์ฉํ๋ค.
- ์ด์ธ์๋ {% bootstrap_javascript jquery=โfullโ %}, {% bootstrap_css %}๋ฅผ ๊ฐ๊ฐ body์ header์ ์ถ๊ฐํ์ฌ์ผ ํ๋ค.
- {% comment %} ๋ฅผ ์ด์ฉํ๋ฉด DTL์ด ๋ฌด์ํ๋ ์ฃผ์์ ๋ฌ ์ ์๋ค.{% endcomment%}
detail.html
```python
{% extends 'base.html' %}
{% load bootstrap4 %}
{% block body %}
<br>
{{movie.title}}
{{movie.title_en}}
{{movie.audience}}
{{movie.open_date}}
{{movie.poster_url}}
<form action="{% url 'movies:delete' movie.id %}" method="POST">
{% csrf_token %}
<input type="submit" value="์ญ์ (post)">
</form>
{% comment %}
<a href="{% url 'movies:delete' movie.id %}">์ญ์ ํด๋ผ ์ ์ก์ด</a>
์๊ฒ์ ์ฃผ์ ๋ค๋๋ฐฉ๋ฒ
{% endcomment %}
<a href="{% url 'movies:update' movie.id %}">์์ </a>
<a href="{% url 'movies:update_model_form' movie.id %}">์์ (๋ชจ๋ธํผ)</a>
{% for comment in movie.comment_set.all %}
{{comment.content}}
<a href="{% url 'movies:comment_delete' movie.id comment.id %}">์ญ์ </a>
<br>
{% endfor %}
<form action="{% url 'movies:comment_create' movie.id %}" method="POST">
{% csrf_token %}
{% bootstrap_form comment_form %}
{% comment %}
forms.py์์ field=(content,) ๋ ๊ฐ๋ฅํ์ง๋ง
์ด๋ฐฉ๋ฒ๋ ๋จ
{% bootstrap_form comment_form exclude='movie'%}
{% endcomment %}
{% buttons submit="์ ์ถ" %}
{% endbuttons %}
</form>
{% endblock %}
#### views.py
```python
from django.shortcuts import render, redirect, get_object_or_404
from .forms import MovieForm, MovieModelForm, CommentModelForm
from IPython import embed # ์น ๋๋ฒ๊น
์ฉ
from .models import Movie, Comment
# Create your views here.
def index(request):
movies = Movie.objects.all().order_by('-id') # all() ์๋ต๊ฐ๋ฅ
context = {
'movies': movies
}
return render(request, 'index.html', context)
def create(request):
if request.method == "POST":
form = MovieForm(request.POST)
if form.is_valid(): # ๋ฐฑ์๋์์ ํ๋ฒ ๋ ๊ฒ์ฆ
movie = Movie() # form.cleaned_data : ๊ฒ์ฆ์ด ์๋ฃ, ๊ฐ๊ณต์ด ์๋ฃ๋ ๋ฐ์ดํฐ (์์ ๋น๊ณต๊ฐ์ ์ง์ฐ๋ ๋ฑ์ ํ๋)
movie.title = form.cleaned_data.get('title')
movie.title_en = form.cleaned_data.get('title_en')
movie.audience = form.cleaned_data.get('audience')
movie.open_date = form.cleaned_data.get('open_date')
movie.genre = form.cleaned_data.get('genre')
movie.watch_grade = form.cleaned_data.get('watch_grade')
movie.score = form.cleaned_data.get('score')
movie.poster_url = form.cleaned_data.get('poster_url')
movie.description = form.cleaned_data.get('title_en')
movie.save()
return redirect('movies:index')
else:
form = MovieForm()
context = {
'form' : form
}
return render(request, 'form.html', context)
def detail(request, id):
# movie = Movie.objects.get(id=id)
movie = get_object_or_404(Movie, id=id) # ์๋ชป๋ ์ ๊ทผ์ด๋ฉด 404 ์๋ฌ๋ฅผ ๋จ๊ฒ ํด์ค
comment_form = CommentModelForm()
context = {
'movie': movie,
'comment_form': comment_form,
}
return render(request, 'detail.html', context)
def delete(request, id):
movie = get_object_or_404(Movie, id=id)
if request.method == "POST": # POST ์์ฒญ์ผ ์์๋ง ์ญ์ ๊ฐ ๊ฐ๋ฅํ๋๋ก ๋ง๋ฆ (์ฆ url์ ํตํ ์ ๊ทผ์ด ์๋ ์ ์์ ์ธ ์ ๊ทผ์ผ์)
movie.delete()
return redirect("movies:index")
else:
return redirect("movies:detail", id)
def update(request, id):
movie = get_object_or_404(Movie, id=id)
if request.method == "POST":
form = MovieForm(request.POST)
if form.is_valid():
movie.title = form.cleaned_data.get('title')
movie.title_en = form.cleaned_data.get('title_en')
movie.audience = form.cleaned_data.get('audience')
movie.open_date = form.cleaned_data.get('open_date')
movie.genre = form.cleaned_data.get('genre')
movie.watch_grade = form.cleaned_data.get('watch_grade')
movie.score = form.cleaned_data.get('score')
movie.poster_url = form.cleaned_data.get('poster_url')
movie.description = form.cleaned_data.get('title_en')
movie.save()
return redirect('movies:detail', id)
else:
form = MovieForm(initial=movie.__dict__) # initial๊ณผ ํด๋น ๊ฐ์ฒด์ __dict__๋ฅผ ์ด์ฉํด ๊ธฐ์กด ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฌ ์ ์์
context = {
'form': form,
}
return render(request, 'form.html', context)
def create_model_form(request):
if request.method == "POST":
form = MovieModelForm(request.POST)
if form.is_valid():
movie = form.save() # form.save()๋ movie ๊ฐ์ฒด๋ฅผ ๋ฆฌํดํ๋ค.
return redirect('movies:detail', movie.id)
else:
form = MovieModelForm()
context = {
'form': form
}
return render(request, 'form.html', context)
def update_model_form(request, id):
movie = get_object_or_404(Movie, id=id) # Movie ๋ชจ๋ธ์ id๊ฐ์ด id์ธ ๊ฐ์ฒด๋ฅผ ๊ฐ์ ธ์๋ผ
if request.method == "POST":
form = MovieModelForm(request.POST, instance=movie) # ์ด๋ฐ ๋ฐฉ๋ฒ์ผ๋ก ๊ณผ๊ฑฐ์ ์ ๋ณด์ ์์ ๋ ์ดํ์ ์ ๋ณด๋ ๊ฐ์ ธ์ฌ ์ ์์
if form.is_valid(): # ์ด๋ฅผ ํตํด ๊ทธ ๋๊ฐ์ง ์ ๋ณด๋ฅผ ๊ฒ์ฆํ ์ ์์
form.save()
return redirect('movies:detail', id)
else:
form = MovieModelForm(instance = movie) # modelForm์ ์์ ๋ฐ์ form์ instanace๋ก ํด์ผํจ
context = {
'form': form
}
return render(request, 'form.html', context)
def comment_create(request, movie_id):
movie = get_object_or_404(Movie, id=movie_id)
if request.method == "POST":
form = CommentModelForm(request.POST)
if form.is_valid():
comment = form.save(commit=False) # ๋ฐ๋ก saveํ์ง ์๊ณ ๊ธฐ๋ค๋ฆผ
comment.movie = movie # movie ์ ๋ณด ์ฃผ์
comment.save() # saveํจ
return redirect('movies:detail', movie_id)
else:
return redirect('movies:detail', movie_id)
else:
return redirect('movies:detail', movie_id)
def comment_delete(request, movie_id, comment_id):
comment = Comment.objects.get(id=comment_id)
comment.delete()
return redirect('movies:detail', movie_id)
#
- POST ์ ๊ทผ๊ณผ GET ์ ๊ทผ์ ์ฐจ์ด๋ฅผ ์ด์ฉํ์ฌ validํ ์ ๊ทผ ๊ตฌ๋ณ๊ฐ๋ฅ
- Form์ ์ด์ฉํ์ฌ update๊ตฌํ
_articles/web/backend/Django/Django ๊ธฐ๋ณธ.md