[5주차]django - 20220105

김동영·2022년 1월 5일
0

Model

models.py 를 통해 데이터 베이스 객체를 생성한다.

# models.py

from django.db import models

# Create your models here.
class Coffee(models.Model):
    name = models.CharField(default = "", max_length = 15)
    price = models.IntegerField(default=0)
    is_ice = models.BooleanField(default=False)

  • default : 기본적으로 어떤 값이 들어갈지 정할 수 있다(초기값)
  • max_length : 최대길이, CharField의 경우에는 필수 정의

admin

생성한 model은 admin.py를 통해 등록하고 관리한다.

# admin.py
from django.contrib import admin
from .models import Coffee

admin.site.register(Coffee)

서버 실행 전에, migrate를 진행해야 한다.

python manage.py makemigrations homepage : homepage app에서 만든 모델(변경사항)을 기록

python manage.py migrate : 모델의 변경사항을 업데이트


커피 데이터베이스가 생긴 모습
오른쪽 상단 add 버튼을 통해 수동으로 데이터 베이스를 추가할 수 있다.


추가하면 저렇게 객체 이름이 model name obejcet 형태가 되는데,

# models.py

from django.db import models

# Create your models here.
class Coffee(models.Model):
    def __str__(self):
        return self.name
    name = models.CharField(default = "", max_length = 15)
    price = models.IntegerField(default=0)
    is_ice = models.BooleanField(default=False)

model 객체에 str 메소드를 추가함으로써 해결할 수 있다.

Template에서 model 확인하기

views.py

from models import Coffee

def coffee_view(request):
    coffee_all = Coffee.objects.all()
    return render(request, 'coffee.html', {"coffee_list" : coffee_all})

models.objects.all() 은 데이터 베이스의 모든 객체를 가져온다는 의미를 가진다.

url.py
...
path('coffee/', coffee_view) # 127.0.0.1/coffee/

url.py에 path를 추가한다.


# coffee.html

<!DOCTYPE html>
<html>
    <head>
        <title>Coffe List</title>
    </head>
    <body>
        <h1>My Coffee List</h1>
        {% for coffee in coffee_list %}
            <p>{{ coffee.name }} , {{ coffee.price }}</p>
        {% endfor %}
    </body>
</html>

model의 내용을 보여주기 위해서 html(template), url.py, views.py 3 파일을 수정해야 한다.

form 으로 template에서 model 수정하기

기존에 admin page에서 model(데이터베이스)을 수정할 수 있었는데, 이를 template에서 가능하도록 하려 한다.

homepage app에 forms.py를 새로 만든다.

django에 내장된 forms를 이용하여 필요한 정보를 명시하면 form을 구성할 수 있다.

# forms.py
from django import forms

from .models import Coffee

class CoffeeForm(forms.ModelForm): # ModelForm을 상속받는 CoffeeForm 생성
    class Meta:
        model = Coffee
        fields = ('name,', 'price', 'is_ice')

이를 views.py에서 호출해야 한다.

# views.py
from .forms import CoffeeForm
...
def coffee_view(request):
    coffee_all = Coffee.objects.all()
    form = CoffeeForm
    return render(request, 'coffee.html', {"coffee_list" : coffee_all, "coffee_form" : form})

template에서 작성한 form을 사용한다.

# coffee.html

<!DOCTYPE html>
<html>
    <head>
        <title>Coffe List</title>
    </head>
    <body>
        <h1>My Coffee List</h1>
        {% for coffee in coffee_list %}
            <p>{{ coffee.name }} , {{ coffee.price }}</p>
        {% endfor %}

        <form>
            {{ coffee_form.as_p }}
        </form>
    </body>
</html>

coffee_froms.as_p 를 사용하지 않으면 위와 같이 한줄로 나온다.

수정한 내용을 저장하는 버튼울 추가한다.

# coffee.html

<!DOCTYPE html>
<html>
    <head>
        <title>Coffe List</title>
    </head>
    <body>
        <h1>My Coffee List</h1>
        {% for coffee in coffee_list %}
            <p>{{ coffee.name }} , {{ coffee.price }}</p>
        {% endfor %}

        <form method="POST">
            {{ coffee_form.as_p }}
            <button type="submit">Save</button>
        </form>
    </body>
</html>

아직까지는 save 버튼을 사용하면 보안 문제가 발생한다.

이는 다음과 같이 csrf token을 삽입함으로써 해결한다.

# coffee.html

<!DOCTYPE html>
<html>
    <head>
        <title>Coffe List</title>
    </head>
    <body>
        <h1>My Coffee List</h1>
        {% for coffee in coffee_list %}
            <p>{{ coffee.name }} , {{ coffee.price }}</p>
        {% endfor %}

        <form method="POST">{% csrf_token %}
            {{ coffee_form.as_p }}
            <button type="submit">Save</button>
        </form>
    </body>
</html>

그런데 아직까지는 form을 등록해도 바로 모델에 변동된 모습이 확인되질 않는다.

views.py

def coffee_view(request):
    coffee_all = Coffee.objects.all()
    # 만약 request type이 post라면 post를 바탕으로 form을 완성하고 form이 유효하면 저장하도록 한다.
    if request.method == "POST":
        form = CoffeeForm(request.POST)
        if form.is_valid():
            form.save()
    else:
        form = CoffeeForm
    return render(request, 'coffee.html', {"coffee_list" : coffee_all, "coffee_form" : form})

앞서 save 버튼을 눌렀을 때 POST하도록 했고, 그럴 경우 form을 새로 구성하고 저장하도록 한다.

Save를 누른 순간 바로 모델에 적용된 모습

Mission

  • GET / : 지난번 작성한 introduce 페이지 response
  • 재고관리 대상을 정의(coffee, burger...)
  • 대상에 맞는 scheme를 모델로 작성
  • 커피를 예시로 했을 때,
  • GET /coffees : 커피 목록을 unordered list로 보여주기

보너스 과제

  • POST /coffees : 새로운 커피 추가
  • PUT /coffees/<pk> : 해당하는 커피의 정보를 변경
  • DELETE /coffees/<pk> : Primary Key 값에 해당하는 커피를 제거
  • POST, PUT, DELETE를 진행한 후 커피 목록을 unordered list로 보여주기
  • redirect() 함수를 사용할 필요가 있을 수 있음

  • GET /

기본 url의 template 변경


  • Fruit을 대상으로 DB schema 작성
# models.py

class Fruit(models.Model):
    def __str__(self):
        return self.name
    name = models.CharField(default = "", max_length = 15)
    price = models.IntegerField(default=0)
    is_domestic = models.BooleanField(default=False)

  • template 에서 button에 formmethod 를 추가함으로써 GET과 POST를 구별할 수 있지만, PUT과 DELETE request를 할 수 없다. 이를 구별하기 위해서 POST의 경우 button 자체에 value를 따로 삽입하여 구분하였다.
# fruit.html

<!DOCTYPE html>
<html>
    <head>
        <title>Fruits</title>
    </head>
    <body>
        <h1>Fruit List</h1>
        {% for fruit in fruit_list %}
            <p>{{ fruit.name }} , {{ fruit.price }}
            {% if fruit.is_domestic %}
                (domestic)
                {% endif%}
            </p>
        {% endfor %}

        <hr/>
        <form>{% csrf_token %}
            {{ fruit_form.as_p }}
            <button type = "submit" formmethod="POST" name="_method" value="POST"/>
                Create
            </button>
            <button type = "submit" formmethod="POST" name="_method" value="PUT"/>
                Update
            </button>
            <button type = "submit" formmethod="POST" name="_method" value="DELETE"/>
                Delete
            </button>
        </form>
    </body>
</html>

# views.py
def fruit_view(request):
    fruit_all = Fruit.objects.all()
    form = FruitForm
    if request.method == "POST":
        if request.POST.get("_method") == "PUT":
            temp = Fruit.objects.get(pk=request.POST.get("name"))
            temp.name = request.POST.get("name")
            temp.price = request.POST.get("price")
            if "is_domestic" in request.POST:
                temp.is_domestic = True
            else:
                temp.is_domestic = False
            temp.save()
        elif request.POST.get("_method") == "DELETE":
            Fruit.objects.filter(pk=request.POST.get("name")).delete()
        else:
            # "POST"
            form = FruitForm(request.POST)
            if form.is_valid():
                form.save()

    return render(request, 'fruit.html', {"fruit_list" : fruit_all, "fruit_form" : form})

삽입된 value를 가지고 각 기능을 구별했다.
이 때, boolean field의 경우 True이면 dict에 'on' value를 가지고 존재하고 False 이면 아예 dict에 들어있지 않다는 것을 조금 어렵게 알아챘다.

따라서 request.POST에 들어있는지의 여부로 True False를 구별하였다.


  • GET /fruit
    현재 fruit 목록을 보여주기


  • Create
    Orange 항목 추가


  • Update
    Watermelon 가격 및 국내산 여부 변경


  • Delete

    Strawberry 삭제

profile
오래 공부하는 사람

0개의 댓글