<오늘 한 일>
- 장고 개인 과제
이동 페이지 안정화(+에러 잡기)
문제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')
# 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 켜놓고 뭔가를 하자..안 그럼 나중에 정리하려면 내가 무슨 문제가 있었는지 기억해내기 쉽지 않다...