๐ Django๋?
ํ์ด์ฌ์ผ๋ก ๋ง๋ค์ด์ง ๋ฌด๋ฃ ์น ํ๋ ์์ํฌ ( ์น ์ฌ์ดํธ ๋ง๋๋ ํ )
ํ์์ฑ
๋ง์ ๋ถ๋ถ์ด ์ด๋ฏธ ๋ง๋ค์ด์ ธ์์ด์, ์ฝ๊ณ ๋น ๋ฅด๊ฒ ํ๋ก์ ํธ๋ฅผ ๋ง๋ค ์ ์๋ค.
- ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ํ๊ธฐ๋ฅ, ์ด๋๋ฏผ ํจ๋, ์ ์ ์ธ์ฆ ๊ธฐ๋ฅ ๋ฑ๋ฑ
์ปค๋ฎค๋ํฐ์์ ๊ณ์ ํดํน์ด ์ด๋ฃจ์ด์ง๊ณ , ์ด๋ฅผ ๋ง๋ ๋ฒ์ ์ด ์ ๋ฐ์ดํธ ๋๋ฏ๋ก ์์ ํ๋ค.
๋ง์ ๋๊ธฐ์ ๋ค์ด ์ฌ์ฉํ๊ณ ์์ด์, ์ ๋ขฐ๋๊ฐ ๋๋ค.
์๋๋ฐฉ์
1. ์ฌ์ฉ์๊ฐ ์๋ฒ์ ์นํ์ด์ง๋ฅผ ๋ณด๋ด๋ฌ๋ผ๊ณ ์์ฒญ(request)ํ๋ค.
2. ์๋ฒ๊ฐ ๋ฉ์ผ๋ฐ์ค(port)์์ ์์ฒญ์ด ๋์ฐฉํ๋์ง ํ์ธํ๋ค
- ์ฅ๊ณ ์ urlresolver๊ฐ ์์ฒญ์ ๊ฐ์ ธ์ URL๊ณผ ๋ง๋์ง ํ์ธํ๋ค.
- ๋ง์ฝ ์ผ์นํ๋ ๊ฒ์ด ์์ผ๋ฉด, ํด๋น ์์ฒญ์ VIEW์ ๋๊ฒจ์ค๋ค
3. ์์ฒญ์ด ๋์ฐฉํ์ผ๋ฉด, ์นํ์ด์ง๋ฅผ ๋ณด๋ด์ค๋ค.
๐ ์ค์น
pip install django
๋ฒ์ , ์ค์นํ์ธ
django-admin --version
ํ๋ก์ ํธ ๋ง๋ค๊ธฐ
django-admin startproject <ํ๋ก์ ํธ>
Django ํ๋ก์ ํธ ํ์ผ์ ๊ธฐ๋ฅ
manage.py ( ๋ช
๋ น์ฐฝ์ ํตํด, ๊ฐ์ข
์ฅ๊ณ ์ ๋ช
๋ น์ ์คํํ๊ธฐ ์ํ ํ์ผ )
<ํ๋ก์ ํธ> ( ํ๋ก์ ํธ๋ช
์ผ๋ก ์์ฑ๋ ๋๋ ํฐ๋ฆฌ. ํจ๋ถ๋ก ์์ ๊ธ์ง! )
__init__.py ( ํ์ด์ฌ์ด ์ด ํด๋๋ฅผ ํจํค์ง๋ก ์ธ์ํ๊ฒ ๋ง๋ค๊ธฐ )
asgi.py ( ์น์๋ฒ์, django๋ฅผ ์ฐ๊ฒฐํด์ฃผ๋ API, wsgi์ ์์ํธํ )
settings.py ( ํ์ฌ ํ๋ก์ ํธ์ ๊ธฐ๋ณธ์ค์ ์ ๋ฎ์ด์ธ ์ค์ ๋ค. )
urls.py ( ์ฌ์ฉ์๊ฐ ์์ฒญํ๋ URL์ ๋ฐ๋ผ, ์ผ์นํ๋ View๋ฅผ ์ฐพ์ ์ฐ๊ฒฐ )
wsgi.py ( ์ค์๋น์ค์์์ ์น์๋น์ค ์ง์
์ ? )
Database ๋ง๋ค๊ธฐ ( ํ๋ก์ ํธ ํด๋์์ ์คํ )
# ์ด๋ฏธ DB๊ฐ ์กด์ฌํ๋ฉด ์ด๊ธฐํ ๋๋ค
python manage.py migrate
์ํผ์ ์ ๋ง๋ค๊ธฐ
python manage.py createsuperuser
์ํผ์ ์ ํ์ธํ๊ธฐ
# django ๋ช
๋ น์ฐฝ ์ ์
python manage.py shell
from django.contrib.auth.models import User
superuser = User.objects.filter(is_superuser=True)
superuser # <QuerySet [<User: ์ด๋ฆ>]>
์ํผ์ ์ ๋น๋ฐ๋ฒํธ ๋ณ๊ฒฝ
python manage.py changepassword <์ด๋ฆ>
์๋ฒ ๊ตฌ๋ํ๊ธฐ ( 8000ํฌํธ ์ฌ์ฉ )
# ์ค์ ์ฌ์ฉ์์ http ์์ฒญ ์ฒ๋ฆฌ๊ฐ ๋ฆ๋ค. ( uwsgi ์ฌ์ฉํด ํด๊ฒฐ๊ฐ๋ฅ )
python manage.py runserver 0.0.0.0:8000
You may need to add '0.0.0.0' to ALLOWED_HOSTS ์ค๋ฅ ํด๊ฒฐ
# settings.py ํ์ผ์ ๋ค์ ๋ด์ฉ์ ์ถ๊ฐํ๋ค.
# 0.0.0.0 ์ฃผ์๋ฅผ ํ์ฉํ๋ค๋ ์๋ฏธ
ALLOWED_HOSTS = ['0.0.0.0']
์ด๊ธฐ ์ค์ ( settings.py )
LANGUAGE_CODE = 'ko-kr'
TIME_ZONE = 'Asia/Seoul'
# os ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉํ๊ธฐ ์ํด ๊ฐ์ ธ์ค๊ธฐ
import os
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
๋ฐ์ดํฐ ๋ฒ ์ด์ค ์ค์ ( settings.py )
# ์ฐ๊ฒฐ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ ๋ณด๋ฅผ ๋ณด์ฌ์ค๋ค
# ๊ธฐ๋ณธ DB๊ฐ sqlite3๋ก ์ค์ ๋์ด์๋ค
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
# ์ฌ์ฉ๊ฐ๋ฅํ DB / ๋ณ๊ฒฝ์ ์ต์
๋ ์ง์ ํด ์ฃผ์ด์ผํ๋ค
PostgreSQL : django.db.backends.postgresql
MySQL : django.db.backends.mysql
SQLite3 : django.db.backends.sqlite3
ORACLE : django.db.backends.oracle
์ฑ ๋ง๋ค๊ธฐ
python manage.py startapp <์ฑ>
์ฑ์ ์ค์ ํ์ผ ์ ์ฉํ๊ธฐ ( settings.py )
# <์ฑ>์ด ์ค์น๋์ด ์์์, settings.py์๊ฒ ์๋ ค์ค๋ค
INSTALLED_APPS = [
'<์ฑ>'
]
๐ Model ์ด๋?
MCV ๋ชจ๋ธ์์ M(Model)์ ์ญํ ์ ๋ด๋น
DB์ ๋ฐ์ดํฐ๋ฅผ ์์ฑ, ์์ ํ๋ค.
DB์์ ๊ฐ์ ธ์จ ๋ฐ์ดํฐ๋ฅผ View๋ก ์ ๋ฌํ๋ค.
Django App ์์ ๊ธฐ๋ณธ์ ์ผ๋ก ์์ฑ๋๋ models.py ๋ชจ๋์์ ์ ์
models.py ์์, ์ฌ๋ฌ๊ฐ์ ๋ชจ๋ธ ํด๋์ค๋ฅผ ์ ์ํ๋ฉฐ, ํ๋ ํ๋๊ฐ DB์ ํ ์ด๋ธ์ ํด๋นํ๋ค
DB์ ์ ์ฅํ๊ณ ์ถ์ ๊ฒ ์ ๋ฆฌํ๊ธฐ
๊ฒ์๊ธ (Post)
๊ฒ์์ (author)
์ ๋ชฉ (title)
๋ด์ฉ (text)
์์ฑํ๊ธฐ ์์ํ ๋ ์ง (created_date)
๊ฒ์ํ์ ์ฌ๋ฆฐ ๋ ์ง (published_date)
Model ๊ธฐ๋ณธ ์ฌ์ฉ๋ฒ ( models.py )
# ๊ธฐ๋ณธ ์ค์ ํ์ผ ๋ถ๋ฌ์ค๊ธฐ ์ํ ๋ชจ๋
from django.conf import settings
# DB ๋ถ๋ฌ์ค๊ธฐ ์ํ ๋ชจ๋
from django.db import models
# ํ์ฌ ์๊ฐ ๋ถ๋ฌ์ค๊ธฐ ์ํ ๋ชจ๋
from django.utils import timezone
# DB์ ์์ฑํ๊ณ ์ถ์ ํ
์ด๋ธ์ ํด๋์ค ํํ๋ก ์ ์ด์ค๋ค
# models.Model์ด ๋ถ์ด์์ด์ผ๋ง ์ฅ๊ณ ๋ชจ๋ธ๋ก ์ธ์ํ๋ค
# models.<ํ๋ํ์
>(<ํ๋์ต์
>) ํ์์ผ๋ก DB๋ฅผ ์์ฑํ๋ค
class Post(models.Model):
# django์์ ๊ธฐ๋ณธ์ผ๋ก ์ฃผ์ด์ง๋ AUTH_USER_MODEL(์ ์ ํ
์ด๋ธ)๊ณผ ์ฐ๊ฒฐํ๋ค. / ์ถํ ์ค๋ช
์ถ๊ฐ
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
title = models.CharField(max_length=200)
text = models.TextField()
created_date = models.DateTimeField(default=timezone.now())
published_date = models.DateTimeField(blank=True, null=True)
# <Post๊ฐ์ฒด>.publish ์
๋ ฅ์, ํด๋น ๊ฐ์ฒด์ published_date์ ํ์ฌ์๊ฐ์ ๋ฃ์ด์ฃผ๋ ํจ์
def publish(self):
self.published_date = timezone.now()
self.save()
def __str__(self):
return self.title
# Primary Key๋ฅผ ์ง์ ํ์ง ์์๋, Django๊ฐ ์๋์ง์
# ํ๋ ์ ์ ์ํด ํด๋์ค ๋ณ์ ์ฌ์ฉ
( ํ
์ด๋ธ ์ปฌ๋ผ์ ๋ฉํ ๋ฐ์ดํฐ๋ฅผ ์ ์ํ๊ธฐ ๋๋ฌธ์ )
# ๊ตฌ์ฑํ๊ณ ์ํ๋ ํ๋ ํด๋์ค ๊ฐ์ฒด๋ฅผ ๊ฐ์ ธ์จ๋ค. ๊ดํธ()์์ ์ต์
์ง์
# ํ๋๋ง๋ค ๋ฐ๋์ ์ง์ ํด ์ฃผ์ด์ผ ํ๋ ์ต์
์ด ์กด์ฌํ๊ธฐ๋ ํ๋ค. (CharField : max_length)
Model ํ๋ ํด๋์ค ๋ชจ์
CharField :
์ ํ๋ ๋ฌธ์์ด ํ๋
์ต๋ ๊ธธ์ด(max_length) ์ต์
์ ์ง์ ํด์ผ ํ๋ค.
EmailField : ์ด๋ฉ์ผ ์ฃผ์ ์ฒดํฌ
GenericIPAddressField : IP ์ฃผ์ ์ฒดํฌ
FilePathField : ํน์ ํด๋ ๊ฒฝ๋ก ์ฒดํฌ
URLField : URL ์ฒดํฌ
TextField : ๋์ฉ๋ ๋ฌธ์์ด ํ๋
IntegerField :
32 ๋นํธ ์ ์ํ ํ๋
BigIntegerField : ํฐ ์ ์ ํ๋
SmallIntegerFiled : ์์ ์ ์ ํ๋
BooleanField :
true / false ํ๋
NullBooleanField : Null์ ํ์ฉํ true / false ํ๋
DatetimeField :
๋ ์ง, ์๊ฐ ํ๋
DateField : ๋ ์ง ํ๋
TimeField : ์๊ฐ ํ๋
DecimalField : ์์์ ํ๋
BinaryField : ๋ฐ์ด๋๋ฆฌ ๋ฐ์ดํฐ ํ๋
FileField : ํ์ผ ์
๋ก๋ ํ๋
ImageField : ์ด๋ฏธ์ง ํ์ผ ํ๋
UUIDField : GUID(UUID)๋ฅผ ์ ์ฅํ๋ ํ๋
# ํ๋ ๊ฐ ๊ด๊ณ ํ๋
ForeignKey : ์ธ๋ถ ํ
์ด๋ธ์ ์ฐ๊ฒฐํ๋ ํ๋
ManyToManyField : ๋ง์ ํ
์ด๋ธ๊ณผ ๋ง์ ํ
์ด๋ธ ์ฐ๊ฒฐํ๋ ํ๋
OneToOneField : ํ
์ด๋ธ์ ์ผ๋์ผ๋ก ์ฐ๊ฒฐํ๋ ํ๋
ํ๋ ์ต์
# ํ๋์ ์ธ์๋ก ์ฃผ์ด, ์ต์
์ ์ฌ์ฉํ ์ ์๋ค.
null :
null=True ์ด๋ฉด, Empty ๊ฐ์ DB์ NULL๋ก ์ ์ฅํ๋ค.
DB์์ Null์ด ํ์ฉ๋๋ค.
blank :
blank=False ์ด๋ฉด, ํ์์ ์ผ๋ก ์
๋ ฅํด์ผ ํ๋ค.
blank=True ์ด๋ฉด, ์ ํ์ ์ผ๋ก ์
๋ ฅํด๋ ๋๋ค.
primary_key :
primary_key=True ์ด๋ฉด, ํด๋น ํ๋๋ฅผ Primary Key๋ก ์ค์ ํ๋ค
( ๋ฐ๋์ ์กด์ฌํด์ผํ๋ Key )
unique :
unique=True ์ด๋ฉด, ํด๋น ํ๋๋ฅผ Unique Key๋ก ์ค์ ํ๋ค
( ์ค๋ณต๋๋ฉด ์๋๋ Key )
default :
ํ๋์ ๊ธฐ๋ณธ๊ฐ์ ์ง์ ํ๋ค. default="WE"
db_column :
์ปฌ๋ผ๋ช
์ ๊ธฐ๋ณธ๊ฐ์ด ์๋, ๋ค๋ฅธ ๊ฐ์ผ๋ก ์ง์ ํ๋ค. db_column="ME"
verbose_name :
๊ฒ์ผ๋ก ๋ณด์ฌ์ค ํ๋ ์ด๋ฆ์ ์ ํ๋ค. varbose_name="๋ด์ฉ"
validators :
์
๋ ฅ๊ฐ์ ๊ฒ์ฌํ ํจ์ ์ง์ .
ํ๋๋ง๋ค ๊ธฐ๋ณธ์ผ๋ก ์ง์ ๋์ด ์๊ธฐ๋ํจ
( ์ด๋ฉ์ผ๋ง ๋ฐ๊ธฐ, ์ต๋๊ธธ์ด, ์ต์๊ธธ์ด, ์ต๋๊ฐ, ์ต์๊ฐ ๋ฑ๋ฑ )
choices (form widget์ฉ) :
select box ์์ค๋ก ์ฌ์ฉ
help_text(form widget์ฉ) :
ํ๋ ์
๋ ฅ ๋์๋ง
auto_now_add :
auto_now_add=True ์ด๋ฉด, ๋ ์ฝ๋ ์์ฑ์ ํ์ฌ์๊ฐ์ผ๋ก ์๋์ ์ฅ
Model ์์ฑ์ ์ฃผ์ ์ฌํญ
blank(๊ณต๋ฐฑ), null(๋น๊ฐ), default(๊ธฐ๋ณธ๊ฐ) ์ค์ ์
๊ฐ์ด ํ์์ ์ธ์ง, ์๋์ง ์ฒดํฌํ๋๋ฐ ๊ธฐ๋ณธ์์๋ก ์์ฉํ๋ฏ๋ก ๋งค๋ฒ ์ ์ํด์ ์ค์ ํด์ฃผ์ด์ผ ํ๋ค.
Model์ ๊ธฐ๋ฐ์ผ๋ก, DB์ ์ฉํ๊ธฐ ์ํ SQL ํ์์ ์๋ฃ(๋ง์ด๊ทธ๋ ์ด์ ) ๋ง๋ค๊ธฐ
# Django ์ฑ ๋ด๋ถ์, migrations ํด๋ ๋ง๋ค๊ณ , ํ
์ด๋ธ ์์ฑ์ ์ํ ํ์ผ ์์ฑ
python manage.py makemigrations
๋ง์ด๊ทธ๋ ์ด์ ํ์ผ ( 0001_initial.py )
# Generated by Django 3.1.7 on 2021-03-15 00:29
import datetime
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
from django.utils.timezone import utc
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('portfolio', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='Post',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=200)),
('created_date', models.DateTimeField(default=datetime.datetime(2021, 3, 15, 0, 29, 31, 14223, tzinfo=utc))),
('published_date', models.DateTimeField(blank=True, null=True)),
('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
]
๋ง์ด๊ทธ๋ ์ด์ ์ ๊ธฐ๋ฐ์ผ๋ก, ์ค์ DB์ ์ ์ฉํ๊ธฐ
# ํ
์ด๋ธ ์คํค๋ง๋ฅผ ์ด์ฉํด, ์ค์ DB์ ์ ์ฉํ๊ธฐ ์ํ ๋ช
๋ น ์คํ
python manage.py migrate
DB ๊ด๋ฆฌ ์ฐฝ(shell) ๋์ฐ๊ธฐ
python manage.py dbshell
DB ๊ด๋ฆฌ ์ฐฝ(shell) ์ข ๋ฃ
exit()
๊ธฐ์กด์ ์ฌ์ฉํ๋ DB๋ก ๋ชจ๋ธ๋ง๋ค๊ธฐ
DB ์ค์ ํด์ฃผ๊ธฐ ( <ํ๋ก์ ํธ>/settings.py )
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
},
'referencedb1': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': 'test.sqlite3',
},
}
๋ชจ๋ธ ์ ์ฉํ๊ธฐ ( ? )
python manage.py migrate ## default DB ๋ง์ด๊ทธ๋ ์ด์
python manage.py inspectdb ## default DB ๋ชจ๋ธ๋ก ๋ง๋ค๊ธฐ
python manage.py migrate --database referencedb1 ## reference DB ๋ง์ด๊ทธ๋ ์ด์
python manage.py inspectdb --database referencedb1 ## reference DB ๋ชจ๋ธ๋ก ๋ง๋ค๊ธฐ
์ฟผ๋ฆฌ์ ์ด๋?
DB๋ก๋ถํฐ ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ณ , ํํฐ๋ฅผ ๊ฑธ๊ฑฐ๋ ์ ๋ ฌ์ ํ ์ ์๊ฒ ํด์ฃผ๋ ๋ช ๋ น์ด
์ฟผ๋ฆฌ์ ์ฌ์ฉํ๊ธฐ ( django์์ ์ง์ ํ ํ์ผ์์๋ง ์ฌ์ฉ๊ฐ๋ฅ, <์ฑ>/views.py ๋ฑ๋ฑ)
# ๋ชจ๋ธ์์ DB๊ฐ์ ธ์ค๊ธฐ
from <์ฑ>.models import Post
# django ๊ธฐ๋ณธ์ ์ DB ๊ฐ์ ธ์ค๊ธฐ
from django.contrib.auth.models import User
# timezone ๋ถ๋ฌ์ค๊ธฐ
from django.utils import timezone
# DB๋ด์ฉ ์ ๋ถ ์ถ๋ ฅํ๊ธฐ (Read)
print(Post.objects.all())
# <QuerySet [<Post: <ํฌ์คํ
1>>,<Post: <ํฌ์คํ
2>>]>
print(User.objects.all())
# <QuerySet [<User: <์ ์ 1>>,<Post: <์ ์ 2>>]>
# DB์ ๋ด์ฉ ์ถ๊ฐํ๊ธฐ (Create)
# User๊ฐ์ฒด ๊ฐ์ ธ์์ ๋ณ์์ ์ ์ฅํ๊ธฐ
me = User.objects.get(username='<์ ์ 1>')
# ์๋ก์ด Post ์ถ๊ฐํ๊ธฐ
Post.objects.create(author=me, title='<์ ๋ชฉ>', text='<๋ด์ฉ>')
# DB ๋ด์ฉ ํํฐ๋งํด์ ์ถ๋ ฅํ๊ธฐ (Read)
# author=me์ธ Post๋ง ์ถ๋ ฅ
print(Post.objects.filter(author=me))
# title์ <์ ๋ชฉ>ํฌํจ๋๋ Post๋ง ์ถ๋ ฅ
print(Post.objects.filter(title__contains='<์ ๋ชฉ>'))
# ๊ฒ์์ผ(published_date)์ ์์ฑํ Post๋ง ์ถ๋ ฅ
print(Post.objects.filter(published_date__lte=timezone.now()))
# DB ๊ฐ์ฒด ๊ฐ์ ธ์์ ํจ์ ์คํํ๊ธฐ
# title์ <์ ๋ชฉ>ํฌํจ๋๋ Post ๊ฐ์ฒด ๊ฐ์ ธ์ค๊ธฐ
post = Post.objects.get(title='<์ ๋ชฉ>')
# <Post๊ฐ์ฒด>.publish() ํจ์ ์คํ
post.publish()
# created_date ์ปฌ๋ผ์ ๊ธฐ์ค์ผ๋ก ์ ๋ ฌํด์ ๋ณ์์ ์ ์ฅ
# ์ค๋ฆ์ฐจ์
order_up = Post.objects.order_by('created_date')
# ๋ด๋ฆผ์ฐจ์
order_dw = Post.objects.order_by('-created_date')
# ์ฟผ๋ฆฌ์
์ฌ๋ฌ๊ฐ ์ฐ๊ฒฐํด์ ์ฌ์ฉํ๊ธฐ
query = Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
์ฟผ๋ฆฌ์ ์กฐ๊ฑด
ํค์๋ | ์ค๋ช |
__lt / __gt | ๋ณด๋ค ์๋ค / ๋ณด๋ค ํฌ๋ค |
__lte / __gte | ๊ฐ๊ฑฐ๋ ์๋ค / ๊ฐ๊ฑฐ๋ ํฌ๋ค |
__in | ์์ ์๋ ๋ฐ์ดํฐ ๊ฒ์ |
__year / __month / __day | ํด๋น ๋ , ์, ์ผ ๋ฐ์ดํฐ ๊ฒ์ |
__isnull ( <ํ๋๋ช >__isnull = True/False | ๊ฐ์ด null์ธ ๋ฐ์ดํฐ ๊ฒ์ |
__contains / __icontains | ์ง์ ํ ๋ฌธ์์ด์ ํฌํจํ๋ ๋ฐ์ดํฐ ๊ฒ์ ( icontains : ๋์๋ฌธ์ ๊ตฌ๋ณ์ํจ) |
__startswith / __istartswith | ์ง์ ํ ๋ฌธ์์ด๋ก ์์ํ๋ ๋ฐ์ดํฐ ๊ฒ์ ( istartswith : ๋์๋ฌธ์ ๊ตฌ๋ณ์ํจ) |
__endswith / __iendswith | ์ง์ ํ ๋ฌธ์์ด๋ก ๋๋๋ ๋ฐ์ดํฐ ๊ฒ์ ( iendswith : ๋์๋ฌธ์ ๊ตฌ๋ณ์ํจ) |
__range | ๋ฌธ์, ์ซ์, ๋ ์ง์ ๋ฒ์ ์ง์ (์ซ์, ์ซ์) |
๐ Template๋?
MCV ๋ชจ๋ธ์์ V(View)์ ์ญํ ์ ๋ด๋น
View์์ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌ๋ฐ์ ํ๋ฉด์ ํ์ถํ๋ค
'<์ฑ>/templates' ํด๋์์ ๋ด์ฉ์ ๊ฐ์งํ๋ค
Template ๊ธฐ๋ณธ ์ฌ์ฉ๋ฒ ( <์ฑ>/templates/<์ด๋ฆ>.html )
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
{# ์ฃผ์ : {#์ฃผ์#} ํ์์ผ๋ก, ์ฃผ์์ ๋ฃ๋๋ค. #}
{# ํ
ํ๋ฆฟ ๋ณ์ : {{๋ณ์}} ํ์์ผ๋ก, views.py์์ ์ธ์๋ฅผ ๋ฐ์์จ๋ค #}
<h1>THis is index1, {{message}}</h1>
{# ํ
ํ๋ฆฟ ํ๊ทธ : {%๋ช
๋ น%} ํ์์ผ๋ก, python ๋ช
๋ น์ ์คํํ๋ค ( if, for ๋ฑ๋ฑ ) #}
{% if count > 0 %}
Data Conunt = {{ count }}
{% else %}
No Data
{# ํ
ํ๋ฆฟ ํํฐ : {{๋ณ์|ํฌ๋งท}} ํ์์ผ๋ก, ์ค๋๋ ์ง๋ฅผ ๋ฃ๊ฑฐ๋, ๋์๋ฌธ์ ๋ณํ์ ํ๋ ๋ฑ ์ฌ๋ฌ ์์
๊ฐ๋ฅ #}
{{ createDate|date:"Y-m-d" }}
{{ lastNam|lower }}
{# HTML Escape : <, >, ', ", & ๋ฑ๊ณผ ๊ฐ์ ๋ฌธ์๋ค์ด ์์ ๊ฒฝ์ฐ ์ด๋ฅผ HTML์์๋ก ๋ณํํด์ค #}
{% autoescape on %}
{{ content }} {# content ๋ณ์์ <, >, ', "๊ฐ ๋ค์ด์๋ค๊ณ ๊ฐ์ #}
{% endautoescape %}
{{ content|excape }}
{# HTML ์ธ์ฝ๋ฉ ๋ณํ๋๊ตฌ๋ฅผ ์ด์ฉํด, ๋ณ์๋ฅผ ๋ฏธ๋ฆฌ html ์์๋ก ๋ฐ๊พธ์ด ์ ๋ฌํ๋ ๋ฒ๋ ์๋ค #}
</body>
</html>
๐ View๋?
MCV ๋ชจ๋ธ์์ C(Controller)์ ์ญํ ์ ๋ด๋น
Model์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์์, ์ ์ ํ๊ฒ ์ ๋ฆฌํ๋ค.
์ ๋ฆฌํ ๋ฐ์ดํฐ๋ฅผ Template์๊ฒ ์ ๋ฌํ๋ค.
๊ฐ ํจ์๊ฐ ํ๋์ View๋ฅผ ์ ์ํ๋ค.
HTTP ์์ฒญ(Request)์ ์ ๋ ฅ๋ฐ๊ณ , HTTP ์๋ต(Response)๋ฅผ ๋๋ ค์ค๋ค.
URL๋ก ํ๋ฉด ์กฐ์ ํ๊ธฐ ( <ํ๋ก์ ํธ>/urls.py )
# django ๊ธฐ๋ณธํ๋ฉด ๋ถ๋ฌ์ค๋ ๋ชจ๋
from django.contrib import admin
# ๊ฒฝ๋ก ์ค์ ์ ์ํ path ํจ์ ๋ถ๋ฌ์ค๊ธฐ
from django.urls import path
# ๋ง๋ ์ฑ์์ ํ๋ฉด(views.py) ๋ถ๋ฌ์ค๊ธฐ
from <์ฑ> import views
# url๋ค์ ''(๊ณต๋ฐฑ)์ฐพ๊ณ , views.py์์ post_list์คํ
# ex) localhost:8000/ => views.post_list()
urlpatterns = [
path('admin/', admin.site.urls),
path('', views.post_list, name='post_list'),
]
View์์ ์คํํ ํจ์ ๋ง๋ค๊ณ , Template๋ก ์ ๋ณด ์ ๋ฌํ๊ธฐ ( <์ฑ>/views.py )
from django.shortcuts import render
# render(request, <ํ
ํ๋ฆฟ>, <์ ๋ฌ๋ฐ์ดํฐ>) ํ์์ผ๋ก ์ฌ์ฉ
def post_list(request):
# ์ฟผ๋ฆฌ์
์ด์ฉํด Post๋ฅผ ๋ถ๋ฌ์จ๋ค (published_date๊ฐ ํ์ฌ์๊ฐ๋ณด๋ค ์๊ฑฐ๋ ๊ฐ์ Post, ์๊ฐ๊ธฐ์ค ์ค๋ฆ์ฐจ์ ์ ๋ ฌ)
posts = Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
# <์ฑ>/templates/post_list.html ํ์ผ์, 'posts'๋ ์ด๋ฆ์ผ๋ก posts ์ ๋ฌ
return render(request, '<์ฑ>/post_list.html', {'posts':posts})
Template(์ถ๋ ฅํ ์นํ์ด์ง) ๋ง๋ค๊ธฐ ( <์ฑ>/templates/post_list.html )
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
{# for๋ฌธ ์์ #}
{% for post in posts %}
<div class="post">
{# ๊ฒ์์ผ ๊ฐ์ ธ์์ ์ถ๋ ฅ #}
<p>published: {{post.published_date}}</p>
{# ์ ๋ชฉ ๊ฐ์ ธ์์ ๋งํฌ๋ง๋ค๊ธฐ #}
<h1><a href="">{{post.title}}</a></h1>
{# linebreaksbr : ํ๋ฐ๋(Enter)๋ฅผ ๋ฌธ๋จ์ผ๋ก ๋ฐ๊พธ๊ธฐ #}
<p>{{post.text|linebreaksbr}}</p>
</div>
{# for๋ฌธ ์ข
๋ฃ #}
{% endfor %}
</body>
</html>
๐ Template ์ฌํ์ฉ
์ฌํ์ฉํ ์ ์๊ฒ Template ์ค์ ํ๊ธฐ ( <์ฑ>/templates/base.html )
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
{% block content %}
{% endblock %}
</body>
</html>
์ฌ์ฌ์ฉํ๊ธฐ ( <์ฑ>/templates/post_list.html )
{% extends '<์ฑ>/base.html' %}
{% block content %}
{% for post in posts %}
<div class="post">
<p>published: {{post.published_date}}</p>
<h1><a href="">{{post.title}}</a></h1>
<p>{{post.text|linebreaksbr}}</p>
</div>
{% endfor %}
{% endblock %
์ค์ ์ถ๋ ฅ ๊ฒฐ๊ณผ ( <์ฑ>/templates/post_list.html )
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
{% for post in posts %}
<div class="post">
<p>published: {{post.published_date}}</p>
<h1><a href="">{{post.title}}</a></h1>
<p>{{post.text|linebreaksbr}}</p>
</div>
{% endfor %}
</body>
</html>
๐ CSS, JS ํ์ผ ์ ์ฉ
static ํด๋๋ฅผ ๋ง๋ค๊ณ , css/js ํ์ผ ๋ฃ์ด์ค๋ค ( <์ฑ>/static/style.css )
์ง๊ธ๊น์ง django ์ ์ฒด ํด๋ ๊ตฌ์กฐ
<ํ๋ก์ ํธ>
<์ฑ>
templates
base.html
...
static
style.css
...
CSS ์คํ์ผ ์ ์ฉํ๊ธฐ ( <์ฑ>/templates/base.html )
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
# <์ฑ>/templates/style.css ๊ฐ์ ธ์ค๊ธฐ
<link rel="stylesheet" href="{% static 'style.css' %}">
</head>
<body>
{% block content %}
{% endblock %}
</body>
</html>
๐ ๊ฐ๋จํ๊ฒ ์์ ์คํ์ผ ์ ์ฉํ๊ธฐ, ์์ด์ฝ ์ฌ์ฉํ๊ธฐ
bootstrap์ ์ฌ์ฉํด์ค๋ค. ( <์ฑ>/templates/base.html )
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="{% static 'style.css' %}">
{# bootstrap ์คํ์ผ, ์์ด์ฝ ๊ฐ์ ธ์ค๊ธฐ #}
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css">
</head>
<body>
{# ํ์ด์ง ์๋จ์ ํํธ ์์ด์ฝ ๋ฃ๊ธฐ #}
<span class='glyphicon glyhicon-heart'></span>
{% block content %}
{% endblock %}
</body>
</html>
* ์ฌ์ฉ๊ฐ๋ฅํ ์์ด์ฝ ๋ณด๊ธฐ / bootstrapk.com/components/
๐ URL์ ๋ฐ๋ผ, ๊ฒ์๊ธ ์์ธํ์ด์ง ๋ณด์ฌ์ฃผ๊ธฐ
URL์์ ์ธ์ ๋ฐ์์ Views๋ก ์ ๋ฌํ๊ธฐ ( <ํ๋ก์ ํธ>/urls.py )
from django.urls import path
from . import views
urlpatterns = [
path('admin/', admin.site.urls),
path('', views.post_list, name='post_list'),
# "localhost/post/<์ซ์>/" ํํ์ ์ฃผ์๋ฅผ ์ธ์ํ๋ค.
# ์ฃผ์์์ pk๊ฐ๋ฐ์์, "views.post_detail" ์ผ๋ก ์ ๋ฌ (post_detail ํจ์ ๋ง๋ค๊ธฐ)
path('post/<int:pk>/', views.post_detail, name='post_detail'),
]
Views์ URL์ธ์ ๋ฐ์์์ Template๋ก ์ ๋ฌํ๊ธฐ ( <์ฑ>/views.py )
from django.shortcuts import render, get_object_or_404
from django.utils import timezone
from django.contrib.auth.models import User
from .models import Post
def post_list(request):
posts = Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
return render(request, '<์ฑ>/post_list.html', {'posts':posts})
# ์ฃผ์์์ ๋ฐ์์จ pk์ธ์์ ๋ง๋ ๊ฒ์๊ธ ๋ถ๋ฌ์ค๊ธฐ
def post_detail(request, pk):
# get_object_or_404 : Primary Key๊ฐ pk์ธ ๊ฒ์๊ธ ์กด์ฌ ์ฌ๋ถ ํ์ธ, ์กด์ฌํ๋ฉด ๊ฒ์๊ธ ์ถ๋ ฅ, ์กด์ฌํ์ง ์์ผ๋ฉด ํน๋ณํ์ด์ง(404) ์ถ๋ ฅ
post = get_object_or_404(Post, pk=pk)
# ํ
ํ๋ฆฟ(post_detail.html ๋ง๋ค๊ธฐ)์ผ๋ก post ๋ณ์์ ๋ฌ
return render(request, '<์ฑ>/post_detail.html', {'post':post})
Template์์ View์์ ๋ณด๋ธ ๋ฐ์ดํฐ ์ฌ์ฉํด, ์์ธํ์ด์ง ๋ง๋ค๊ธฐ ( <์ฑ>/templates/post_detail.html )
{% extends '<์ฑ>/base.html' %}
{% block content %}
<div class="post">
{% if post.published_date %}
<div class="date">
{{post.published_date}}
</div>
{% endif %}
<h1>{{post.title}}</h1>
<p>{{post.text|linebreaksbr}}</p>
</div>
{% endblock %}
๊ฒ์๊ธ ์ ๋ชฉ ๋๋ฅด๋ฉด, ์์ธํ์ด์ง๋ก ์ด๋ํ๋๋ก ๋ง๋ค๊ธฐ ( <์ฑ>/templates/post_list.html )
{% extends '<์ฑ>/base.html' %}
{% block content %}
{% for post in posts %}
<div class="post">
<p>published: {{post.published_date}}</p>
{# ํด๋ฆญ์ post_detail.html ํ์ผ๋ก post.pk๊ฐ ๋ณด๋ด๊ธฐ #}
<h1><a href="{% url 'post_detail' pk=post.pk %}">{{post.title}}</a></h1>
<p>{{post.text|linebreaksbr}}</p>
</div>
{% endfor %}
{% endblock %}
๐ ๊ฒ์๊ธ ์์ฑ, ์์ ํ์ด์ง ๋ง๋ค๊ธฐ
View์ DB ์ฐ๊ฒฐํ๋ ํผ ๋ง๋ค๊ธฐ ( <์ฑ>/forms.py )
# ํผ์ ๋ถ๋ฌ์ค๊ธฐ
from django import forms
# Post ๋ชจ๋ธ ๋ถ๋ฌ์ค๊ธฐ
from .models import Post
# PostForm ํผ ๋ง๋ค๊ธฐ
# forms.ModelForm์ด ์์ด์ผ ์ฅ๊ณ ๊ฐ ํผ์ผ๋ก ์ธ์ํ๋ค.
class PostForm(forms.ModelForm):
# ํผ์ ๋ง๋ค๋ ์ฐ์ด๋ ๋ชจ๋ธ ์ง์
class Meta:
# Post ๋ชจ๋ธ๊ณผ ์ฐ๊ฒฐํ๊ธฐ
model = Post
# ํผ์ Post.title, Post.text ๋ถ๋ฌ์ค๊ธฐ
fields = ('title', 'text',)
# ํ๋ฉด์ ๋ณด์ฌ์ค ํ๋์ด๋ฆ ์ง์ ํ๊ธฐ
labels = {
'title':'์ ๋ชฉ',
'text':'๋ด์ฉ'
}
URL์ ๋ฐ๋ฅธ View ์ค์ ํด์ฃผ๊ธฐ ( <ํ๋ก์ ํธ>/urls.py )
from django.urls import path
from . import views
urlpatterns = [
path('admin/', admin.site.urls),
path('', views.post_list, name='post_list'),
path('post/<int:pk>/', views.post_detail, name='post_detail'),
# ๊ฒ์๊ธ์ ์์ฑํ view(post_new)๋ฅผ ๋ง๋ค์ด ์ฐ๊ฒฐํ๋ค.
path('post/new/', views.post_new, name='post_new'),
# ๊ฒ์๊ธ์ ์์ ํ view(post_edit)๋ฅผ ๋ง๋ค์ด ์ฐ๊ฒฐํ๋ค.
path('post/<int:pk>/edit/', views.post_view, name='post_edit'),
]
Views์ URL์ธ์ ๋ฐ์์์ Template๋ก ์ ๋ฌํ๊ธฐ ( <์ฑ>/views.py )
# ํ์ด์ง๋ฅผ ์ด๋์์ผ์ฃผ๋ ๋ชจ๋
from django.shortcuts import render, get_object_or_404, redirect
from django.utils import timezone
from django.contrib.auth.models import User
from .models import Post
# PostForm ๊ฐ์ ธ์ค๊ธฐ
from .forms import PostForm
def post_list(request):
posts = Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
return render(request, '<์ฑ>/post_list.html', {'posts':posts})
def post_detail(request, pk):
post = get_object_or_404(Post, pk=pk)
return render(request, '<์ฑ>/post_detail.html', {'post':post})
# post_new ํจ์ ๋ง๋ค๊ธฐ
def post_new(request):
# POST ์์ฒญ์ด ์๋ค๋ฉด, ๊ฐ์ ธ์ค๊ธฐ
if request.method == "POST":
# POST ์์ฒญ์ด ์ ํจํ์ง ํ์ธํ๊ธฐ
if form.is_valid():
# post์ ๊ฐ์ ธ์จ form(์ ๋ชฉ,ํ
์คํธ) ์ ์ฅํ๊ธฐ (์์ง DB๋ฐ์ ์ํจ)
post = form.save(commit=False)
# post์ ์์ฑ์ ์ถ๊ฐํ๊ธฐ
post.author = request.user
# post์ ๊ฒ์์ผ ์ถ๊ฐํ๊ธฐ
post.published_date = timezone.now()
# post DB์ ์ ์ฉํ๊ธฐ
post.save()
# ๋ฐฉ๊ธ ์์ฑํ Primary Key์ ์ผ์นํ๋ ๊ฒ์๊ธ์ ์์ธํ์ด์ง๋ก ์ด๋ํ๋ค.
return redirect('post_detail', pk=post.pk)
# POST ์์ฒญ์ด ์๋ค๋ฉด
else:
# ๋น์ด์๋ ํผ์ ์ ๋ฌํด์ค๋ค. (์์ผ๋ฉด ์๋ฌ)
form = PostForm()
# ๊ฒ์๊ธ์ ์์ฑํ๋ ํ์ด์ง(post_edit.html)์ ํผ์ ์ ๋ฌํ๊ณ ์ด๋ํ๋ค
return render(request, '<์ฑ>/post_edit.html', {'form':form})
# post_edit ํจ์ ๋ง๋ค๊ธฐ
def post_edit(request, pk):
# ๊ธฐ์กด์ ๊ฒ์๊ธ ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ
post = get_object_or_404(Post, pk=pk)
if request.method == "POST":
# ์์ ๋ ๊ฒ์๊ธ ์ ๋ณด ํผ์ ๋ฃ์ด์ ๋ฐ์์ค๊ธฐ ๊ธฐ์กด(instance) + ์์ (request)
form = PostForm(request.POST, instance=post)
if form.is_valid():
post = form.save(commit=False)
post.author = request.user
post.published_date = timezone.now()
post.save()
return redirect('post_detail', pk=post.pk)
else:
# ๊ธฐ์กด์ ๊ฒ์๊ธ ์ ๋ณด ํผ์ ๋ฃ์ด์ ๋ฐ์์ค๊ธฐ
form = PostForm(instance=post)
return render(request, '<์ฑ>/post_edit.html', {'form':form})
๊ฒ์๊ธ ์์ฑํ์ด์ง ๋ง๋ค๊ธฐ ( <์ฑ>/templates/post_edit.html )
{% extends '<์ฑ>/base.html' %}
{% block content %}
<h1>New Post</h1>
<form method="post" class="post-form">
# ๋ณด์์ ์ํ ์์
{% csrf_token %}
# ํผ์์ ๋ชจ๋ ์ ๋ณด ๊ฐ์ ธ์ ์ถ๋ ฅ
{{form.as_p}}
<button type="submit" class="save btn btn-default">Save</button>
</form>
{% endblock %}
์์ธํ์ด์ง์ ์์ ๋ฒํผ ๋ง๋ค๊ธฐ ( <์ฑ>/templates/post_detail.html )
{% extends '<์ฑ>/base.html' %}
{% block content %}
<div class="post">
{% if post.published_date %}
<div class="date">
{{post.published_date}}
</div>
{% endif %}
{# ์์ ๋ฒํผ, post_edit/post/<pk> ์ผ๋ก ์ด๋ #}
<a href="{% url 'post_edit' pk=post.pk %}" class="btn btn-default"><span class='glyphicon glyphicon-pencil'>์์ </span></a>
<h1>{{post.title}}</h1>
<p>{{post.text|linebreaksbr}}</p>
</div>
{% endblock %}
๐ ๊ฐ์ ์๋ง ๊ฒ์๊ธ ์์ฑํ๋๋ก ๊ถํ์ค์
๊ฐ์ ์๋ง ๊ฒ์๊ธ ์์ฑ ( <์ฑ>/templates/base.html )
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BmbxuPwQa2lc/FVzBcNJ7UAyJxM6wuqIj61tLrc4wSX0szH/Ev+nYRRuWlolflfl" crossorigin="anonymous">
<link rel="stylesheet" href="{% static 'css/style.css' %}">
<link rel="preconnect" href="https://fonts.gstatic.com">
</head>
<body>
<body>
<div class="page-header">
# ์ ์ ๊ฐ ๊ถํ์ด ์์ผ๋ฉด, ์๊ธ ๋ฒํผ ๋ณด์ด๊ธฐ
{% if user.is_authenticated %}
<a href="{% url 'post_new' %}" class="top-menu"><span class="glyphicon glyphicon-plus">์๊ธ</span></a>
{% endif %}
<h1><a href="/">Django Girls Blog</a></h1>
</div>
<div class="content container">
<div class="row">
<div class="col-md-8">
{% block content %}
{% endblock %}
</div>
</div>
</div>
</body>
</body>
</html>
๊ฒ์๊ธ ์์ ๊ถํ ์ค์ ํ๊ธฐ ( <์ฑ>/templates/post_detail.html )
{% extends 'portfolio/index.html' %}
{% block content %}
<div class="post">
{% if post.published_date %}
<div class="date">
{{post.published_date}}
</div>
{% endif %}
# ์ ์ ๊ฐ ๊ถํ์ด ์์ผ๋ฉด, ์์ ๋ฒํผ ๋ณด์ด๊ธฐ
{% if user.is_authenticated %}
<a href="{% url 'post_edit' pk=post.pk %}" class="btn btn-default"><span class='glyphicon glyphicon-pencil'>์์ </span></a>
{% endif %}
<h1>{{post.title}}</h1>
<p>{{post.text|linebreaksbr}}</p>
</div>
{% endblock %}
๐ ์์์ ์ฅํ ๊ธ (draft) ๊ด๋ฆฌํ๊ธฐ
draft ๊ด๋ฆฌํ์ด์ง๋ก ์ด๋ํ url ๋ง๋ค๊ธฐ ( <์ฑ>/urls.py )
from django.urls import path
from . import views
urlpatterns = [
path('', views.post_list, name='post_list'),
path('post/<int:pk>/', views.post_detail, name='post_detail'),
path('post/new/', views.post_new, name='post_new'),
path('post/<int:pk>/edit/', views.post_edit, name='post_edit'),
# drafts/ ํ์์ url์ด ๊ฐ์ง๋๋ฉด, views.post_draft_list ์คํ
path('drafts/', views.post_draft_list, name='post_draft_list'),
]
์์์ ์ฅ ๊ฒ์๊ธ ๋ถ๋ฌ์, Template์ ์ ๋ฌ ( <์ฑ>/views.py )
from django.shortcuts import render, get_object_or_404, redirect
from django.utils import timezone
from django.contrib.auth.models import User
from .models import Post
from .forms import PostForm
# ์ค๊ฐ ์๋ต
def post_draft_list(request):
# ๊ฒ์์ผ์๊ฐ ์
๋ ฅ๋์ง ์์ ๊ฒ์๊ธ ์ ๋ณด ๋ถ๋ฌ์ค๊ธฐ
posts = Post.objects.filter(published_date__isnull=True).order_by('created_date')
# ์์์ ์ฅ ํ์ด์ง๋ก ์ด๋, ์ ๋ณด ์ ๋ฌ
return render(request, '<์ฑ>/post_draft_list.html', {'posts':posts})
์์๊ฒ์ํ ํ์ด์ง ๋ง๋ค๊ธฐ ( <์ฑ>/templates/post_draft_list.html )
{% extends 'portfolio/index.html' %}
{% block content %}
{% for post in posts %}
<div class="post">
# ๊ฒ์๊ธ ์์ฑ์ผ์ ์ผ-๋ฌ-์ฐ ํ์์ผ๋ก ํ์ํ๊ธฐ
<p class="date">created: {{post.created_date|date:'d-m-Y'}}</p>
<h1><a href="{% url 'post_detail' pk=post.pk %}">{{post.title}}</a></h1>
# 200 ๊ธ์๊ฐ ๋์ผ๋ฉด ์๋ฅด๊ธฐ
<p>{{post.text|truncatechars:200}}</p>
</div>
{% endfor %}
{% endblock %}
์์๊ฒ์ํ ์ด๋ ๋ฒํผ ์ถ๊ฐํ๊ธฐ ( <์ฑ>/templates/base.html )
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BmbxuPwQa2lc/FVzBcNJ7UAyJxM6wuqIj61tLrc4wSX0szH/Ev+nYRRuWlolflfl" crossorigin="anonymous">
<link rel="stylesheet" href="{% static 'css/style.css' %}">
<link rel="preconnect" href="https://fonts.gstatic.com">
</head>
<body>
<body>
<div class="page-header">
{% if user.is_authenticated %}
<a href="{% url 'post_new' %}" class="top-menu"><span class="glyphicon glyphicon-plus">์๊ธ</span></a>
{# ์ ์ ๊ฐ ๊ถํ์ด ์์ผ๋ฉด, ์์๊ฒ์ํ ๋ฒํผ ๋ณด์ด๊ธฐ #}
<a href="{% url 'post_draft_list' %}" class="top-menu"><span class="glyphicon glyphicon-edit"></span></a>
{% else %}
<a href="{% url 'login' %}" class="top-menu"><span class="glyphicon glyphicon-lock"></span></a>
{% endif %}
<h1><a href="/">Django Girls Blog</a></h1>
</div>
<div class="content container">
<div class="row">
<div class="col-md-8">
{% block content %}
{% endblock %}
</div>
</div>
</div>
</body>
</body>
</html>
๐ ์์์ ์ฅํ ๊ธ ๊ฒ์ํ๊ธฐ (publish)
url๋ก ๊ฒ์ํ ๊ธ(์์์ ์ฅ) ์ ๋ณด์ ๋ฌํ๊ธฐ ( <์ฑ>/urls.py )
from django.urls import path
from . import views
urlpatterns = [
path('', views.post_list, name='post_list'),
path('post/<int:pk>/', views.post_detail, name='post_detail'),
path('post/new/', views.post_new, name='post_new'),
path('post/<int:pk>/edit/', views.post_edit, name='post_edit'),
path('drafts/', views.post_draft_list, name='post_draft_list'),
# post/<์ซ์>/publish/ ํ์์ url์ด ๊ฐ์ง๋๋ฉด, views.post_publish ์คํ
path('post/<int:pk>/publish/', views.post_publish, name='post_publish'),
]
์์์ ์ฅ๊ธ ๊ฒ์ํ๊ธฐ ( <์ฑ>/views.py )
from django.shortcuts import render, get_object_or_404, redirect
from django.utils import timezone
from django.contrib.auth.models import User
from .models import Post
from .forms import PostForm
# ์ค๊ฐ ์๋ต
def post_publish(request, pk):
# Primary Key ์ด์ฉํด์, ๊ฒ์ํ ๊ธ ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ
post = get_object_or_404(Post, pk=pk)
# Post ๋ชจ๋ธ ๋ด๋ถ์ ์๋ publish() ํจ์ ์ฌ์ฉํด์, ๊ฒ์ํ๊ธฐ
post.publish()
# ํด๋น ๊ฒ์๊ธ๋ก ์ด๋
return redirect('post_detail', pk=pk)
๊ฒ์ํ๊ธฐ ๋ฒํผ ๋ง๋ค๊ธฐ ( <์ฑ>/templates/post_detail.html )
{% extends '<์ฑ>/base.html' %}
{% block content %}
<div class="post">
{% if post.published_date %}
<div class="date">
{{post.published_date}}
</div>
{# ์์์ ์ฅํ ๊ธ ์ผ๋, '๊ฒ์'๋ฒํผ ์ถ๋ ฅํ๊ณ post_publish์ pk๊ฐ ์ ๋ฌ #}
{% else %}
<a href="{% url 'post_publish' pk=post.pk %}" class="btn btn-default"><span class='glyphicon glyphicon-pencil'>๊ฒ์</span></a>
{% endif %}
{% if user.is_authenticated %}
<a href="{% url 'post_edit' pk=post.pk %}" class="btn btn-default"><span class='glyphicon glyphicon-pencil'>์์ </span></a>
{% endif %}
<h1>{{post.title}}</h1>
<p>{{post.text|linebreaksbr}}</p>
</div>
{% endblock %}
๐ ๊ฒ์๊ธ ์ญ์ ํ๊ธฐ (delete)
url๋ก ์ญ์ ํ ๊ธ ์ ๋ณด์ ๋ฌํ๊ธฐ ( <์ฑ>/urls.py )
from django.urls import path
from . import views
urlpatterns = [
path('', views.post_list, name='post_list'),
path('post/<int:pk>/', views.post_detail, name='post_detail'),
path('post/new/', views.post_new, name='post_new'),
path('post/<int:pk>/edit/', views.post_edit, name='post_edit'),
path('drafts/', views.post_draft_list, name='post_draft_list'),
path('post/<int:pk>/edit/', views.post_publish, name='post_publish'),
# post/<์ซ์>/remove/ ํ์์ url์ด ๊ฐ์ง๋๋ฉด, views.post_remove ์คํ
path('post/<int:pk>/remove/', views.post_remove, name='post_remove'),
]
์์์ ์ฅ๊ธ ๊ฒ์ํ๊ธฐ ( <์ฑ>/views.py )
from django.shortcuts import render, get_object_or_404, redirect
from django.utils import timezone
from django.contrib.auth.models import User
from .models import Post
from .forms import PostForm
# ์ค๊ฐ ์๋ต
def post_publish(request, pk):
# Primary Key ์ด์ฉํด์, ๊ฒ์ํ ๊ธ ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ
post = get_object_or_404(Post, pk=pk)
# Post ๋ชจ๋ธ ๋ด๋ถ์ ์๋ publish() ํจ์ ์ฌ์ฉํด์, ๊ฒ์ํ๊ธฐ
post.publish()
# ํด๋น ๊ฒ์๊ธ๋ก ์ด๋
return redirect('post_detail', pk=pk)
๊ฒ์ํ๊ธฐ ๋ฒํผ ๋ง๋ค๊ธฐ ( <์ฑ>/templates/post_detail.html )
{% extends '<์ฑ>/base.html' %}
{% block content %}
<div class="post">
{% if post.published_date %}
<div class="date">
{{post.published_date}}
</div>
{# ์์์ ์ฅํ ๊ธ ์ผ๋, '๊ฒ์'๋ฒํผ ์ถ๋ ฅํ๊ณ name='post_publish'์ pk๊ฐ ์ ๋ฌ #}
{% else %}
<a href="{% url 'post_publish' pk=post.pk %}" class="btn btn-default"><span class='glyphicon glyphicon-pencil'>๊ฒ์</span></a>
{% endif %}
{% if user.is_authenticated %}
<a href="{% url 'post_edit' pk=post.pk %}" class="btn btn-default"><span class='glyphicon glyphicon-pencil'>์์ </span></a>
{% endif %}
<h1>{{post.title}}</h1>
<p>{{post.text|linebreaksbr}}</p>
</div>
{% endblock %}
๐ ๋ก๊ทธ์ธ ํ๋ฉด ๋ง๋ค๊ธฐ
๋ก๊ทธ์ธ ํ๋ฉด ๋ณด์ฌ์ค url ๋ง๋ค๊ธฐ ( <์ฑ>/urls.py )
# ๋ก๊ทธ์ธ ํ๋ฉด์ ๋ง๋ค django ๊ธฐ๋ณธ ๋ชจ๋ ๋ถ๋ฌ์ค๊ธฐ
from django.contrib.auth import views as auth_views
from django.urls import path
from . import views
urlpatterns = [
path('', views.post_list, name='post_list'),
path('post/<int:pk>/', views.post_detail, name='post_detail'),
path('post/new/', views.post_new, name='post_new'),
path('post/<int:pk>/edit/', views.post_edit, name='post_edit'),
path('drafts/', views.post_draft_list, name='post_draft_list'),
path('post/<int:pk>/edit/', views.post_publish, name='post_publish'),
path('post/<int:pk>/remove/', views.post_remove, name='post_remove'),
# accounts/login/ ํ์์ url์ด ๊ฐ์ง๋๋ฉด, auth_views.LoginView.as_view() ์คํ
path('accounts/login/', auth_views.LoginView.as_view(), name='login'),
]
๋ก๊ทธ์ธ ํ๋ฉด ๋ง๋ค๊ธฐ ( <์ฑ>/templates/registration/login.html )
{% extends '<์ฑ>/base.html' %}
{% block content %}
{# ์๋ฌ ๋ฐ์์ ๋ฉ์์ง ์ถ๋ ฅ #}
{% if form.errors %}
<p>์ด๋ฆ๊ณผ ๋น๋ฐ๋ฒํธ๊ฐ ์ผ์นํ์ง ์์ต๋๋ค. ๋ค์ ์๋ํด์ฃผ์ธ์.</p>
{# ์๋ฌ ๋ฐ์ ์ํ๋ฉด, ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๋ฐ์, name='login'์ธ ๊ณณ์ผ๋ก ์ ๋ฌํ๋ค. #}
{% endif %}
<form method="post" action="{% url 'login' %}">
{% csrf_token %}
<table>
<tr>
<td>{{form.username.lagel_tag}}</td>
<td>{{form.username}}</td>
</tr>
<tr>
<td>{{form.password.lagel_tag}}</td>
<td>{{form.password}}</td>
</tr>
</table>
<input type="submit" value="login">
<input type="hidden" name="next" value="{{next}}">
</form>
{% endblock %}
๋ก๊ทธ์ธ ์ฑ๊ณต์ ์ด๋ํ ํ๋ฉด ์ค์ ํ๊ธฐ ( <ํ๋ก์ ํธ>/settings.py )
LOGIN_REDIRECT_URL = '/'
๋ก๊ทธ์ธ ๋ฒํผ ์ถ๊ฐํ๊ธฐ ( <์ฑ>/templates/base.html )
# ํค๋ ์๋ต
<body>
<body>
<div class="page-header">
{# ์ ์ ๊ฐ ๋ก๊ทธ์ธํ์ผ๋ฉด, ์์ฑ/์์ ๋ฒํผ ๋ณด์ด๊ธฐ #}
{% if user.is_authenticated %}
<a href="{% url 'post_new' %}" class="top-menu"><span class="glyphicon glyphicon-plus">์๊ธ</span></a>
<a href="{% url 'post_draft_list' %}" class="top-menu"><span class="glyphicon glyphicon-edit"></span></a>
{# ์ ์ ์๊ฒ ์ธ์ฌ๋ฉ์์ง #}
<p class="top-menu">Hello {{user.username}} </p>
{# ์ ์ ๊ฐ ๊ถํ์ด ์์ผ๋ฉด, ๋ก๊ทธ์ธ ๋ฒํผ ๋ณด์ด๊ธฐ #}
{% else %}
<a href="{% url 'login' %}" class="top-menu"><span class="glyphicon glyphicon-lock"></span></a>
{% endif %}
<h1><a href="/">Django Girls Blog</a></h1>
</div>
<div class="content container">
<div class="row">
<div class="col-md-8">
{% block content %}
{% endblock %}
</div>
</div>
</div>
</body>
</body>
๐ ๋ก๊ทธ์์ ํ๋ฉด ๋ง๋ค๊ธฐ
๋ก๊ทธ์์ ํ๋ฉด ๋ณด์ฌ์ค url ๋ง๋ค๊ธฐ ( <์ฑ>/urls.py )
from django.contrib.auth import views as auth_views
from django.urls import path
from . import views
urlpatterns = [
path('', views.post_list, name='post_list'),
path('post/<int:pk>/', views.post_detail, name='post_detail'),
path('post/new/', views.post_new, name='post_new'),
path('post/<int:pk>/edit/', views.post_edit, name='post_edit'),
path('drafts/', views.post_draft_list, name='post_draft_list'),
path('post/<int:pk>/edit/', views.post_publish, name='post_publish'),
path('post/<int:pk>/remove/', views.post_remove, name='post_remove'),
path('accounts/login/', auth_views.LoginView.as_view(), name='login'),
# accounts/logout/ ํ์์ url์ด ๊ฐ์ง๋๋ฉด, auth_views.LoginView.as_view() ์คํํ๊ณ , '/' ๊ฒฝ๋ก๋ก ์ด๋
path('accounts/logout/', auth_views.LogoutnView.as_view(next_page='/'), name='logout'),
]
๋ก๊ทธ์์ ๋ฒํผ ์ถ๊ฐํ๊ธฐ ( <์ฑ>/templates/base.html )
# ํค๋ ์๋ต
<body>
<body>
<div class="page-header">
{% if user.is_authenticated %}
<a href="{% url 'post_new' %}" class="top-menu"><span class="glyphicon glyphicon-plus">์๊ธ</span></a>
<a href="{% url 'post_draft_list' %}" class="top-menu"><span class="glyphicon glyphicon-edit"></span></a>
{# logout ํ๋ฉด์ผ๋ก ์ด๋ #}
<p class="top-menu">Hello {{user.username}} <small><a href="{% url 'logout' %}>Log out</a></small></p>
{% else %}
<a href="{% url 'login' %}" class="top-menu"><span class="glyphicon glyphicon-lock"></span></a>
{% endif %}
<h1><a href="/">Django Girls Blog</a></h1>
</div>
<div class="content container">
<div class="row">
<div class="col-md-8">
{% block content %}
{% endblock %}
</div>
</div>
</div>
</body>
</body>
๐ ๋๊ธ ๊ธฐ๋ฅ ๋ง๋ค๊ธฐ
๋๊ธ ์ ์ฅํ DB ๋ง๋ค๊ธฐ ( <์ฑ>/models.py )
class Comment(models.Model):
# Post์ ์ฐ๊ฒฐ
post = models.ForeignKey('<์ฑ>.Post', on_delete=models.CASCADE, related_name='comments')
author = models.CharField(max_length=200)
text = models.TextField()
created_date = models.DateTimeField(default=timezone.now)
#
approved_comment = models.BooleanField(default=False)
#
def approve(self):
self.approved_comment = True
self.save()
# ์ฝ๋ฉํธ ๋ด์ฉ ๋๋ ค์ฃผ๊ธฐ
def __str__(self):
return self.text
๋ง์ด๊ทธ๋ ์ด์ ํ์ผ ๋ง๋ค๊ณ , DB์ ์ ์ฉํ๊ธฐ
python manage.py makemigrations <์ฑ>
python manage.py migrate
๋๊ธ ์์ฑ ํ๋ฉด ๋ณด์ฌ์ค url ๋ง๋ค๊ธฐ ( <์ฑ>/urls.py )
from django.contrib.auth import views as auth_views
from django.urls import path
from . import views
urlpatterns = [
path('', views.post_list, name='post_list'),
...
# ์ค๊ฐ์๋ต
# post/pk/comment/ ํ์์ url์ด ๊ฐ์ง๋๋ฉด, views.add_comment_to_post() ์คํ
path('post/<int:pk>/comment/', views.add_comment_to_post, name='add_comment_to_post'),
]
๋๊ธ์์ฑ, DB ์ฐ๊ฒฐํ ํผ ๋ง๋ค๊ธฐ ( <์ฑ>/forms.py )
form django import forms
# ๋๊ธ ๋ชจ๋ธ ๋ถ๋ฌ์ค๊ธฐ
from models import Post, Comment
class PostForm(forms.ModelForm:
...์๋ต
# ๋๊ธ ํผ ์ถ๊ฐ
class CommentForm(forms.ModelForm):
class Meta:
# Post ๋ชจ๋ธ ์ฌ์ฉ
model = Post
# ์ฐ๊ฒฐํ ํ๋ ์ง์
fields = ('title', 'text',)
๋๊ธ ๊ธฐ๋ฅ ๋ง๋ค๊ธฐ ( <์ฑ>/views.py )
from django.shortcuts import render, get_object_or_404, redirect
from django.utils import timezone
from django.contrib.auth.models import User
from .models import Post
# ๋๊ธ ํผ ๋ถ๋ฌ์ค๊ธฐ
from .forms import PostForm, Comment
# ์ค๊ฐ ์๋ต
def add_comment_to_post(request, pk):
# Primary Key ์ด์ฉํด์, ๋๊ธ๋ฌ ๊ธ ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ
post = get_object_or_404(Post, pk=pk)
# post์์ฒญ์ด ์์ ๋, ๋๊ธ ์
๋ ฅ๋ฐ์ ํผ์ผ๋ก ์ ๋ฌ
if request.method=="POST":
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.post = post
comment.save()
# ๋๊ธ ์์ฑํ, ํด๋น ๊ฒ์๊ธ๋ก ์ด๋
return redirect('post_detail', pk=pk)
# post์์ฒญ์ด ์์ ๋, ๋๊ธ ์
๋ ฅ ๋ฐ์ ํผ์ ์ ๋ฌ
else:
form = CommentForm()
return render(request, '<์ฑ>/add_comment_to_post.html', {'form':form})
๊ฒ์๊ธ์ ๋๊ธ ํ์ํ๊ธฐ ( <์ฑ>/post_detail.html )
# ํฌ์คํธ ์๋์ ๋๊ธ ์ถ๊ฐ
{% for comment in post.comments.all %}
<div class="comment">
<div class="date">{{comment.created_date}}</div>
<strong>{{comment.author}}</strong>
<p>{{comment.text|linebreaks}}</p>
</div>
# ๋๊ธ์ด ์์ผ๋ฉด ์ค๋ช
ํ์
{% empty %}
<p>No comments here yet :(</p>
{% endfor %}
# ๋๊ธ ์
๋ ฅ ๋ฒํผ ์ถ๊ฐ, add_comment_to_post๋ก pk๊ฐ ์ ๋ฌ
<a href="{% url 'add_comment_to_post' pk=post.pk %}" class="btn btn-default">Add comment</a>
๐ ์ฅ๊ณ ๊ด๋ฆฌ์๋?
django์์ ์ ๊ณตํ๋, DB๋ด์ฉ์ CRUDํ ์์๋ ๊ธฐ๋ณธ ํ์ด์ง(admin)
์ฅ๊ณ ๊ด๋ฆฌ์ ์ฌ์ฉ๋ฒ ( <์ฑ>/admin.py )
# adminํ์ด์ง ์ฌ์ฉํ๊ธฐ ์ํ ๋ชจ๋ ๋ถ๋ฌ์ค๊ธฐ
from django.contrib import admin
# admin์์ ๊ด๋ฆฌํ DB ๋ถ๋ฌ์ค๊ธฐ
from .models import Post,Comment, <DB1>, ...
# DB๋ด์ฉ CRUD ๊ด๋ฆฌํ๊ธฐ
admin.site.register(Post)
admin.site.register(Comment)
admin.site.register(<DB2>)
...
# ๋ฐ๋ก ๋ฐ๋ก ์ฌ์ฉํด์ฃผ์ด์ผ ํ๋ค. - admin.site.register(Post, Comment, <DB1>) ์ค๋ฅ
๐ Template ํ๊ทธ ๋ง๋ค๊ธฐ ( ์ํ๋ ํ์ด์ฌ ๊ธฐ๋ฅ์ ํ ํ๋ฆฟ์์ ์ฌ์ฉ๊ฐ๋ฅ! )
์ํ๋ ํ๊ทธ ๋ง๋ค๊ธฐ ( <์ฑ>/templatetags/mytags.py )
# ์ซ์ ๋ํ๊ธฐ ํ๊ทธ ๋ง๋ค๊ธฐ
from django import template
register = template.Library()
# ํํฐ ํ๊ทธ ๋ง๋ค๊ธฐ
@register.filter
def add(num1, num2):
return num1 + num2
# ์ฌํ ํ๊ทธ ๋ง๋ค๊ธฐ
@register.simple_tag
def add_simple(num1, num2):
return num1 + num2
ํ๊ทธ ์ฌ์ฉ๊ฐ๋ฅํ๋๋ก ์ค์ ํด์ฃผ๊ธฐ ( <ํ๋ก์ ํธ>/settings.py )
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
#########################์ถ๊ฐํ ๋ถ๋ถ###########################
'libraries':{
'mytags': 'portfolio.templatetags.mytags',
}
#############################################################
},
},
]
๋ง๋ ํ๊ทธ ์ฌ์ฉํ๊ธฐ ( <์ฑ>/templates/<ํ ํ๋ฆฟ> )
{% load mytags %}
{% num1|add:num2 %}
{% add_simple num1 num2 %}
{# num1 + num2 ๋ฅผ ํ๋ฉด์ ํ์! #}
with ํ๊ทธ ์ด์ฉํ๊ธฐ
{% load mytags %}
{% with num1|add:num2 as result1 %}
{% result1|add:num3 %}
{% endwith %}
{# with๋ฅผ ์ฌ์ฉํด ํ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ์ ์ฅํ๊ณ , ํ์ฉํ ์ ์๋ค. #}