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)토큰 코드를 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>
- 중간의 `` 는 POST 요청시에 오류처리만을 보여주기 위한 시각적 개선안으로 사용된다. (없으면 사이트 전체가 바뀌기 때문에 인터페이스적으로 불편)
 - HTTP Method(서버에 요청하는 방식) : 
POSTVSGETGET: 어떠한 정보를 가져와 조회하기 위해서 사용- 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파일에서 ``의 형태로 들어감) 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),
]
- 로그인 후에 어떻게 될지는 다음에 하도록 함(기본적인 뼈대만 만들은 상태)