Languages/Python

[ํŒŒ์ด์ฌ] Django๋ž€? / ์‚ฌ์šฉ๋ฒ• (์ปค๋ฎค๋‹ˆํ‹ฐ ๊ฒŒ์‹œํŒ ๋งŒ๋“ค๊ธฐ)

MOONCO 2021. 3. 3. 00:21

๐Ÿ‘‰ 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๋ฅผ ์‚ฌ์šฉํ•ด ํƒœ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ์ €์žฅํ•˜๊ณ , ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. #}
๋ฐ˜์‘ํ˜•