본문 바로가기

Django

20210202_ Django admin, template,view만들기, url연결 - 회원가입, 로그인

Django

Django admin

  • 기본적으로 admin의 경우 settings.py를 통해 활성화 되어 있다.

  • 또한 urls.py의 경우에도 admin은 기본적으로 만들어져 있다.

  • url주소에 admin을 붙이면 관리자 창을 이용할 수 있다.

  • python manage.py runserver를 통해서 서버를 돌리고 해당 ip주소로 들어가면 홈페이지가 뜬다.

  • 해당 ip주소에 /admin을 넣으면 관리자 로그인 화면이 뜬다.

  • 서버 종료는 ctrl + c

  • 로그인을 위해서 계정을 만들어야 하는데 python manage.py createsuperuser 를 통해 만들수 있다.

    • 이를 통해서 로그인 하면 개발자 툴 페이지로 접근 가능하다.

Django admin 활용

  • 앱에서 만든 모델 어드민에 등록

  • admin.py 파일에 관리자가 사용할 정보를 넣을 수 있음

from django.contrib import admin
from .models import Sl_user
# Register your models here.


class Sl_userAdmin(admin.ModelAdmin):
    pass


admin.site.register(Fcuser, FcuserAdmin)
  • 저장후 runserver 시 모델이 들어간것을 볼 수 있고 모델 수정삭제를 Sql로 작성해야 하나 관리자 도구를 통해 유저 인터페이스 내에서 가능함

  • 시각화 개선

  • 인터페이스 내에서 생성된 앱안에 오브젝트가 무엇인지 알아보기 힘듦(그냥 단지 앱이름의 object로만 뜨기 때문에 각 오브젝트의 username을 반환시켜 알아보기 편하게 만들어야 함)

  • __str__ 을 통해서 객체를 문자열로 반환하게 만든다.

  • models.py 파일

from django.db import models

# Create your models here.


class Sl_user(models.Model):
    username = models.CharField(max_length=32, verbose_name='사용자명')
    password = models.CharField(max_length=64, verbose_name='비밀번호')
    registered_dttm = models.DateTimeField(
        auto_now_add=True, verbose_name='등록시간')

    def __str__(self):
        return self.username

    class Meta:
        db_table = 'slowbuscamp_user'
  • 이것 보다 더 보기 좋게 하기 위해 각 오브젝트의 필드와 내용이 보이게 하려면

  • admin.py 파일

from django.contrib import admin
from .models import Sl_user
# Register your models here.


class Sl_userAdmin(admin.ModelAdmin):
    list_display = ('username', 'password')


admin.site.register(Fcuser, FcuserAdmin)

  • 관리자 탭에서의 보여지는 테이블 이름 변경

  • models.py 파일

  • class Meta에서 관리자 탭 db테이블 이름변경 가능

from django.db import models

# Create your models here.


class Sl_user(models.Model):
    username = models.CharField(max_length=32, verbose_name='사용자명')
    password = models.CharField(max_length=64, verbose_name='비밀번호')
    registered_dttm = models.DateTimeField(
        auto_now_add=True, verbose_name='등록시간')

    def __str__(self):
        return self.username

    class Meta:
        db_table = 'slowbuscamp_user'
        verbose_name = '슬로우버스캠프 사용자'  # 기본적으로 복수형을 지원하기 때문에 s가 자동으로 붙게 되어 있음
        verbose_name_plural = '슬로우버스캠프 사용자'  # 복수형이름을 따로 지정하여 자동으로 붙는 s를 제거 가능

회원가입 구현

1. Django template 만들기

  • 표시될 회원가입 html 만들기

  • 기본적으로 bootstrap에서 제공하는 form, CSS, JS 기본 형식을 가져다 쓴다. 전체적인 형식은 starter template을 참고하여 head를 만들고 form 형식을 가져다가 body를 채운다.

  • bootstrap introduction

  • bootstrap form

  • form의 경우 입력을 받아 서버에 전달(POST)

  • {% csrf_token %}form안에 넣어 놓으면 암호화 키를 숨겨두어 크로스 도메인을 막아줌(django에서는 토큰 없으면 에러남)

    • 크로스 도메인은 다른 사이트에서 서버에 데이터 요청시 보안정책으로 SOP 동일 근원정책으로 회신 받지 못하는 것을 말함
  • CDN(콘텐츠 배달 네트워크)

    • 로컬이 아닌 css,html,js를 제공하는 서비스의 서버 원본에서 가져오는 것이 아니라 현재 pc에서 가장 빠르게 가져올수 있는 위치의 서버에서 요청하여 가져오게됨
    • 성능을 높이기 위해서 사용함(bootstrap에서 아까 연결하였음)
  • Static 폴더

    • css, js 등의 파일을 로컬에 넣어 놓고 연결시킴
    • bootstrap 4.3 theme free 키워드 검색 한 결과의 한 사이트
    • 사이트를 통해서 마음에 드는 스타일의 bootstrap.min.css 다운 받는다. 물론, bootstrap.css도 상관 없다. min은 압축용어라고 한다.
    • 프로젝트 폴더에 static 폴더 생성하여 해당 파일을 넣고 프로젝트 settings.py 에서 맨아래 STATIC_URL에서 STATICFILES_DIRS = [] 을 설정함
"setttings.py 파일"
STATIC_URL = '/static/'
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'static')
]  # BASE_DIR  이 프로젝트 폴더를 의미, 프로젝트 폴더의 static 폴더
<html>
<head>
        <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- <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"> -->
    <!-- bootstrap에서 다운받은 stylesheet 를 연결시켜 적용 -->
    <link rel="stylesheet" href="/static/bootstrap.min.css" />
    <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.4/dist/umd/popper.min.js" integrity="sha384-q2kxQ16AaE6UbzuKqyBE9/u/KzioAlnx2maXQHiDX9d4/zp8Ok3f+M7DPm+Ib6IU" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.min.js" integrity="sha384-pQQkAEnwaBkjpqZ8RU1fF1AKtTcHJwFl3pblpTlHXybJjHpMYo79HY3hIi4NKxyj" crossorigin="anonymous"></script>
</head>
<body>
    <div class="container">
        <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 %}
                    <div class="form-group">
                      <label for="username" class="form-label">사용자 이름</label>
                      <input type="text" class="form-control" id="username" placeholder="사용자 이름" name="username">
                    </div>
                    <!-- name 속성을 사용하여 서버에서 읽을수 있게함 -->
                    <div class="form-group">
                        <label for="useremail" class="form-label">사용자 이메일</label>
                        <input type="email" class="form-control" id="useremail" placeholder="사용자 이메일" name="useremail">
                      </div>
                    <div class="form-group">
                      <label for="password" class="form-label">비밀번호</label>
                      <input type="password" class="form-control" id="password" placeholder="비밀번호" name="password">
                    </div>
                    <div class="form-group">
                      <label for="re-password" class="form-label">비밀번호 확인</label>
                      <input type="password" class="form-control" id="re-password" placeholder="비밀번호 확인" name="re-password">
                    </div>
                    <button type="submit" class="btn btn-primary">등록</button>
                </form>
            </div>
        </div>
    </div>
</body>
</html>
  • 중간의 {{error}} 는 POST 요청시에 오류처리만을 보여주기 위한 시각적 개선안으로 사용된다. (없으면 사이트 전체가 바뀌기 때문에 인터페이스적으로 불편)
  • HTTP Method(서버에 요청하는 방식) : POST VS GET
    • GET : 어떠한 정보를 가져와 조회하기 위해서 사용
      • URL데이터 노출O / 데이터의 위치 헤더 / 캐싱 가능
      • htt://localhost:8080/boardList?name=제목&contents=내용
    • POST : 데이터를 서버로 제출하여 추가 또는 수정하기 위해서 사용
      • URL데이터 노출X / 데이터의 위치 바디/ 캐싱 불가
      • http://localhost:8080/addBoard
    • 참고 사이트

2. Django views 만들기

  • 해당 앱의 views.py 파일에서 구현할 로직과 데이터 베이스 연결 지정
  • 필요한 기능을 위한 import먼저하고 함수를 선언할때 request 객체로 선언해야함
  • request객체 : 클라이언트에서 서버로 보내는 요청을 담고 있는 객체
  • Django shortcut functions - render() 랜더 메서드 : 해당 파일을 렌더링함
  • 모양 및 옵션 : render(request, template_name, context=None, content_type=None, status=None, using=None)
  • 눈여겨 볼 옵션 context : dictionary 형태의 변수이름을 옵션에 넣으면 그 변수안에 들어 있는 key 와 value를 연결시켜 렌더링함 (key의 경우 html파일에서 {{key}}의 형태로 들어감)
  • HttpRequest 객체의 경우 여러가지 속성을 가지고 있는데 그중 HttpRequest.method 메서드의 경우 HTTP 메서드가 어떤 형식으로 오느냐를 가지고 수행할 명령을 지정가능하다. (GET , POST에 따라서)
  • POST를 받은 값을 할당할 변수 선언시 get을 통해 값이 없을 경우 예외 처리
  • 마지막으로 model 인스턴스인 sl_user의 save함수를 통해서 DB로 INSERT SQL 전달
from django.http import HttpResponse
from django.shortcuts import render
from django.contrib.auth.hashers import make_password, check_password 
# 저장된 password 암호화
from .models import Fcuser

def register(request):  # request 형태로 전달해줘야 되고
    if request.method == 'GET':
        # 반환하고 싶은 html파일, 폴더를 포함하면 경로 모양으로
        return render(request, 'register.html')
    elif request.method == 'POST':
        # username = request.POST['username'] # 값을 못받고 제출시 오류가 나기 때문에 예외 처리 필요
        # password = request.POST['password']
        # re_password = request.POST['re-password']
        username = request.POST.get('username', None)
        useremail = request.POST.get('useremail', None)
        password = request.POST.get('password', None)
        re_password = request.POST.get('re-password', None)

        res_data = {}

        if not (username and useremail and password and re_password):  # 값을 못받는 경우 에러시 에러출력 메세지
            res_data['error'] = '모든 값을 입력해야 합니다.'
        elif password != re_password:
            res_data['error'] = '비밀번호가 일치하지 않습니다!'
            # return HttpResponse('비밀번호가 일치하지 않습니다!')
        else:
            sl_user = Sl_user(
                username=username,
                useremail=useremail,
                password=make_password(password)  # 암호화 함수를 사용해서 암호화 하여 생성
            )

            sl_user.save()

        return render(request, 'register.html', res_data)
# 들어오는 방법이 2가지임, 직접 주소를 작성하는 경우 및 등록버튼을 눌러서 보내는 경우

3. Django urls 연결하기

  • 프로젝트 폴더 urls.py에 앱 연결 (주소창에 적을때 어떻게 연결할지 정해주는 것임)
  • 기존의 admin 연결과 같이 path경로 설정해줌
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('sl_user/', include('sl_user.urls'))
]
  • 주소창에 도메임 이름 이후에 오는 자원 경로 설정 -> sl_user/이라고 치면 sl_user라는 앱의 urls 파일로 연결

  • 앱 자체에 urls 파일 생성urls.py -> views의 해당 함수와 연결시키기

from django.urls import path
from.import views

urlpatterns = [
    path('register/', views.register),
]

로그인 구현

1. Django template 만들기

  • register html에서 필요 없는 부분을 제거하고, 제목 로그인으로 변경
  • username , password 만 남기고 버튼은 로그인으로 변경
<html>
<head>
        <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- <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"> -->
    <!-- bootstrap에서 다운받은 stylesheet 를 연결시켜 적용 -->
    <link rel="stylesheet" href="/static/bootstrap.min.css" />
    <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.4/dist/umd/popper.min.js" integrity="sha384-q2kxQ16AaE6UbzuKqyBE9/u/KzioAlnx2maXQHiDX9d4/zp8Ok3f+M7DPm+Ib6IU" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.min.js" integrity="sha384-pQQkAEnwaBkjpqZ8RU1fF1AKtTcHJwFl3pblpTlHXybJjHpMYo79HY3hIi4NKxyj" crossorigin="anonymous"></script>
</head>
<body>
    <div class="container">
        <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 %}
                    <div class="form-group">
                      <label for="username" class="form-label">사용자 이름</label>
                      <input type="text" class="form-control" id="username" placeholder="사용자 이름" name="username">
                    </div>
                    <div class="form-group">
                      <label for="password" class="form-label">비밀번호</label>
                      <input type="password" class="form-control" id="password" placeholder="비밀번호" name="password">
                    </div>
                    <button type="submit" class="btn btn-primary">로그인</button>
                </form>
            </div>
        </div>
    </div>
</body>
</html>

2. Django views 만들기

  • 기존의 앱에 login 함수 만듦
  • 기존 register와 다른 점은 거의 없으나 Sl_user.objects.get을 사용하여 db에서 username이 같은 것만 sl_user에 할당하여 모델을 가져오고, make_password된 sl_user의 password를 check_password를 통해 입력받은 password와 같은지 확인
from django.http import HttpResponse
from django.shortcuts import render
from django.contrib.auth.hashers import make_password, check_password  # 저장된 password 암호화
from .models import Fcuser
# Create your views here.


def login(request):
    if request.method == 'GET':
        return render(request, 'login.html')

    elif request.method == 'POST':
        username = request.POST.get('username', None)
        password = request.POST.get('password', None)
        res_data = {}
        if not (username and password):
            res_data['error'] = '모든 값을 입력해 주세요.'
        else:
            sl_user = Sl_user.objects.get(username=username)
            if check_password(password, sl_user.password):
                # 로그인 처리
                pass
            else:
                res_data['error'] = '잘못된 아이디 또는 비밀번호 입니다.'
        return render(request, 'login.html', res_data)

3. Django urls 연결하기

  • login/ 입력시 views의 login함수와 연결되게 설정
from django.urls import path
from.import views

urlpatterns = [
    path('register/', views.register),
    path('login/', views.login),
]
  • 로그인 후에 어떻게 될지는 다음에 하도록 함(기본적인 뼈대만 만들은 상태)