컨트롤+쉬프트+탭+T : 터미널

django-admin 하면 무슨 명령어 쓸 수 있는지 나옴

 

django-admin startproject pragmatic : 그럼 프로젝트가 만들어짐.

 

open -> project 열기로 들어가

 

가상 환경 만들어주자. 

File-settings-

일케 하면 가상 환경 만들어짐. 이제 터미널 껐다가 켜면...

자동으로 안돼.

ㅅㅂ...

 

venv/Scripts/activate.ps1 활성화해줘. activate.bat으로 하니까 안돼.

터미널이 파워쉘이라서 그런가봐.

 

python manage.py runserver 하면 서버 켜짐


django 개발 패턴

 

Model : 장고 데이터베이스와 통신하게 해주는 편리한 도구 

데이터베이스에 저장할 때 굳이 DB 언어를 사용하지 않고도 간편하게 디비 내용 수정/삭제 할 수 있게 함

View : 유저가 서버에 요청 , 그러면 서버가 응답을 해야지. 우리가 계산하는 부분.

Check if authenticated

Check request valid

Collect data from DB

Render response

Controller Template : 유저 인터페이스와 밀접하게 관련

 


첫 앱 시작, 그리고 기본적인 view 만들기

python manage.py startapp accountapp

 

그럼 새로운 accountapp 폴더가 생긴다

 

그럼 pragmatic 폴더의 settings.py에 가서 INSTALLED_APPS에 accountapp을 추가해준다.

이 프로젝트 안에서 아 이게 새로 설치된 앱이구나 라고 사용할 수 있는거야.

우리가 일일이 해줘야하는 부분이야.

 

실수) library root가 venv였는데, venv2를 켜고 왜 django 인식이 안되지? 이랬음.

처음에 venv2를 켠 이유는, activate.bat이 안되서 새로 만들었었거든.

알고보니 파워쉘이라서 activate.ps1이 맞았고.

 

accountapp의 views.py에 가자.

 

def hello_world(request):
	return HttpResponse('')

 

일단은 따라해보고, 나중에 한번 더 보면서 필기하자.

 

일단 git bash를 깔아서 git을 사용해볼거임.

 


pragmatic 폴더 안에 .gitignore 파일을 만들어. 근데 이미 깃헙에서 좋은거 제공해주구 있으니까 이거 쓰자.

gitignore/JetBrains.gitignore at main · github/gitignore · GitHub

 

GitHub - github/gitignore: A collection of useful .gitignore templates

A collection of useful .gitignore templates. Contribute to github/gitignore development by creating an account on GitHub.

github.com

아 글구 민감한 정보를 깃헙에 공유하면 안되잖아

그래서 pragmatic의 settings.py에 있는 secret 키를 안보이게 해줄거야

environ이라는 라이브러리를 써서..

django-environ

 

django-environ

Next Getting Started

django-environ.readthedocs.io

 

env 소스 settings.py랑 .env파일 만들어서 추가하고

VCS -> enable version control -> git

 

지금 보니까 git을 git bash로 하는 것보다 그냥 cmd에서 하는게 더 편할 것 같아

https://cofs.tistory.com/421

 

cmd에서 git 사용하기 / windows 에서 github 사용하기

windows의 cmd에서 git명령어를 사용해보자. 필자의 경우 windows에서 conda 가상환경을 만들고 이것저것 테스트 하다보니 다음과 같은 오류를 만나서 git을 사용해야 할 경우가 생겼다. ERROR: Cannot find

cofs.tistory.com

아니다

git bash쓰면 오른쪽에 branch가 나오네 ㅋㅋ

 

그러면 그냥 git bash 쓰자 ㅋㅋ

 

git status 하면

이제 모든 파일을 한번 추적해보자

 

git add .

 

그리구 git status 하면

모든 파일이 추적이 시작됐당

 

아직 아무것도 커밋 안했으니까 다 새로운 파일이라구 나옴

커밋하고나서 뭐 바꾸면 modified 나오징

 

git commit -m "Initial Commit" 해버리면

첫번째 커밋 완성

이제 아무 변경 사항이 없다고 뜨지.

왜?

이미 입력 했자나. 모든거를.

 

누런색은 추적이 안된다는 뜻임 ㅎ

 

environ 홈피에 있는 코드 말고 이대로 하면 됨.

environ이 제공하는 코드는 다른 것도 껴있는지 안되네

 


(빠진거)

accountapp의 __pycache__

pragmatic의 __pycache__

 

__pycache__ <- 이거 추가

 

이거 아직 안없앴네 gitignore에 추가해줌

그리고 git add .

git commit -m "delete redundant files"

 

 

* extends vs include

 

extends의 경우

 

ㅁ                                                          ■

ㅁ -> 비어있는 블록을 이용해서 채워나간다 ->■ 

ㅁ                                                          ■

즉, 상속

 

내부를 채운다.

 

include의 경우

ㅁ                                                       ■

ㅁ <- 내용물을 가져와서 빈 블록에다 넣음<-■ 

ㅁ                                                       ■

즉, 함수/멤버 가져다 쓰는거

 

즉...

extends로 바탕을 만들고, include로 내용을 채운다!

 

즉, 결론적으로 중간에 있는 결과물이 요청을 받았을 때 되돌려줄 Response View가 된다.

 

ㅁ (templete)  --- extends ---> ▣ (Response View) <---include----- ■ (내용물)

 

 

 

pragmatic에다가 templates 폴더 만듦

그 안에다가 base.html 만들고

내용을 

def hello_world(request):
    return render(request, 'base.html')

일케 바꿔

 

그럼 에러가 뜨거등

이제 templates를 연결해줘야대

settings.py의 TEMPLATES = [

'DIRS':[os.path.join(BASE_DIR, 'templates')],

]

이렇게 입력해주면 돼. 그럼 연결됨.

 

이제 이렇게 하구 git status를 해보니까

새롭게 추가된 파일들과 수정된 파일들이 보여.

 


9강.

include / extends / block 구문을 이용한 뼈대 html 만들기

 

templates에 head.html 만들어

글고 base.html에 있는 head 내용 다 head.html에 옮겨

글구 base.html에 {% include 'head.html' %} 추가해

 

팁) 커서, 알트, 커서 누르면 동시에 여러 줄 편집됨

 

글구 어차피 

 

header와 footer는 변경되지 않을거야

그러니까 footer.html, header.html 따로 만들어서 빼고

base.html에 {% include 'header.html' %}, {% include 'footer.html' %} 각각 자리에 추가해주면 돼.

 

accountapp 폴더 밑에 templates 폴더 만들고 그 밑에 accountapp 폴더를 만들어

굳이 왜 또 만들어?

안그러면 views.py에서 accountapp/base.html으로 해야돼.

가독성을 위해서 저렇게 폴더 밑에 폴더 만들어주면 base.html로 쓸 수 있어.

 

일단 accountapp/templates/accountapp/hello_world.html을 만들어

글고 

{% extends 'base.html' %}

{% block content %}
    <div style ="height:20rem; background-color:#38df81; border-radius:1rem; margin: 2rem;">
        <h1>
            testing
        </h1>
    </div>
{% endblock %}

이렇게 해서 base.html의 뼈대를 갖고 오게 할거야.

 

아 근데 이 전에, base.html은 이렇게 만들었어.

{% block content %} 이걸 넣어줬음.

<!DOCTYPE html>
<html lang="ko" xmlns:margin="http://www.w3.org/1999/xhtml">

{% include 'head.html' %}

<body>

{% include 'header.html' %}

{% block content %}
{% endblock %}


{% include 'footer.html' %}

</body>
</html>

 

글고 views.py를 이렇게 수정하면?

from django.http import HttpResponse
from django.shortcuts import render

# Create your views here.

def hello_world(request):
    return render(request, 'accountapp/hello_world.html')

이제 base.html을 읽어오는게 아니라, accountapp/hello_world.html을 읽어와.

근데 hello_world.html은 base.html의 뼈대를 그대로 갖고오고

block content 부분만 자기가 덧붙인거지.

그럼 어쨌뜬 이렇게 됨.

 


 

10강

style, 구글 폰트를 통해 Header, Footer 꾸미기

 

header.html 이렇게 만들구

<div>
    <div>
        <h1>Pragmatic</h1>
    </div>
    <div>
        <span>nav1</span>
        <span>nav2</span>
        <span>nav3</span>
        <span>nav4</span>
    </div>

</div>

이렇게 크롬 개발자 모드를 사용하면 어떻게 모양이 바뀔지 쉽게 확인할 수 있어.

이게 괜찮네?

그러면 코드에 바로 옮겨넣는거야

<div style="text-align:center;">
    <div>
        <h1>Pragmatic</h1>
    </div>
    <div>
        <span>nav1</span>
        <span>nav2</span>
        <span>nav3</span>
        <span>nav4</span>
    </div>

</div>

이렇게.

 

footer.html을 이렇게 바꿔주자

<div style="text-align:center;">
    <div style="font-size:.6rem;">
        <span>공지사항</span> |
        <span>제휴문의</span> |
        <span>서비스 소개</span>
    </div>
    <div style="margin-top:1rem;">
        <h6 style="margin-top:1rem;">Pragmatic</h6>
    </div>
</div>

그러면

이미 그럴듯해졌어 겉보기에는 ㅋㅋ

 

base.html에 <hr>도 넣어주고

<!DOCTYPE html>
<html lang="ko" xmlns:margin="http://www.w3.org/1999/xhtml">

{% include 'head.html' %}

<body>

{% include 'header.html' %}

<hr>

{% block content %}
{% endblock %}

<hr>

{% include 'footer.html' %}

</body>
</html>

여기서 header.html이랑 footer.html 각각 div style에 margin 2rem씩 줬어. (bottom, top 각각)

 

여기다 이제 boot strap을 적용시킬거야.

부트스트랩 = 트위터에서 만든 스타일 라이브러리

 

부트스트랩 들어가서

css 복사하는 것만으로 적용할 수 있어

 

Header.html에 css 복사한거 붙여넣어. 어차피 적용이 되거든. 

<head>
    <meta charset="UTF-8">
    <title>Pragmatic</title>
<!--    BOOT STRAP   --> <!--컨트롤 슬래시-->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"
          integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
</head>

글구 최상단 제목의 Pragmatic을 좀 띄울거야

header.html 드러가서

margin: 2rem 0; 이렇게 하면 2rem은 상하, 0은 좌우

 


이번에는 폰트를 바꿔보자

구글에서 구글 폰트 치삼

여기서 폰트 누르고 select this style 눌러

저거 긁어다가 header.html에 똑같이 복붙 하는거야

 

<head>
    <meta charset="UTF-8">
    <title>Pragmatic</title>
<!--    BOOT STRAP   --> <!--컨트롤 슬래시-->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"
          integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
    <!-- 구글 폰트-->
    <link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Hahmlet:wght@300&display=swap" rel="stylesheet">
</head>

 

 

그 다음에  

저 폰트 패밀리를 원하는 div style에다가 갖다 붙이는거야

 

그러면

<div style="text-align:center; margin: 2rem 0;"> <!-- 2rem 상하 / 0 좌우-->
    <div>
        <h1 style="font-family: 'Hahmlet', serif;">Pragmatic</h1>
    </div>
    <div>
        <span>nav1</span>
        <span>nav2</span>
        <span>nav3</span>
        <span>nav4</span>
    </div>

</div>

ㄹㅇ 간지나게 바뀜

 

footer.html도 똑같이 바꿈


11강

static 설정 및 css 파일 분리

디자인 파일만 따로 분리를 해두자

 

따로 분리하기 전에 static이라는 설정을 먼저 해야돼.

 

static : css, 자바스크립트 폰트 등 자주 변경되지 않는 asset

app별로 따로 관리하게 된다.

 

settings.py에 가서

이렇게 일단 함

STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')

 

팁) python manage.py collectstatic 하면 프로젝트에 있는 모든 static 파일들을 모아준대

 

os.path.join이 뭐임?

os는 라이브러리. os에서 제공하는 함수나 모듈

path는 경로 관련한 모듈

join은 그 중에서도 합치는 모듈

 

BASE_DIR은... 컨트롤 B 누르면 선언된 변수로 점프함.

BASE_DIR = Path(__file__).resolve().parent.parent

그럼 이게 나오는데

BASE_DIR이 의미하는건, 최상위 pragmatic 폴더 말하는거래.

 

1)  __file__은 현재 파이썬 파일의 위치를 나타내는 스페셜 변수이며

https://mingrammer.com/underscore-in-python/

 

파이썬 언더스코어(_)에 대하여

파이썬에서 언더스코어(underscore, _)는 특별하다. 타 언어에서 언더스코어(_)는 단지 스네이크 표기법의 변수나 함수명을 위해서만 사용되어지

mingrammer.com

2)

STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')

결국 이건 뭔 소리냐하면, 

최상위 pragmatic/staticfiles 폴더에 static 파일들을 다 모으겠다는 뜻임.

 

우리는 특정 app에 종속되지 않는, 프로젝트 전체에 유효한 static 폴더를 따로 만들고 싶어.

 

 

장고 docs 에 들어가서

STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')

STATICFILES_DIRS = [
    BASE_DIR / "static",
]

이렇게 추가하면 됨

 

원래 app 내부에 static 폴더가 있는데, 우리가 따로 추가를 해줌으로써 특정 앱에 종속되지 않도록 하는거야.

static 폴더 내부에 base.css 만들어.

 

footer.html에 이거 대신에

<div style="text-align:center; margin-top:2rem;">
    <div style="font-size:.6rem;">
        <span>공지사항</span> |
        <span>제휴문의</span> |
        <span>서비스 소개</span>
    </div>
    <div style="margin-top:1rem;">
        <h6 style="font-family: 'Hahmlet', serif;">Pragmatic</h6>
    </div>
</div>
<h6 class="pragmatic_footer_logo">Pragmatic</h6>

이렇게 바꾸고

static/base.css는 일케

.pragmatic_footer_logo {
 font-family: 'Hahmlet', serif;
}

클래스는 .으로 접근함

 

이제 base.css를 가져와줘야돼

 

head.html에다가 그 구문을 입력해줄건데, (왜 여기다? 왜냐면 여기다 적용하면 전체 문서에 적용됨)

 

그러려면 static 관련한 파일을 가져오기 위해서는 제일 위에 

{% load static %}을 적어줘야돼

 

{% load static %}

<head>
    <meta charset="UTF-8">
    <title>Pragmatic</title>
<!--    BOOT STRAP   --> <!--컨트롤 슬래시-->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"
          integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
    <!-- 구글 폰트-->
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Hahmlet:wght@300&display=swap" rel="stylesheet">

    <!-- Default CSS Link -->
    <link rel="stylesheet" type="text/css" href="{% static 'base.css' %}">
</head>

 

이렇게 해버리면 장고가 알아서 base.css 파일을 찾아서 렌더링을 해서 브라우저에 넘겨줌.

 

css에 옮기는건, 다 안해도 됨...

그냥 한 두개 정도 css로 할 필요 없는건 안해도 되징

 


12강

CSS 간단 핵심

DISPLAY 속성(attribute) : block, inline, inline-block, none

 

block : 모든 tag에는 부모가 존재함.

그 부모의 최대한의 너비를 모두 가져감. 부모의 최대 폭과 같다.

inline : 글씨의 높이만큼만 가져감 (글 안에 있다)

inline-block : ? 설명 이해 안감

none : 아무것도 없음

-> html 태그에 있긴 있는데, 브라우저에서는 없는거야.

 

cf) visibility : hidden

 

none은 진짜 없어지거든? 그런데 hidden은 있는데 눈에만 안보이는거야.

ㅁ■ 라고 하자. 

ㅁ이 none이면

그냥 ■ 되는거야.

그런데 hidden이면

(  )■ <- 이렇게 눈에는 안보이지만 뭐가 있는거야.

 

SIZE attribute

4개

 

px, em, rem, %

 

rem을 모든 곳에 써서 구축할거야. 가끔씩 % 씀

 

이유를 알려줌.

 

크기를 왜 신경쓰느냐?

우리는 responsive로 웹사이트를 만들거야.

모바일이나 pc 다 지원하게 만들거라.

 

1) px. 부모가 커지든 작아지든 무조건 width:100px, height:100px 안바뀜

2) em. 부모가 커지면 child가 따라가. 부모가 2배 커지면 자식도 2배 커짐

-> 부모가 여러 개 있을 때 문제가 돼. 

 

참고) 1rem = 16px.

 

부모가 2개 있고 각각 2배씩 커졌다고 하자. 그러면 2*2 총 4배됨.

3) rem. root html에 기본적으로 적용된 기본값에 anchoring 되어있어.

바로 위의 부모가 커지든 작아지든 상관없고, root html의 폰트 사이즈에 따라가.

4) %. 바로 위의 부모에만 영향을 받음.

 


13강.

CSS display 속성, rem 단위 실습

 

스타일 정하는게 지금 2가지 배웠지

 

div에 바로 div style ="height:20rem;" 이렇게 하는거랑

base.css 따로 만들어서 클래스로 하는거

 

그렇게 안하고

<style>
    .testing {
    background-color : white;
    }
</style>

이렇게 해도 돼.

 

그럼 3가지 방법의 적용되는 순서?

 

가장 중요한거. div style > <style> > CSS

 

팁) 내가 원하는 대로 display 설정이 안나온다. 그럼 div style한테 우선 순위가 밀렸을 수도 있어.

 

 

이번엔 git에서 이전으로 돌아가보자

 

git reset --hard HEAD

 

이렇게 하면 가장 최근에 한 커밋부터 지금까지 변경된 사항들을 모두 reset 하는거야

 


14강.

Model, DB 연동

 

기존에는 testing 이 부분이 정적이었잖아.

이제 이걸 DB와 연동시켜서 동적으로 바꿔볼거야. 저장하고 수정하고 이런거 되게.

 

python manage.py makemigrations

models.py에 쓰는 내용을 DB와 연동시킬 파이썬 파일로 만들어주는 역할함

 

accountapp/models.py

from django.db import models

# Create your models here.

class HelloWorld(models.Model):
    text = models.CharField(max_length=255, null=False) #char이 null이 되도 괜찮은지. 안괜찮으니 false.
    

이제 python manage.py makemigrations 돌려보면

디비랑 장고를 연결시키는 연결 고리

 

근데 이게 자동으로 연결이 되는게 아니라, 명령어 한번 더 쳐줘야돼.

 

python manage.py migrate

이러면 디비랑 연동이 된거임.

근데 나는 0001_initial.py 하나만 했는데 다른게 뭐가 많이 뜨지?

그건 urls.py에 기본적으로 있는 admin이랑 account 때문에 그런거임.

 

db 관련한거는 settings.py에서 볼 수 있어. 보니까 sqlite 쓰네.

 

디비는 나중에는 바꿔야되는데 현재 상황에서는 sqlite만 써도 되니까 일단은 함

글구 0001_initial.py 이거 다시 지우고 마이그레이션 다시 하겠다

이런건 절대 안됨.

다른 방법이 있대 알려주신다구 함

 


15강

HTTP 프로토콜 GET, POST

서버에서 무엇을 원하는지

GET : inquiry. 조회를 하기 위해서 많이 보냄.

조회할 때는 새로 뭔가 만드는 것보다는 적게 데이터가 들겠지.

그래서 https://onion.haus/?param1=value1 

?는 파라미터가 시작한다는 뜻

POST : 어떤 정보를 서버 내에서 추가하거나 수정할 때

create, update

 

https://onion.haus/ 

POST + BODY

POST는 같은 주소를 보낸다고 하더라도, get처럼 물음표를 치고 파라미터 보내느게 아니고

body라는 응답 몸통에 넣어서 보내.

예를 들어서, 게시글을 작성한다고 하자.

그걸 브라우저의 주소에 넣기에는 한계가 있잖아.

그니까 body 안에다 숨겨서 넣는겨.

근데 숨긴다는 뜻이, 암호화되어있다는 뜻이 아냐.

 

http는 암호화 안되어있고 https는 암호화 되어있어

 

* 16강 : GET, POST 프로토콜 실습

 

POST를 쓰려면 form을 만들어줘야돼. 

우리가 만들고 있는 /account/hello_world/ (슬래시 중요) 를 반드시 써줘야돼.

 

질문)

너무 이상해. /account/ 이건 어디서 나온거야?

지금까지 다 accountapp으로 했는데, 뜬금없이 어디서 나왔냐고?

 

저 btn btn-primary 클래스는 어디서 왔느냐? 부트 스트랩에서 왔다.

프라이머리 색깔 가진 버튼이 된다네?

 

이것만 하면 오류뜸

{% csrf_token %} 이라는걸 써줘야돼.

 

이게 뭔데? 장고에서 제공하는 보안 기능이래.

post를 이용해서 메세지를 보낼 때는, 항상 form 안에다가 csrf_token을 명시해줘야돼.

이걸 항상 적어줘야 이 post가 작동을 한다.

 

추가적인 데이터 꾸러미(context)안에 'text'라는 이름을 가진 문장을 실어 보내겠다.

def hello_world(request):

    if request.method == "POST":
        return render(request, 'accountapp/hello_world.html', context={'text':'POST METHOD!!!'})

text에 내용이 있으면 장고가 문장을 리턴해준다.

 

재밌는 점.

이미 들어온 상태에서는 잘 되는데, 주소창에 새로고침하면 에러가 뜬다.

왜?

POST에 대해서는 해줬는데, GET에 대해서는 아무런 처리도 안해줬잖아.

 

templates/accountapp/hello_world.html이야

def hello_world(request):

    if request.method == "POST":
        return render(request, 'accountapp/hello_world.html', context={'text':'POST METHOD!!!'})
    elif request.method == "GET":
        return render(request, 'accountapp/hello_world.html')

이렇게 하면

이런 식으로 나와

 


17강.

POST 통신을 이용한 DB 데이터 저장 실습

 

DB SAVE

1. Send POST data

2. Receive POST data

3. SAVE DB

 

일단 post data를 보내고, 받고, 그 데이터를 디비에 저장하는걸 해볼거야.

 

hello_world.html 보자

{% extends 'base.html' %}

{% block content %}
    <div style ="border-radius:1rem; margin: 2rem;">
        <h1 style="font-family: 'lobster', cursive;">
            testing
        </h1>

        <form action="/account/hello_world/" method="post">
            {% csrf_token %}
            <input type="submit" class="btn btn-primary" value="POST">
        </form>

        <h1>
            {{ text }}
        </h1>

    </div>
{% endblock %}

이렇게 되어 있거든. 저기 보면 div style에서 촌스러운 녹색 다 지워버렸고,

h1 style=font-family를 lobster, cursive 이렇게 두개 뒀는데, lobster라는게 없으면 cursive로 하라는거임.

만약 구글 폰트에서 못가져왔을 때.

 

{% extends 'base.html' %}

{% block content %}
    <div style ="border-radius:1rem; margin: 2rem; text-align:center;">
        <h1 style="font-family: 'lobster', cursive;">
            Hello World List
        </h1>

        <form action="/account/hello_world/" method="post">
            {% csrf_token %}
                <div>
                    <input type="text" name="hello_world_input">
                </div>
            <input type="submit" class="btn btn-primary" value="POST">
        </form>

        <h1>
            {{ text }}
        </h1>

    </div>
{% endblock %}

이렇게 하니까 input text가 생겼어.

 

from django.http import HttpResponse
from django.shortcuts import render

# Create your views here.

def hello_world(request):

    if request.method == "POST":
        temp = request.POST.get('hello_world_input')

        return render(request, 'accountapp/hello_world.html', context={'text':'POST METHOD!!!'})
    elif request.method == "GET":
        return render(request, 'accountapp/hello_world.html')

이거는.. POST를 누르면, request에서 POST중에 name이 hello_world_input을 가져와라.

 

글구 이렇게 수정하면? POST 값을 받아서 return할 수 있다. 어디에? hello_world.html의 {{text}} 자리에.

 

이제 받아오지.

 

이거를 이제 디비에 저장하고 싶어

 

models.py 보면 아까 만들어둔게 있어.

from django.db import models

# Create your models here.

class HelloWorld(models.Model):
    text = models.CharField(max_length=255, null=False) #char이 null이 되도 괜찮은지. 안괜찮으니 false.

알트엔터 치면 모델에서 임포트 알아서 해줌

 

new_hello_world=HelloWorld()

아까 HelloWorld라는 빵틀에서 새로운 객체인 new_hello_world를 만들게 돼

 

models.py 보면

class HelloWorld(models.Model):
    text = models.CharField(max_length=255, null=False) #char이 null이 되도 괜찮은지. 안괜찮으니 false.

이거 보면 HelloWorld로 만든 객체는 text 멤버를 갖고 있자나

 

new_hello_world=HelloWorld()
new_hello_world.text = temp
new_hello_world.save()

이렇게 해버리면, temp값을 text 멤버 변수에 저장하고,

new_hello_world.save() 해버리면 장고가 그냥 디비에 저장해버림.

 

views.py

from django.http import HttpResponse
from django.shortcuts import render

# Create your views here.
from accountapp.models import HelloWorld


def hello_world(request):

    if request.method == "POST":
        temp = request.POST.get('hello_world_input')

        new_hello_world=HelloWorld()
        new_hello_world.text = temp
        new_hello_world.save()

        return render(request, 'accountapp/hello_world.html', context={'hello_world_output':new_hello_world})
    elif request.method == "GET":
        return render(request, 'accountapp/hello_world.html')

그래서 new_hello_world 객체를 hello_world_output에 넣는거야.

(그럼 저게 객체인가... 저 자리가 무슨 자리인지 모르겠음.)

context  template 에서 쓰이는 변수명과, Python 의 객체를 연결하는 사전형 값입니다. 

라고 하네.

 

여기까지... 

버튼 누르면 이제 디비에 데이터가 저장이 된다.

담 시간에는 디비에 저장한 데이터를 화면에 뿌려주는걸 한다.

 


18강

DB 정보 접근 및 장고 템플릿 내 for loop

 

views.py

def hello_world(request):

    if request.method == "POST":
        temp = request.POST.get('hello_world_input')

        new_hello_world=HelloWorld()
        new_hello_world.text = temp
        new_hello_world.save()

        hello_world_list = HelloWorld.objects.all()
        return render(request, 'accountapp/hello_world.html', context={'hello_world_list':hello_world_list})
    elif request.method == "GET":
        return render(request, 'accountapp/hello_world.html')

 

HelloWorld.objects.all() 하면 HelloWorld의 모든 데이터를 다 긁어올 수 있어.

그 list를 돌려보내줄거야.

 

hello_world.html을 보면...

{% extends 'base.html' %}

{% block content %}
    <div style ="border-radius:1rem; margin: 2rem; text-align:center;">
        <h1 style="font-family: 'lobster', cursive;">
            Hello World List
        </h1>

        <form action="/account/hello_world/" method="post">
            {% csrf_token %}
                <div>
                    <input type="text" name="hello_world_input">
                </div>
            <input type="submit" class="btn btn-primary" value="POST">
        </form>


        {% if hello_world_list %}
        <h1>
            {{ hello_world_list }}
        </h1>
        {% endif %}

    </div>
{% endblock %}

 

이렇게 하면 일단 Hello_World의 리스트가 나와

우리가 받아온 오브젝트 자체야

그럼 이렇게 나오거든?

객체가 반환되는거야.

{% if hello_world_list %}
    {% for hello_world in hello_world_list %}
<h1>
    {{ hello_world.text }}
</h1>
	{% endfor %}
{% endif %}

그러면 이렇게 for문으로 받아온다음에 text로 접근하면 되징

 

그럼 이렇게 됨... ㄷㄷ

 

views.py

def hello_world(request):

    if request.method == "POST":
        temp = request.POST.get('hello_world_input')

        new_hello_world=HelloWorld()
        new_hello_world.text = temp
        new_hello_world.save()
        return HttpResponseRedirect(reverse('accountapp:hello_world'))
    else:
        hello_world_list = HelloWorld.objects.all()
        return render(request, 'accountapp/hello_world.html', context={'hello_world_list':hello_world_list})

좀 대대적으로 손봤는데...

일단 HttpResponseRedirect 이거는 왜 했냐하면, 바로 hello_world.html로 넘겨주고 싶어서.

그거 하려면 reverse 함수를 써야된대

 

근데 나는 애초에 새로고침 눌러도 post처럼 작동되는게 어색하다고 느껴서

그냥 get은 elif로 했었는데, 강사님이 어색하게 만든 이유가 있었어. 빌드업이었던거임 ㅋㅋ

 


Pycharm 디버깅 설정

run-configuration settings

 

 

manage.py에서 debug manage하면

 

그럼 실제로 서버가 돌아감.

 

차이점?

breaking point 걸고 하면 디버깅 할 수 있다는데 문제는

ㅅㅂ 나는 왜 에러뜨고 안되노?

브레이킹 포인트만 누르면 에러뜨고 멈추노

 

일단 시간 없으니까 넘어간다

 


20강

Django의 CRUD, Class Based View 소개

 

지금까지 우리가 한 것

 

Form (Input Text) -----> Hello World (Function) -----> HTML (Output Text)

물론 Form도 templates/hello_world.html 내부에 있음

 

추가적으로 보면, Hello World에서 Database에 저장/읽기 하고,

HTML에서 output text for문으로 읽기 했지

 

근데 문제점?

 

지금 누구나 글을 쓸 수 있자나.

그래서 우린 이제 인증 시스템을 구축할거야.

우리는 이제 계정이 필요하다

Account

 

우리는 지금까지 Account App을 만들고 있었던거야....... 미띤...

결과적으로 우리는 계정 관련된 function을 만들어야 한다.

만들어야 할 것?

 

1. Sign up  

2. View info (1과 2 사이에 login 기능 넣을거임)

3. Change info

4. Quit

 

장고는 CRUD로 유명하다

 

Create

Read

Update

Delete

 

왜 유명함?

 

CRUD에 대한 View를 따로 제공해

이 작업들에 최적화되어있는 도구들을 제공해

Create View

Read View

Update View

Delete View

 

이걸 Class Based View라고 함. <---> Function Based View. (ex. Hello World <- 함수 기반의 View)

 

ex)

class AccountCreateView(generic.CreateView):

model = User

form_class = AccountCreateForm

success_url = reverse_lazy('app:list')

template_name = 'accountapp/accountapp_create.html'

 

CBV를 하면, 생산성, 가독성 높아지고 복잡성/시간 낮아짐.

 

CRUD는

 

article

photo

account

project

profile

order

video

music

 

이 싸이클 안에 들어감.

 

하여간 이 싸이클 안에 모든걸 접목해서 만들겠다고 생각해야됨.

 

그래서,

Sign Up -> Create View

View Info -> Read View

Change info -> Update View

Quit -> Delete View

 

이렇게 만들거임.

 

--- 20강 끝...

 

21강

CreateView를 통한 회원가입 구현

지금 장고에서 Account 부분 만들고 있어. 

 

Sign Up -> Create View

 

이 사이에 Login View. 왜? 그래야 회원가입이 됐는지 확인이 가능

 

View Info -> Read View

Change Info -> Update View

Quit -> Delete View

 

views.py

from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render

# Create your views here.
from django.urls import reverse, reverse_lazy
from django.views.generic import CreateView

from accountapp.models import HelloWorld

...

class AccountCreateView(CreateView):
    model = User #상속
    form_class = UserCreationForm #장고가 기본제공
    success_url = reverse_lazy('accountapp:hello_World')
    template_name = 'accountapp/create.html'
    

    #함수와 클래스의 불러오는 방식이 달라서, reverse를 그대로 사용할 수 없다.
    #reverse_lazy는 클래스 뷰에서 사용하고 reverse는 함수 뷰에서 사용한다.

 

urls.py

urlpatterns = [
    path('hello_world/', hello_world, name='hello_world'),
    path('create/', AccountCreateView.as_view(), name='create')
]

as_view()를 써야 함수형과 똑같이 작동한대.

 

이제 views.py를 보자

class AccountCreateView(CreateView):
    model = User #상속
    form_class = UserCreationForm #장고가 기본제공
    success_url = reverse_lazy('accountapp:hello_World')
    template_name = 'accountapp/create.html'


    #함수와 클래스의 불러오는 방식이 달라서, reverse를 그대로 사용할 수 없다.
    #reverse_lazy는 클래스 뷰에서 사용하고 reverse는 함수 뷰에서 사용한다.

 

AccountCreateView를 추가해줘

 

그리고 templates/accountapp/에 create.html을 만들어.

 

create.html

{% extends 'base.html' %}

{% block content %}

<div>
    <form action="{% url 'accountapp:create' %}" method="post">
        {% csrf_token %}
        {{ form }}
        <input type="submit" class="btn btn-primary">
    </form>
</div>

<% endblock %}

자... 지금 뭘 한거냐하면

 

{{ form }} 이거 있지?

 

원래 회원가입 하려면 아이디, 패스워드, 기타 등등 input text 이 칸을 많이 만들어야하잖아

근데 create.html에 정의해두고 여기서 {{ form }}만 하면 알아서 불러와지는거야.

 

결과물을 보면

이렇게 내가 구현도 안한게 구현이 되어있어. 편하네.

 

테스트 해보니까 잘 된다.

(w하나 오타 고침)

 

근데 됐는지 안됐는지 확인이 안되잖아.

그럼 로그인을 한번 구축해보자.

 


22강

Login / Logout 구현

 

Login View

Logout View 

 

이 두 가지도 장고에서 제공함. 왜? 무조건 구현해야되는 기본적인거니깐.

 

urls.py

urlpatterns = [
    path('hello_world/', hello_world, name='hello_world'),
    path('login/', LoginView.as_view(template_name='accountapp/login.html'), name='login'),
    path('logout/', LogoutView.as_view(), name='logout'),
    path('create/', AccountCreateView.as_view(), name='create')
]

이렇게 하면

이렇게 로그인창도 내가 특별하게 구현 안했는데 돼

 

그리고 로그인해보면

이렇게 에러가 뜨는데, profile로 가라구 하지?

이게 우리가 선택을 안했기 때문에 default로 정해진 값으로 가는거야.

 

Login View랑 Logout View의 경로가 어떻게 가느냐?

 

Redirect Mechanism

 

POST나 GET 파라미터중에서 next라는 value 가진 값을 찾음.

next -> 없으면 -> LOGIN_REDIRECT_URL -> 없으면 -> Default

 

header.html에 이렇게 추가했음.

<div class="pragmatic_header"> <!-- 2rem 상하 / 0 좌우-->
    <div>
        <h1 class="pragmatic_logo">Pragmatic</h1>
    </div>
    <div>
        <span>nav1</span>
        <span>nav2</span>
        <span>nav3</span>
        {% if not user.is_authenticated %}
        <a href="{% url 'accountapp:login' %}?next={{ request.path }}">
        <span>login</span>
        </a>
        {% else %}
        <a href="{% url 'accountapp:logout' %}?next={{ request.path }}">
            <span>logout</span>
        </a>
        {% endif %}
    </div>

</div>

이제 로그인 로그아웃도 됨.

잘은 모르겠지만 아직두...

 

그런데 여전히 http://127.0.0.1:8000/account/login으로 접속해서 로그인을 하면

 

이런 오류가 다시 떠

그래서 LOGIN_REDIRECT_URL 을 신경써줘야돼

 

settings.py 맨 밑에다가

LOGIN_REDIRECT_URL = reverse_lazy('accountapp:hello_world')
LOGOUT_REDIRECT_URL = reverse_lazy('accountapp:login')

이거 추가하면 오류 안뜸.

 

 

  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기