본문 바로가기

About coding/Today I learned

2023년 04월 04일 TIL [#Django 입문_2]


오늘의 학습 계획

_생활코딩 django 강의 2회독차(따라치기)

_튜터님이 만들어주신 파이썬 예제: 클래스 예제 다 풀기

_스파르타 django 강의 1회독차(2배속) > 2회독차(따라치기)


Django 새롭게 배운 내용

1.라우팅

_사용자가 접속하고 들어온 주소 (경로)(path)를 어디로 할당 할 지 처리하는 작업.

_사용자의 주소 입력 (http://127.0.0.1/) (http://127.0.0.1/create/) (http://127.0.0.1/read/1/) 이런 모양들 >

> myproject > urls.py > 먼저 urlpatterns 를 지정해주어야 한다. > 리스트형식으로써 안에는 라우팅과 관련된 정보가 적혀 있음. 예시는,

urlpatterns = [
    path('admin/', admin.site.urls),
]

예시의 admin은 관리자 화면으로 이동하기 위함. 장고가 기본으로 갖고 있는 것임. 이걸 응용해서 직접 해보자 > 

> 사용자가 http://127.0.0.1/ 주소를 들고 들어왔다 가정 > 

>  우선 제일 먼저 project의 urls.py 파일에서 import path 뒤에 include 써서 임포트하기 >

> urlpatterns = [ ] 안에 인클루드 경로 추가.

 

urlpatterns = [
	path('admin/', admin.site.urls)
    path('', include('연결할앱이름.urls'))   #연결할앱 아래에 있는 urls.py를 사용해라! 라는 뜻
]

> 프로젝트의 urls.py 파일을 복사해서 myapp에게도 urls.py 파일을 만들어줌 > 

> myapp의 urls.py에서 필요 없는 것들을 지워줌

   import에서 include 지워줌. 독스트링설명과 urlpatterns 리스트만 남김. >

> path()하고 받고싶은 경로들 적어줌.

from django.urls import path
urlpatterns = [
    path(''),
    path('create/'),
    path('read/1/')
]

다 했으면 view.py 들어가서 작동될 함수를 적어주는데, 아래와 같은 형식.

from django.shortcuts import render, HttpResponse

# Create your views here.
def index(request):
    return HttpResponse('Welcome!')

import에 HttpResponse 적어주는 것 중요하고, def index() 에서 인자값으로 무언가 받게 해주어야함. 관행적으로 request라고 한다.

이렇게 해 놓고 다시 myapp의 urls.py로 돌아가서 경로마다 해당하는 구체적인 함수(view에 만들어 논 것) 적어줌

from django.urls import path
from myapp import views
urlpatterns = [
    path('', views.index),
    path('create/', views.index),
    path('read/1/', views.index)
]

이런식으로 path('경로', views.함수이름)

이렇게 부른다.

 

다 됐으면 브라우저에서 http://127.0.0.1:8000 접근하면 "Welcome!" 화면이 나온다. ㅎㅎㅎㅎㅎ

여기서 매우 주의할 점!!! ** 장고가 실행되고 있어야함.

어떻게 실행하냐? (윈도우+vs코드기준) 터미널에서 python manage.py runserver 명령어 치면 동작.

이거 몰라서 자꾸 왜 안되지? 하면서 views.py 갔다가 urls.py 갔다가 여기저기서 터미널에서 파이썬 파일 실행 눌러보고 난리도 아니었다 ㅋㅋㅋㅋㅋㅋㅋ

갑자기 아 ... 문득.... 하고 manage.py runserver가 떠오름

그것도 앞에 python 붙이는 것 빼먹어서 한참 고생 🤣🤣🤣 그래도 찾아내서 뿌듯하다

흐흐흐

 

여까지 하면 라우팅도 끝!

 

이 아니라

마지막으로, 계속 변화하는 주소대로 path 받는 법을 해보자.

myapp의 urls.py 파일에서 시작한다.

from django.urls import path
from myapp import views
urlpatterns = [
    path('', views.index),
    path('create/', views.create),
    path('read/<id>/', views.read) #아까 read/1/ 이었던 곳 1 자리에 꺽쇠하고 id.
]

앞으로는 <id>자리에 무슨 숫자가 오느냐에 따라 보여주는 페이지 모습이 달라지게 될거다.

이 다음 단계는 view의 read 함수로 간다.

def read(request, id):
    return HttpResponse('read'+str(id))

read 함수에서 인자값으로 id를 새롭게 받아주고,

잘 받았는지 확인할 겸, 받은 id를 활용할 겸. 출력되는 'read'문자열 뒤에 id인자로 받은 값이 따라서 출력되도록 함.

결과는

요로케 주소창에 클라이언트가 /read/2/ 라고 치면

화면에 read2가 나오고.

요로케 주소창에 클라이언트가 /read/3/ 라고 치면

화면에 read3가 나오고.

요로케 주소창에 클라이언트가 /read/99/ 라고 치면

화면에 read99가 나오고.

 

잘 된다.

ㅎㅎㅎㅎㅎㅎㅎㅎㅎㅎㅎㅎㅎㅎ

이것으로 라우팅도 끝!

 

 

2. 장고 CRUD

 

 

 


오늘은 문시해알 대신 코딩테스트

 

_오늘의 코딩테스는 최빈값 구하기

:프로그래머스 2번 문제이지만 묘하게 난이도가 있는 친구.

def solution(array):
    # 최빈값 : 주어진 array 리스트 에서 가장 자주 나오는 값.
    # 여러개면 -1을 리턴.
    # 딕셔너리로 하자!
    
    # 빈 딕셔너리를 만들어서 정수배열을 하나씩 순회할 때,
    # 정수를 키값으로써 딕셔너리에 추가하며 중복이 아니면 밸류를 1로 지정,
    # 중복이면 밸류에 +1
    
    # GO!
    
    empty_dict = {}  #빈 딕셔너리 만들고 #{1:1, 2:1, 3:2...+1, 4:4} 이런 식으로 추가됨
    for num in array:
        if num in emptry_dict:
            empty_dict[num] += 1
            
 #여기서 empty_dict[num]이란, empty_dict 안에서 for문 돌리고 있는 num을 키값으로 가지는 밸류값을 지칭.
        
        else:
            empty_dict[num] = 1
            
 #여기까지 했으면
 	
    max_num = max(empty_dict.values()) 
    
 #다만 이건 최빈값의 밸류값을 가져왔을 뿐 키값이 아니다. *사전형을 가져오는 명령은 .values() .keys() .items() 하면 리스트로 가져옴
            
    return

여기서 맥스 넘이 나왔을 때 이게 최빈값인 줄 알았다 ㅋㅋ 사실 이건  최빈값이 아니라 최빈값 키가 가진 밸류값임.

 

 

이어서 쭉쭉 해보면,

def solution(array):

    empty_dict = {}  #{1:1, 2:1, 3:3, 4:1... }
    for num in array:
        if num in empty_dict:
            empty_dict[num] += 1
        else:
            empty_dict[num] = 1
    
    max_num = max(empty_dict.values()
    
    
    check_list = []
    # 빈 리스트를 만들고
    
    for key_, value_ in empty_dict.items(): # for문으로 아까 만든 딕셔너리의 키와 밸류를 같이 돌린다.
        if value_ == max_num:               # 밸류값이 맥스넘이랑 동일하면 그의 키값을 빈 리스트에 어펜드.
            check_list.append(key_)         # 그러면 리스트는 키값만 가지게 됨.
    
    print(check_list)

이렇게 하면 키값을 추려냈으니 얼추 끝났고, 마지막으로 array에서 최빈값이 여러개일 경우 -1을 리턴하도록 만드는 조건만 충족하면 된다.

 

 

def solution(array):

    empty_dict = {}  # {1:1, 2:1, 3:2 ... }
    for num in array:
        if num in empty_dict:
            empty_dict[num] += 1
        else:
            empty_dict[num] = 1

    max_num = max(empty_dict.values())

    check_list = []

    for key_, value_ in empty_dict.items():
        if value_ == max_num:
            check_list.append(key_)

    if len(check_list) > 1:  #만약에 최빈값이 여러개면 만들어진 리스트의 길이가 1 이상일 것이므로 랭을 쓴다.
        return -1

    else:
        return check_list[0]


print(solution([1, 2, 3, 3, 3, 4, 4, 4, 4, 4]))

이거 풀 때 맨날 다른 사람 풀이를 봐도 len이 나오길래, 무슨 의도로 쓴 건지 몰라서 궁금했는데,

오늘 소은님이 친절하고 자세하게 알려주셔서 명확하게 알게 되었다 ㅠ

너무 감사한 소은님 👍👍👍

 

알게된점

_딕셔너리에서 원하는 값만 추리는 코드들 .values() .keys() .items()

_len의 영리한 사용

_리스트의 대괄호와 딕셔너리의 대괄호는 다르다는 점!!!

리스트의 대괄호는 요소들의 인덱스(번째)를 나타내고, 딕셔너리의 대괄호는 키값을 지목하여 밸류값을 불러낸다.


작은 질문들:

Q. 생활코딩 django CRUD의 Delete 파트에서 따라가며 코딩하던 중, 아래와 같은 부분에서 id 값이 None으로 잡힌다.

from django.shortcuts import render, HttpResponse, redirect
from django.views.decorators.csrf import csrf_exempt
import random

nextId = 4
topics = [
    {'id':1, 'title':'routing', 'body':'Routing is...'},
    {'id':2, 'title':'view', 'body':'View is...'},
    {'id':3, 'title':'model', 'body':'Model is...'}
]

def HTMLTemplate(articleTag, id=None):
    global topics
    ol = ''
    for topic in topics:
        ol += f'<li><a href="/read/{topic["id"]}">{topic["title"]}</a></li>'
    
    return f'''
    <html>
    <body>
        <h1><a href="/">Django</a></h1>
        <ul>
            {ol}
        </ul>
        {articleTag}
        <ul>
            <li><a href="/create/">create</a></li>
            <li>
                <form action="/delete/" name="id" method="post">
                    <input type="hidden" name="id" value="{id}">
                    <input type="submit" value="delete">
                </form>
            </li>
        </ul>
    </body>
    </html>
    '''

def index(request):
    article = '''
    <h2>Welcome</h2>
    Hello, Django
    '''
    return HttpResponse(HTMLTemplate(article))

def read(request, id):
    global topics
    article = ''
    for topic in topics:
        if topic['id'] == int(id):
            article = f'<h2>{topic["title"]}</h2>{topic["body"]}'
    return HttpResponse(HTMLTemplate(article, id))


@csrf_exempt
def create(request):
    global nextId
    if request.method == 'GET':    
        article = '''
            <form action="/create/" method="POST">
                <p><input type="text" name="title" placeholder="title"></p>
                <p><textarea name="body" placeholder="body"></textarea></p>
                <p><input type="submit"></p>
            </form>
        '''
        return HttpResponse(HTMLTemplate(article))
    elif request.method == 'POST':
        title = request.POST['title']
        body = request.POST['body']
        newTopic = {"id": nextId, "title":title, "body":body}
        topics.append(newTopic)
        url = '/read/'+ str(nextId)
        nextId = nextId + 1
        return redirect(url)
    

@csrf_exempt
def delete(request):
    global topics
    if request.method == 'POST':
        id = request.POST['id']
        print('id', id)
        newTopics = []
        for topic in newTopics:
            if topic['id'] != int(id):
                newTopics.append(topic)
        topics = newTopics
        return redirect('/')

스파르타 껄로 공부한 다음에 돌아오면 여기서 부터 다시 추적할 것. 이걸로 Delete를 마치고 Update 공부해야 한다.

https://www.youtube.com/watch?v=bycMlzNMuiM&list=PLuHgQVnccGMDLp4GH-rgQhVKqqZawlNwG&index=12 

12강 5분 51초 근처

 

>헐 미쳤다! 한참을 고민해도 안보이다가 갑자기 눈에 들어왔는데 이 부분 때문인가?

아까 id 인자로 받는 곳이 없어서 오류 날까봐 임시로 정해둔 것. id=None 이라고 정해뒀던 값을 풀자.

id 값을 지우니... 오류가 난다... 킁... 다시 None으로 적어 놓고...


복습용 키워드 메모장:

[스파르타 django]

#클라이언트 #서버