<오늘 한 일>
- 장고 개인 과제
이동 페이지 안정화(+에러 잡기)
- 참으로 많은 에러들이 있었다...
- 문제1: 주소를 직접 쳐서 들어가면 들어가지는데 재고관리시스템, 상품등록을 누르면 해당 페이지로 이동하지 않음
<a class="navbar-brand" href="product-list">재고관리시스템</a>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="product-create"> 상품등록 <span class="sr-only"></span></a>
</li>
- 원래는 href 부분에 저렇게 앞에 /를 안 붙였었다
- 그래서 로그인한 다음에 저 버튼들을 누르면
http://127.0.0.1:8000/login/product-list
http://127.0.0.1:8000/login/product-create
- 주소가 이런식으로 입력돼서 페이지를 찾을 수 없다는 에러창이 떴었다
- 주소 앞에 /를 붙여주니까 말끔히 해결...!
<a class="navbar-brand" href="/product-list">재고관리시스템</a>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="/product-create"> 상품등록 <span class="sr-only"></span></a>
</li>
- 문제2: 로그인 하지 않았을 때 재고관리시스템을 누르면 에러 뜸
- 재고관리시스템을 누르면 상품목록을 볼 수 있는 페이지가 나오게끔 구현했는데, 그 페이지는 로그인한 사용자만 볼 수 있어서 에러가 뜨는 것이었다
- 로그인하지 않은 사용자가 재고관리시스템을 누를 경우 로그인 페이지로 이동하게끔 구현할 필요가 있었다
- 그래서 html 파일을 아래와 같이 수정했다
# 비로그인 사용자가 재고관리시스템을 클릭하면 로그인 페이지로 이동함
{% if not user.is_authenticated %}
<a class="navbar-brand" href="/login">재고관리시스템</a>
# 로그인 사용자가 재고관리시스템을 클릭하면 상품 목록 페이지로 이동함.
# 상품등록, 입고, 출고 버튼은 로그인한 사용자만 볼 수 있음
{% elif user.is_authenticated %}
<a class="navbar-brand" href="/product-list">재고관리시스템</a>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="/product-create"> 상품등록 <span class="sr-only"></span></a>
</li>
<li class="nav-item active">
<a class="nav-link" href="/inbound-create"> 입고 <span class="sr-only"></span></a>
</li>
<li class="nav-item active">
<a class="nav-link" href="#"> 출고 <span class="sr-only"></span></a>
</li>
</ul>
</div>
{% endif %}
- 문제 3: 서버 실행 후 나오는 주소인 http://127.0.0.1:8000를 클릭하면 로그인 창 또는 상품 목록 페이지가 나왔으면 좋겠는데 에러 페이지만 나옴
- 이것도 엄청 헤맸는데 해결하고 보니 너무 간단해서 문제로 쓰기 민망할 정도...ㅎㅎ
- views.py에 home이라는 함수를 새로 정의했다
# erp/views.py
def home(request):
# user라는 변수에 로그인된 유저인지에 대한 정보가 담긴다
user = request.user.is_authenticated
if user: # 로그인 된 상태면 상품목록 페이지로 이동
return redirect('/product-list')
else: # 로그인 안 된 상태면 로그인 페이지로 이동
return redirect('/login')
- urls.py 에서 함수를 부른다
# erp/urls.py
from django.urls import path
from . import views
app_name = 'erp'
urlpatterns = [
# 기본 주소로 접속하면 home 함수를 실행한다
path('', views.home, name='home'),
]
상품 등록 구현하기
- 일단 html 만들기 머리 아파서 admin 페이지에서 html이랑 css를 따왔다..
# erp/models.py
class Product(models.Model):
class Meta:
db_table = "product"
verbose_name = "상품"
code = models.CharField(max_length=32, null=False, verbose_name='상품코드')
name = models.CharField(max_length=32, null=False, verbose_name='상품명')
description = models.TextField(max_length=256, verbose_name='상품설명')
price = models.IntegerField(verbose_name='상품가격')
sizes = (
('S', 'Small'),
('M', 'Medium'),
('L', 'Large'),
('F', 'Free'),
)
size = models.CharField(choices=sizes, max_length=1, verbose_name='상품사이즈')
quantity = models.IntegerField(default=0)
def __str__(self):
return self.code
# def save(self, *args, **kwargs):
# # 생성될 때 stock quantity를 0으로 초기화 로직
# super().save(*args, **kwargs)
# if not self.id: # 생성시 id가 없음 -> 생성동작
# Product.objects.create()
# else:
# # do update
- 예시 코드에 save 함수가 있는데 이걸 어떻게 활용해야 할지 몰라서 그냥 주석처리 해놨다
# erp/views.py
@login_required
def product_create(request):
# 상품 등록 view
if request.method == 'GET':
return render(request, 'erp/product_create.html')
elif request.method == 'POST':
code = request.POST.get('code', '')
name = request.POST.get('name', '')
description = request.POST.get('description', '')
price = request.POST.get('price', '')
size = request.POST.get('size', '')
if code == '' or name == '' or price == '' or size == '---------':
return render(request, 'erp/product_create.html', {'error': '내용을 채우십시오.'})
Product.objects.create(
code=code, name=name, description=description, price=price, size=size)
return redirect('/product-list')
- 로그인한 사용자만 접근할 수 있게 했다
- 겟 요청인 경우 상품 등록 페이지를 띄우게 했고 포스트 요청인 경우 입력값을 데이터베이스에 저장하게끔 했다
- 설명을 제외하고 빈칸일 경우 내용을 채우라는 안내문구가 뜨게 했다
- 상품 등록을 누르면 상품목록으로 새로고침되게끔 했다
# erp/urls.py
app_name = 'erp'
urlpatterns = [
path('', views.home, name='home'),
path('product-create/', views.product_create, name='product-create'),
]
- urls.py에 상품 등록 주소를 연결하고 상품 등록 함수가 실행되게 했다
# base.html
<li class="nav-item active">
<a class="nav-link" href="/product-create"> 상품등록 <span class="sr-only"></span></a>
</li>
- 네브바에 상품 등록을 눌렀을 때 상품등록 페이지로 이동하게 설정했다
입고 구현하기
# erp/models.py
class Inbound(models.Model):
"""
입고 모델입니다.
상품, 수량, 입고 날짜, 금액 필드를 작성합니다.
"""
class Meta:
db_table = "inbound"
verbose_name = "입고"
product = models.ForeignKey(
Product, on_delete=models.CASCADE, verbose_name='상품코드')
quantity = models.IntegerField(verbose_name='수량')
inbound_date = models.DateTimeField(auto_now_add=True, verbose_name='입고날짜')
- 입고날짜를 모델에 넣긴 했는데....입고날짜를 같이 표시하려면 어떻게 해야하는지.....모르겠다...
- admin에도 입고날짜는 따로 없어서......데이터베이스에는 있는데...휴
# erp/views.py
@login_required
# @transaction.atomic
def inbound_create(request):
# 상품 입고 view
# 입고 기록 생성
if request.method == 'GET':
all_products = Product.objects.all().order_by('code')
return render(request, 'erp/inbound_create.html', {'products': all_products})
elif request.method == 'POST':
product = Product.objects.get(code=request.POST.get('code'))
quantity = request.POST.get('quantity', '')
if quantity == '':
return render(request, 'erp/inbound_create.html', {'error': '수량은 필수값입니다.'})
Inbound.objects.create(product=product, quantity=quantity)
# 입고 수량 조정
product.quantity += int(quantity)
product.save()
return redirect('/product-list')
- @transaction.atomic는 코드 예시에 붙어있던 건데 튜터님이 모르는 기능은 쓰지 말라고 하셔서 주석처리 했다
- 저걸 굳이 안 써도 입고 구현이 잘 돼서 그냥 주석으로 남겨놓고 시간이 남으면 저게 뭔지 알아보기로....
- 겟 요청일 때 {'products': all_products}가 있는 이유는 html에서 products를 for문에 돌려 상품의 코드를 가져오기 위함이다
- 포스트 요청에서 선택한 코드와 상품 데이터베이스에 있는 코드와 비교해서 일치하는 값이 있으면 product 변수에 넣는다
- 입고 모델에 값을 저장해주고, post로 받은 코드에 해당하는 그 상품의 수량을 조정한다
# erp/urls.py
from django.urls import path
from . import views
app_name = 'erp'
urlpatterns = [
path('', views.home, name='home'),
path('product-create/', views.product_create, name='product-create'),
path('product-list/', views.product_list, name='product-list'),
path('inbound-create/', views.inbound_create, name='inbound-create'), # 입고 url 추가
]
- 입고 url에 접속하면 inbound_create 함수가 실행되게 설정해주고
# erp/inbound_create.html
# 폼태그 부분
form class="form-area" method="post" action="/inbound-create/">
{% csrf_token %}
<div class="form-group mt-2 mb-2">
<label for="code">상품코드</label>
<select name="code">
<option value="">---------</option>
{% for product in products %}
<option value="{{product.code}}">{{product.code}}</option>
{% endfor%}
</select>
</div>
<div class="form-group mt-2 mb-2">
<label for="quantity">수량</label>
<input type="int" class="form-control" id="quantity" name="quantity">
</div>
<hr>
{% if error %}
<div class="alert alert-danger" role="alert">
{{ error }}
</div>
{% endif %}
<div style="float: right">
<button type="submit" class="btn btn-primary">등록</button>
<a href="#" class="btn btn-secondary">재고 관리</a>
</div>
</form>
- 폼 태그에 메소드는 post로 action은 입고페이지로 설정
- 상품 코드는 데이터베이스에 있는 코드들을 선택할 수 있게 함
- 수량 입력 안 하면 경고창 뜨게 함
- 재고 관리 부분은 아직 url을 입력 안 했음
- 그냥 상품 리스트로 갈 수 있게 해도 될 거 같긴 한데.....
- 과제 디렉토리 예시에 상품 목록 따로 있고 인벤토리 따로 있어가지고....내가 뭘 잘못 이해하고 있나..?
<오늘 새롭게 배운 것>
- 절대주소와 상대주소
- 절대주소는 앞에 '/'를 붙이고 상대주소는 안 붙임
- 그럼 절대주소는 그 주소로 이동하고 상대주소는 현재 주소에 그 주소가 이어져 나옴
- 상대주소는 어떤 때에 써야 하는지 잘 모르겠음
- 상대주소로 썼다가 오류가 계속 나서 매니저님 도움 받아서 절대주소 써서 해결함...
<느낀 점>
- 아 뭔가 할 수 있을 거 같으면서도
- 정말 아무것도 모르겠기기도 하고
- 혼란한 하루다
- TIL을 위한 정리가 하나도 안 되어 있어서 주말에 정리해서 수정할 예정....
- 여튼 오늘은 개인과제밖에 못했다ㅠ
<다음 주 목표>
- 장고프로젝트..!!! 잘 해야겠지...
- 그 와중에 알고리즘 문제도 하루에 1~2문제씩은 꾸준히 풀 것이다 정리는 못할지언정
- 정리는 주말에~0~
- TIL도 놓치지 말자....
- 이번주 과제한다고 목금 제대로 못 썼는데 평소처럼 TIL 켜놓고 뭔가를 하자..안 그럼 나중에 정리하려면 내가 무슨 문제가 있었는지 기억해내기 쉽지 않다...