[django] 초간단 쇼핑몰 - model,admin,register

Hyeseong·2020년 12월 8일
2

project

목록 보기
1/3

Project - 초간단 쇼핑몰 기능 구현

목차

  • 회원관리
  • 상품관리
  • 주문관리
  • 클래스를 활용한 뷰 생성
    • 함수 VS 클래스 -> 뷰의 재사용
    • 데코레이터 -> 기능의 재사용
  • DRF로 RESTful API도 개발

프로젝트 구성

우선 가상환경을 만들게요.


$ python -m venv venv

$ source venv/Scripts/activate
(venv)

$ pip install django
...
...

일차적인 가상환경 설정과 그 가상환경안에 라이브러리 설치는 끝났어요.

프로젝트 설치

프로젝트의 이름을 config라고 적고 해당 프로젝트 디렉토리와 파일을 현재 작업중인 디렉토리에 설치하도록 명령을 내렸어요.
ls명령어로 방금 구성한 파일과 디렉토리를 볼수 있어요.

$ django-admin startproject config .
$ ls
config/  manage.py*  venv/

자! 쇼핑몰을 만들 것이므로 3개의 앱(모델)이 필요해요.

  1. product
  2. user
  3. order
$ django-admin startapp product
$ django-admin startapp user
$ django-admin startapp order

config/settings.py파일 안에서 앱설치 리스트 변수에 우리가 만든 앱 3개를 작성해줍니다.

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
	
    # 3개 작성할게요.
    'product',
    'user',
    'order',
]

MVC 패턴에 따라서 프로젝트의 본격적인 작업을 시작해 볼게요.

Model 구성

앱이 3개 만들어진 만큼 order, user, product앱들의 models.py에 작성이 각각 이루어 질거에요.

order앱

from django.db import models

class Order(models.Model):
    user = models.ForeignKey('user.User', on_delete=models.CASCADE, verboss_name='사용자')
    # 유의할 것은 Foreign키의 필수 매개변수가 삭제될 경우 참조한 객체는 어떻게 할지를 결정하는 옵션이 on_delete에요. 
    # 첫번째 인자는 settings앱에 등록된 user앱의 models.py의 User클래스를 사용하겠다는 의미에요.

    product = models.ForeignKey('product.Product', on_delete=models.CASCADE, verbose_name='상품')
    quantity = models.IntegerField(verbose_name='수량')
    created_dt = models.DateTimeField(auto_now_add=True, verbose_name='등록날짜')

    def __str__(self): # 관리자 페이지에서 객체를 확인할때 속성값으로 받게되면 해당 값의 명이 출력되요. 아니면 이상한 `object`라는 명으로 출력되요.
        return self.name

    class Meta: # 관리자 페이지 설정
        db_table = 'my_order' # DB에 저장될 테이블 이름 지정
        verbose_name = '주문'
        verbose_name_plural = '주문'
        # 복수형 지정안하면 "주문s"가 되는데요. s붙이지 않기 위해서 그래요.

user앱

from django.db import models

class User(models.Model):
    email = models.EmailField(verbose_name='이메일') # 관리자 화면에서 좀더 편하게 한글화된 이름을 보도록 할게요.
    password = models.CharField(max_length=64, verbose_name='비밀번호')
    created_dt = models.DateTimeField(auto_now_add=True, verbose_name='등록날짜') # 처음 객체가 생성된 날짜를 자연스럽게 지정하기 위해 auto_now_add로 지정해요.

    def __str__(self):
        return self.email

    class Meta: 
    	db_table = 'my_user' 
    	verbose_name = '고객'
    	verbose_name_plural = '고객'
    

product앱

from django.db import models

class Product(models.Model):
    name = models.CharField(max_length=256, verbose_name='상품명')
    price = models.IntegerField(verbose_name='상품가격')
    description = models.TextField(verbose_name='상품설명')
    stock = models.IntegerField(verbose_name='재고')
    created_dt = models.DateTimeField(auto_now_add=True, verbose_name='등록날짜')

    def __str__(self):
        return self.name

    class Meta: 
    	db_table = 'my_product' 
    	verbose_name = '상품'
    	verbose_name_plural = '상품'

db를 생성하기 위한 작업을 진행해볼게요. 각 파일을 ctrl+s 눌러서 저장해주세요.
아래 명령어 딱 2개만 넣으세요.

$ python manage.py makemigrations order user product
$ python manage.py migrate

$ python manage.py makemigrations order user product
Migrations for 'product':
  product\migrations\0001_initial.py
    - Create model Product
Migrations for 'user':
  user\migrations\0001_initial.py
    - Create model User
Migrations for 'order':
  order\migrations\0001_initial.py
    - Create model Order

$ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, order, product, sessions, user
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying auth.0012_alter_user_first_name_max_length... OK
  Applying user.0001_initial... OK
  Applying product.0001_initial... OK
  Applying order.0001_initial... OK
  Applying sessions.0001_initial... OK

Admin 구성

관리자 페이지를 구성해 볼게요.
우선 각 앱의 admin.py 작업을 진행할게요.

user/admin.py

from django.contrib import admin
from user.models import User

class UserAdmin(admin.ModelAdmin):
    list_display = ('email',) # 마지막에 , 안 넣으면 문자열로 인식해요.

admin.site.register(User, UserAdmin)

order/admin.py

from django.contrib import admin
from order.models import Order

class OrderAdmin(admin.ModelAdmin):
    list_display = ('user','product',)
    
admin.site.register(Order, OrderAdmin)

product/admin.py

from django.contrib import admin
from product.models import Product

class ProductAdmin(admin.ModelAdmin):
    list_display = ('name','price',)
    
admin.site.register(Product, ProductAdmin)

관리자 아이디 생성

관리자 화면에 접속하기 위한 페이지를 생성해볼게요.

$ ./manage.py createsuperuser
Username (leave blank to use 'osori'): admin
Email address: admin@gmail.com
Password:
Password (again):
This password is too short. It must contain at least 8 characters.
This password is too common.
This password is entirely numeric.
Bypass password validation and create user anyway? [y/N]: y
Superuser created successfully.

Class Base View

부모클래스가 가진 것(메서드, 속성값)을 받아서 자식클래스가 재구현함

클래스 뷰를 어떻게 사용되는지 사용해야 할지에 대한 자세한 설명이 공식문서에 기록되어 있어요.
반드시 알고 넘어가야 장고를 사용할 수 있어요.

공식 문서

회원가입 만들기

회원가입을 하기전에 선행 사항들이 있는데요. MVC중에서 View 보는 영역을 한번 손보도록 할게요.
base.html을 만들건데요. bootstrap을 이용하게 될거에요.

view 작성

user/view.py

def index(request):
    return render('index.html')

template 작성

user/templates/base.html, index.html
해당 앱에 templates 디렉토리 안에 html 파일 2개를 만들어 줄게요.
안의 내용은 bootstrap을 이용해서 만들어 나갈게요.
css,js 링크와 스크립트 태그를 복사해서 html 파일 안에 넣어줍니다.
부트스트랩css, js

base.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <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-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW" crossorigin="anonymous"></script>

</head>
<body>
    <div class="container">
        {% block contents %}
        {% endblock contents %}
    </div>
</body>
</html>

index.html

{% extends 'base.html' %}
{% block contents %}
Hello World!
{% endblock %}

url 연결

config/urls.py

from django.shortcuts import render

def index(request):
    return render(request,'index.html')

화면 랜더링

python manage.py runserver

로컬 서버에서 잘 돌아 가는지 확인합니다.
hello world

회원가입 view만들기

form만들기

일단 form을 만들어야 해요.
user앱에 forms.py 파일을 만들고 소스코드를 작성할게요.

class RegisterForm(forms.Form): # forms.Form을 상속받아요.
    email = forms.EmailField(
        error_messages={    # 입력하지 않을시 생성되는 오류 메시지
        'required': '이메일을 입력해주세요'
        },
        max_length=64,
        label='이메일',
    )
    password = forms.CharField(
        error_messages={
            'required':'비밀번호를 입력하세요'
        },
        widget=forms.PasswordInput, # 추측컨데 비밀번호 입력 요건을 갖춘 입력방식이 될듯함.
        label='비밀번호'            # 라벨 이름을 표기함.
    )
    re_password = forms.CharField(
        error_messages={
            'required':'비밀번호를 입력하세요'
        },
        widget=forms.PasswordInput, 
        label='비밀번호'            
    )

이렇게 간단하게 form을 만들어 봤어요.

view 작성-1

회원가입 폼을 만들었으니 이를 활용할 view를 만들어 볼게요.

from django.shortcuts import render
from django.views.generic.edit import FormView # form을 활용할수 있게 해주는 클래스에요

def index(request):
    return render(request,'index.html')

class RegisterView(FormView):
    template_name = 'register.html'
    # template_name이라고 하면 html파일이조? 이게 부모인 FormView에서 가져온거에요.
    
    form_class = RegisterForm # 위의 임포트든 된것을 form_class의 값으로 할당해줌.

html작성(회원가입)

user/templates/register.html ...

{% extends "base.html" %}

{% block contents %}
<div class="row mt-5">
  <div class="col-12 text-center">
    <h1>회원가입</h1>
  </div>
</div>
<div class="row mt-5">
  <div class="col-12">
    {{ error }}
  </div>
</div>
<div class="row mt-5">
  <div class="col-12">
    <form method="POST" action=".">
      {% csrf_token %}
      {% for field in form %}
      <div class="form-group">
        <label for="{{ field.id_for_label }}">{{ field.label }}</label>
        <input type="{{ field.field.widget.input_type }}" class="form-control" id="{{ field.id_for_label }}"
          placeholder="{{ field.label }}" name="{{ field.name }}" />
      </div>
      {% if field.errors %}
      <span style="color: red">{{ field.errors }}</span>
      {% endif %}
      {% endfor %}
      <button type="submit" class="btn btn-primary">회원가입</button>
    </form>
  </div>
</div>
{% endblock %}

로컬에서 서버를 띄울 경우
깔끔하게 랜더링되어서 회원가입 페이지가 완성된걸 확인할 수 있어요.

하지만 기존 우리가 작성된 것에 빠진것이 있어요 validation유효성 검사입니다.

form추가작성

from django import forms
from user.models import User


class RegisterForm(forms.Form): # forms.Form을 상속받아요.
    email = forms.EmailField(
        error_messages={    # 입력하지 않을시 생성되는 오류 메시지
        'required': '이메일을 입력해주세요'
        },
        max_length=64,
        label='이메일',
    )
    password = forms.CharField(
        error_messages={
            'required':'비밀번호를 입력하세요'
        },
        widget=forms.PasswordInput, # 추측컨데 비밀번호 입력 요건을 갖춘 입력방식이 될듯함.
        label='비밀번호'            # 라벨 이름을 표기함.
    )
    re_password = forms.CharField(
        error_messages={
            'required':'비밀번호를 입력하세요'
        },
        widget=forms.PasswordInput, 
        label='비밀번호'            
    )

    def clean(self): # validation을 진행하는 메서드
        cleaned_data = super().clean() # 부모 클래스에서 갖고 있던 clean을 상속 받아요.
        email = cleaned_data.get('email')
        password = cleaned_data.get('password')
        re_password = cleaned_data.get('re_password')

        if password and re_password: # 비밀번호 입력란 2개가 입력되어야하고
            if password != re_password: # 2개가 입력되었지만 서로 다른 경우 오류 메시지를 출력하도록함.
                self.add_error('password', '비밀번호가 서로 다릅니다.')
                self.add_error('re_password', '비밀번호가 서로 다릅니다.')
            else:
                user = User(
                email = email,
                password=password,
                )
                user.save() # db저장
            

위 로직을 로컬에서 확인하면 아래와 같이 확인 할 수 있겠조?

유효성 검사 - 회원가입 실패시 결과

비밀번호가 서로 다를 경우

유효성 검사 - 회원가입 성공시 결과

profile
어제보다 오늘 그리고 오늘 보다 내일...

1개의 댓글

comment-user-thumbnail
2024년 1월 17일

order models.py 5행 verboss_name 오타 있어용

답글 달기