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)
생성한 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 메소드를 추가함으로써 해결할 수 있다.
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 파일을 수정해야 한다.
기존에 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를 누른 순간 바로 모델에 적용된 모습
GET /
: 지난번 작성한 introduce 페이지 responseGET /coffees
: 커피 목록을 unordered list로 보여주기POST /coffees
: 새로운 커피 추가PUT /coffees/<pk>
: 해당하는 커피의 정보를 변경DELETE /coffees/<pk>
: Primary Key 값에 해당하는 커피를 제거POST
, PUT
, DELETE
를 진행한 후 커피 목록을 unordered list로 보여주기GET /
기본 url의 template 변경
# 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)
# 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
Update
Watermelon 가격 및 국내산 여부 변경
Delete
Strawberry 삭제