📢 공지사항
home
💻

Django 1

상태
현지수
배정
월 17시~19시 : 1,2,3,
화 14시~16시 : 4,5,6,
수 14시~16시 : 7,8,
목 13시~15시 : 9,10, 복습
금13시~15시 : 복습

1. 파이썬, django, 가상환경 세팅

dir - 디렉토리 확인
cd - 디렉토리 이동
pip install virtual - 가상환경 관련 패키지 설치하기
virtualenv myenv - myenv 가상환경 만들기
activate.bat - 가상환경 실행
> \path\to\env\Scripts\activate
pip install Django - 장고 설치하기

2. 프로젝트 생성, app 생성, 서버 구동, django cycle

가상환경마다 다른 개발환경 구축 가능!
>py -m django —version : 가상환경 구동해서 django 설치 됐는지 확인하기
>django-admin startproject mysite : mysite라는 프로젝트 생성
>py manage.py runserver : 장고 프로젝트 제대로 작동하는지 확인(나왜이거 안되지)
>py manage.py startapp polls : polls 앱 생성
view 코드 작성 후 url 파일과 연결!(include 함수)
최상위 url conf에서 url을 파씽하고 받아서 path 별로 다른 앱으로 분기 시켜줌
url에 따라서 파씽을 해주고 path에 따른 앱으로 분기!
우리가 사용하고 있는 웹서버는 개발 목적으로만 사용해야함
클라이언트는 우리가 만든 웹어플리케이션을 보기 위해 요청을 함
장고는 경량개발 웹서버가 이미 설치되어있음
개발할때는 경량 웹서버 사용, 배포할 때는 Nginx / Apache 사용
클라이언트가 요청을 하면 웹서버인 Nginx / Apache이 요청 맞아줌
WSGI는 웹서버와 장고 프레임워크를 연결하기 위해 사용
사용자가 주소를 요청하는데 URL 파일에서 요청 주소 잘게 나누고 역할에 맞게 VIEW로 이동함

3. git 관련

git bash
ls : 디렉토리, 파일을 보기위한 명령어
cd : 위치를 이동하기 위한 명령어
git init : 디렉토리 초기화
git add : 현재 위치로부터 모든 파일 추적
git commit : 현재 파일, 디렉토리 저장
(글자 작성하려면 i 누르고 작성, esc 누르고 나온 후 :wq하면 저장 후 종료됨)
git push

4. django model, api

setting 파일에서 데이터베이스 종류 변경할 수 있음
>py manage.py migrate : 데이터베이스 테이블을 생성
<models에서 데이터베이스 모델 만들기>
from django.db import models class Question(models.Model): question_text = models.CharField(max_length=200) pub_date = models.DateTimeField('date published') class Choice(models.Model): question = models.ForeignKey(Question, on_delete=models.CASCADE) choice_text = models.CharField(max_length=200) votes = models.IntegerField(default=0)
Python
복사
Question, Choice 데이터베이스 모델 2개
Question - 질문 내용, 생성일
Choice - 선택지에 해당하는 질문, 투표
ForeignKey - Question이라는 데이터모델을 참조하겠다라는 뜻, 하나의 Question에 여러개의 Choicer가 대응됨으로 일-대-다
<모델의 활성화>
장고는 앱 별로 기능이 나눠져있는데 앱을 등록을 하느냐, 하지않느냐에 따라 사용여부가 달라짐
setting 파일 내 INSTALLED_APPS에 내가 만든 앱 등록하기
INSTALLED_APPS = [ 'polls.apps.PollsConfig', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', ]
Python
복사
polls 앱의 apps에서 config파일을 등록하겠다는 뜻
>py manage.py makemigrations polls : migration이라는 장소에다가 이 모델들을 데이터베이스 내에 테이블을 생성할 수 있도록 설계도를 만드는 작업
mygrate 명령어 입력하면 데이터베이스 내에 실제 테이블 만드는 작업 수행
<API>
>py manage.py shell : shell 내로 들어가기
API : 개발자가 필요로하는 데이터를 뽑아낼 수 있도록 만들어놓은 함수 / 서버에게 데이터베이스에게 데이터를 입력할 수 있도록 만들어놓은 함수
from polls.models import Choice, Question : choice, question 사용
Question.objects.all() : 현재 question 내의 모든 데이터를 갖고오기
from django.utils import timezone : 발행일 시간을 입력하기 위해 timezone 라이브러리 import
q = Question(question_text="What's new?", pub_date=timezone.now()) : 질문 입력
q.save()
q.id : 모델을 생성할 때 명시를 하지 않더라도 장고에서 자동으로 만들어주는 필드
class Question(models.Model): question_text = models.CharField(max_length=200) pub_date = models.DateTimeField('date published') def __str__(self): return self.question_text
Python
복사
str 메소드 사용해서 데이터 알 수 있게 해줌, 처음엔 1이라고 나오는데 하면 질문 나옴
커스텀메소드도 추가하기

5. django admin 사용법

admin : 사이트 관리를 위해 관리자 전용페이지로 거의 모든 웹어플리케이션에 존재함.
장고는 모델(데이터베이스)를 ui가 존재하는 화면으로 관리할 수 있게 해줌.
py manage.py createsuperuser : 관리자 생성
py manage.py runserver : 서버 시작
from django.contrib import admin from .models import Question admin.site.register(Question)
Python
복사
만든 모델을 보기 위해서는 admin.py에 작성
admin 화면에서 모델 안에 데이터 생성/삭제 가능

6. django view 사용

def detail(request, question_id): return HttpResponse("You're looking at question %s." % question_id) def results(request, question_id): response = "You're looking at the results of question %s." return HttpResponse(response % question_id) def vote(request, question_id): return HttpResponse("You're voting on question %s." % question_id)
Python
복사
view에서는 request라는 인자를 받고 HttpResponse 함수를 return하게 됨!!!!!!!!!!
# ex: /polls/ path('', views.index, name='index'), # ex: /polls/5/ path('<int:question_id>/', views.detail, name='detail'), # ex: /polls/5/results/ path('<int:question_id>/results/', views.results, name='results'), # ex: /polls/5/vote/ path('<int:question_id>/vote/', views.vote, name='vote'),
Python
복사
패턴에 걸리게 되면 뷰를 호출, question_id는 view에 있는 parameter와 일치해야함
#from django.shortcuts import render from django.http import HttpResponse from .models import Question # Create your views here. def index(request): #return HttpResponse("Hello, world. You're at the polls index.") latest_question_list = Question.objects.order_by('-pub_date')[:5] output = ', '.join([q.question_text for q in latest_question_list]) return HttpResponse(output) def detail(request, question_id): return HttpResponse("You're looking at question %s." % question_id) def results(request, question_id): response = "You're looking at the results of question %s." return HttpResponse(response % question_id) def vote(request, question_id): return HttpResponse("You're voting on question %s." % question_id)
Python
복사
question 질문 가져오기
클라이언트에게 보여주는 페이지 수정을 하려면 view 내에서 수정해야하기때문에 어려움.
그래서 내부로직 담당인 view와 디자인 담당인 템플릿 구분
어떻게 하면 수정영향범위를 줄일 수 있을까 고민
템플릿에 코드 연결할때 templates/polls/index 디렉토리 생성
<h1>{{ question.question_text }}</h1> <ul> {% for choice in question.choice_set.all %} <li>{{ choice.choice_text }}</li> {% endfor %} </ul>
HTML
복사
choice_set.all
from django.http import HttpResponse from django.template import loader from .models import Question def index(request): latest_question_list = Question.objects.order_by('-pub_date')[:5] template = loader.get_template('polls/index.html') context = { 'latest_question_list': latest_question_list, } return HttpResponse(template.render(context, request))
Python
복사
context를 통해서 템플릿의 데이터 전달하고 사용
render 함수 사용시 코드 양을 줄일 수 있음
shortcut 사용해서 예외 발생시키기(choice 외래키????????)

7. form, generic view

<form action="{% url 'polls:vote' question.id %}" method="post"> {% csrf_token %} <fieldset> <legend><h1>{{ question.question_text }}</h1></legend> {% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %} {% for choice in question.choice_set.all %} <input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}"> <label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br> {% endfor %} </fieldset> <input type="submit" value="Vote"> </form>
Python
복사
from django.http import HttpResponse, HttpResponseRedirect from django.shortcuts import get_object_or_404, render from django.urls import reverse from .models import Choice, Question # ... def vote(request, question_id): question = get_object_or_404(Question, pk=question_id) try: selected_choice = question.choice_set.get(pk=request.POST['choice']) except (KeyError, Choice.DoesNotExist): # Redisplay the question voting form. return render(request, 'polls/detail.html', { 'question': question, 'error_message': "You didn't select a choice.", }) else: selected_choice.votes += 1 selected_choice.save() # Always return an HttpResponseRedirect after successfully dealing # with POST data. This prevents data from being posted twice if a # user hits the Back button. return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))
Python
복사
form 태그, input 태그(입력할 수 있도록) 사용해서 view 수정
{% csrf_token %} : 사이트가 위조요청, 해킹 방지
사용자가 submit 버튼을 누르게 되면, 해당 url 호출하게 되고 url에서는 view의 vote 호출
view를 호출할 때 question id 넘겨받고 question 데이터를 조회하게 됨
이 question에 대해서 외래키를 갖는 선택지를 가져오는데 선택지 중에서 pk값이 템플릿에서 넘겨받은 값을 조회함
선택된 데이터가 없을 때 예외 발생, 다시 상세페이지로 reponse 함
데이터가 있는 경우에는 선택지에 표를 1 올려주고 저장 results url로 redirect
reverse 사용해서 url을 하드코딩하지 않기 위해서 app_name : url_name
result !!!!!!!!!!!!!!!!!!!!!!!
from django.urls import path from . import views app_name = 'polls' urlpatterns = [ path('', views.IndexView.as_view(), name='index'), path('<int:pk>/', views.DetailView.as_view(), name='detail'), path('<int:pk>/results/', views.ResultsView.as_view(), name='results'), path('<int:question_id>/vote/', views.vote, name='vote'), ]
Python
복사
generic view는 함수 기반 view와 달리 장고에서 미리 작성된 as_view 함수를 호출하여 view 호출
detail이나 results url에도 parameter 이름을 지우고 pk값만 명시해도 됨
pk는 db내의 하나의 데이터를 구분할 수 있는 값, 중복되지 않음
post-get 방식?

8. test

목적 : 버그 수정, 기능 명확히
import datetime from django.test import TestCase from django.utils import timezone from .models import Question class QuestionModelTests(TestCase): def test_was_published_recently_with_future_question(self): """ was_published_recently() returns False for questions whose pub_date is in the future. """ time = timezone.now() + datetime.timedelta(days=30) future_question = Question(pub_date=time) self.assertIs(future_question.was_published_recently(), False)
Python
복사
파일이름 tests.py
앱 내부에 파일 존재
필요한 패키지들 import하고
testcase를 작성할 때 testclass에 상속해주면 됨
class Question(models.Model): question_text = models.CharField(max_length=200) pub_date = models.DateTimeField('date published') def __str__(self): return self.question_text def was_published_recently(self): now = timezone.now() return now - datetime.timedelta(days=1) <= self.pub_date <= now
Python
복사
수정 : question 생성 날짜가 미래로 넘어가지 않도록 현재 날짜를 주고 최근 기준을 하루로 둠
테스트 코드는 충분할수록 좋음
<뷰 테스트>
from django.test.utils import setup_test_environment
setup_test_environment() : 테스트 환경 구성
from django.test import Client : 테스트 코드에서 사용자 역할!
response = client.get('/') : 클라이언트가 웹페이지 호출(get 조회를 위해 호출, post 데이터 생성 or 수정)
response.status_code : 상태코드 - 서버에서 응답에 대한 상태를 보여줌
def get_queryset(self): """ Return the last five published questions (not including those set to be published in the future). """ return Question.objects.filter( pub_date__lte=timezone.now() ).order_by('-pub_date')[:5]
Python
복사
미래의 날짜가 안나오도록 filter를 넣어서 현재 시간보다 작거나 같은 데이터를 가져오도록
__lte : less than = , 장고에서 제공되는 filter 조건

9. css, static file

렌더링 : 사용자가 서버로부터 데이터를 받아 자신의 화면에 보여지는 작업
화면이 보여지기 위해서는 html,css,javascript(static file = 정적파일)가 필요함
장고에서는 서버와 static file을 분리할 수 있게 기능을 제공해줌
앱 내부에 static 디렉토리 만들어서 관리해야함

10. customize admin

from django.contrib import admin from .models import Question class QuestionAdmin(admin.ModelAdmin): fields = ['pub_date', 'question_text'] admin.site.register(Question, QuestionAdmin)
Python
복사
admin을 customize 하기 위해서는 admin을 상속받는 클래스를 선언
클래스 내에 우리가 필요로 하는 값을 직접 부여해서 커스터마이징
register 인자의 두번째 인자로 커스터마이징한 클래스를 넘겨주면 됨
field를 직접 명시해서 보여지는 데이터 순서를 변경 가능
from django.contrib import admin from .models import Question class QuestionAdmin(admin.ModelAdmin): fieldsets = [ (None, {'fields': ['question_text']}), ('Date information', {'fields': ['pub_date']}), ] admin.site.register(Question, QuestionAdmin)
Python
복사
필드가 많아서 관리가 필요한 경우 fieldset을 통해 field를 묶어서 제목을 줄 수 있음
from django.contrib import admin from .models import Choice, Question class ChoiceInline(admin.StackedInline): model = Choice extra = 3 class QuestionAdmin(admin.ModelAdmin): fieldsets = [ (None, {'fields': ['question_text']}), ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}), ] inlines = [ChoiceInline] admin.site.register(Question, QuestionAdmin)
Python
복사
question admin에서 choice를 관리할 수 있도록 변경하기
Inline을 상속받아서 클래스 만들고, 보여질 모댈의 종류와 개수 명시
작성 후 questionadmin의 inline으로 choiceinline등록
class ChoiceInline(admin.TabularInline): : table 모습으로 변경 가능
리스트 디스플레이를 명시하지 않으면 리스트에 있는 데이터필드가 하나만 보이게 됨
class QuestionAdmin(admin.ModelAdmin): list_display = ('question_text', 'pub_date', 'was_published_recently')
Python
복사
얘로 변경 가능
<속성을 몇가지 부여하여 편리성 향상시키기>
ordering = 'pub_date' : 필드를 정렬할 때의 기준을 발행일로 하겠다
boolean = True : T/F 문자모습에서 아이콘 모습으로 보여짐
description = 'published recently?' : 타이틀을 변경시켜주는 속성
list_filter = {'pub_date'} : 왼쪽에 필터기능 추가
search_fields = ['question_text'] : 위쪽에 검색창 만들어짐
<admin 템플릿 변경하기>
앱관련 템플릿은 앱 내부에 만들었지만, admin 관련 템플릿은 최상위 위치에서 관리
최상위 위치에 template 디렉토리 만들고 내부에 하위디렉토리 admin 디렉토리 생성
setting 파일 템플릿 위치에 만든 템플릿 위치 명시 해주기
admin 템플릿 위치는 장고 소스코드 안에 있음(보통 가상환경 내부)
admin 하위디렉토리에서 커스터마이징 할 파일을 프로젝트 소스코드 위치로 복사해주기