Django

안재영·2024년 4월 8일

Django?

장고는 파이썬으로 만들어진 무료 오픈소스 웹 애플리케이션 프레임워크 입니다

파이썬 가상환경 설정

cmd를 이용하여

py -m venv 프로젝트경로

를 실행시키면 해당 경로에 가상환경이 생성됩니다.

가상환경 활성화

프로젝트경로\Scripts\activate.bat

를 실행시키면 가상환경이 활성화됩니다

활성화된 가상환경을 비활성화시키고싶다면

deactivate

를 실행시켜주세요

Django

가상환경구축을 완료했다면 Django를 설치해봅시다

py -m pip install Django

장고 프로젝트 생성

django-admin startproject 프로젝트명

입력하면 프로젝트 경로에 방금 입력한 프로젝트명으로 프로젝트가 생성됩니다

cd 프로젝트명
python manage.py runserver

해당 프로젝트로 이동후 프로젝트 내의 manage.py 로 서버를 실행시켜주면 local 주소를 확인 할수있는데 해당 주소를 브라우저에 입력하면 서버가 실행 된 것을 볼수 있습니다

일단 서버를 종료시킵니다

ctrl+c를 누르면 서버를 종료시킬수있습니다

장고를 이용하여 app을 생성해봅시다

python manage.py startapp polls

프로젝트내에 polls라는 폴더가 생겼습니다

이제 url를 이용하여 pulls에 접근하는 방법을 찾아봅시다

장고 프로젝트의 urls를 열어보면 urlpatterns 을 확인할수 있습니다.

from django.urls import path, include

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

import 내용에 include를 추가하고 path에 polls를 추가합니다

이제 장고서버를 실행시켜서 url에 /polls 로 접근하게 되면 이후 작업을 polls.urls에서 처리하게됩니다

polls쪽 작업을 진행해봅시다

urls.py를 생성해줍니다

그후 아래 코드를 입력해줍니다

from django.urls import path
from . import views

urlpatterns = [
    path("", views.index, name='index'),
]

이제 /polls로 들어오게되면 views.index를 실행하게됩니다

이제 실행되는 views파일을 처리해봅시다

일단 기존에 적혀있는 내용을 전부 지우고 아래 코드를 입력해봅시다

from django.http import HttpResponse

def index(request):
    return HttpResponse("hello world.")

작업이 완료됬으면 다시 장고 서버를 실행시켜줍니다

주소/polls/ 로 접근하게되면
기존 프로젝트의 urls에서 path의 polls를 타고
polls의 urls로 이동한뒤 polls의 path를 타고
views의 index를 실행하게됩니다.

views의 index는 HttpResponse("hello world.")를 리턴하고 있으니 서버는 해당 내용을 응답받아 브라우저에 hello world 를 보여주게됩니다

지금까지의 설명은 장고를이용해 url을 처리해 고정된 값을 넘겨주는 경우를 처리했지만 보통의 페이지들은 고정된 값을 던져주는것이 아닌 DB를 읽고 요청하는 값을 넘겨주는게 대부분의 페이지들입니다

장고를 이용하여 DB에서 값을 읽어오는 방법을 알아봅시다

model

모델은 db를 테이블 별로 읽어서 하나의 테이블에 저장되어있는 값을 코드에서 읽을수있게 도와줍니다 이러한 기능을 orm이라고 부릅니다

장고 모델에서 자주사용되는 field 타입

  • booleanField
  • charField
  • DateField
  • DateTimeField
  • FloatField
  • JSONField
  • TextField

그 외의 field등이 궁금하다면 https://docs.djangoproject.com/ 로 들어가서 확인해봅시다

모델을 만들어봅시다

polls에 models.py로 이동해줍니다

class Question(models.Model) :
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField(auto_now_add=True)

class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

질문의 내용을 처리할수있는 Question과 질문의 답을 받는 Choice를 만듭니다

이제 이 내용을 이용하여 모델을 테이블에 써주기위한 마이그레이션이라는걸 만듭니다

장고의 마이그레이션 기능은 설치된 앱에 대해서 진행 하기 때문에

프로젝트에 settings.py로 가서 INSTALLED_APPS 로 가서

'polls.apps.PollsConfig’, 

를 추가해polls를 등록해줍니다

이제 cmd로 가서

python manage.py makemigrations polls

를 실행시키면 polls에 대한 마이그래이션이 진행됩니다

해당 내용의 sql이 궁금하다면

python manage.py sqlmigrate polls 0001

을 실행시키면 sql을 볼수있습니다

해당 내용을 확인하다보면 model을 작성할때 넣지않은 id가 생성되어 primary key로 잡혀있는것을 볼수있습니다.
장고에서 마이그래이션을 진행하게되면 id가 생성되어 primary key로 자동으로 잡히게됩니다

이제 테이블을 생성해봅시다

python manage.py migrate

를 실행하면 장고에 설치된 apps에 대해 모든 migrate 를 진행합니다
진행 내역을 살펴보면 우리가 만들려했던 polls.0001에 대해서도 진행이 완료된것을 확인할수 있습니다

혹시 모델에 수정사항이 생길경우는 똑같이 makemigrations후 migrate를 진행하면 반영이 됩니다

이 상태에서 수정사항이 잘못되어 다시 전에쓰던 마이그래이션으로 돌아가야될경우

python manage.py migrate polls 0001

를 입력하면 전에쓰던 0001버전으로 돌아가게됩니다

admin

admin 페이지는 일반적으로 시스템을 관리하는 페이지를 말합니다
장고에서는 생성된model들을 기반으로 데이터를 생성, 조회, 수정, 삭제 기능(CRUD)을 지원합니다

장고에서 지원하는 어드민기능을 사용하기위해 어드민 계정을 만들어줍시다

python manage.py createsuperuser

을 입력하면 아이디 비밀번호등 정보를 입력해달라고 나옵니다

입력해줍시다

어드민으로 접속해봅시다

프로젝트의 urls.py로 이동하면 urlpatterns에서

path("admin/", admin.site.urls),

를 확인할수 있습니다

이를확인하니 주소/admin으로 접속할경우 admin.site가 나온다는걸 알수있습니다

접속해줍시다

접속후 user를 클릭해보면 방금 생성한 admin계정의 정보를 볼수있습니다

admin을 클릭하고 상세정보로 들어가서 permissions를 확인해보면 superuser가 체크되어있는걸 볼수있습니다

이를이용해서 다른 super유저를 생성해봅시다 좌측 user 에 add를 클릭해줍시다

아이디와 비밀번호를 입력해서 생성해줍시다

이제 생성된 admin2를 클릭하여 permissions에서 원하는 권한을 모두 체크한뒤 하단에 save를 눌러줍니다

생성과 정보 수정까지 모두 진행이 됬습니다

이러한 기능은 사용자뿐만 아니라 모든 모델들에 사용할수 있습니다

polls 의 admin.py로 이동해 정보를 수정해줍시다

from django.contrib import admin
from .models import Question, Choice

# Register your models here.
admin.site.register(Question)
admin.site.register(Choice)

해당 내용을 저장하고 admin페이지에서 새로고침을 진행하면 polls 관련내역이 추가된것을 볼수있습니다

좌측 add를 누르면 모델의 field에 맞게 입력 창이 나옵니다

내용을 입력후 save를 누르면 데이터가 추가가됩니다

question에 정보를 추가해보면 내용이 question object(1)로 출력되고있습니다 이를 알아보기쉽게 text의 내용이 출력되게 수정해봅시다

model.py로 이동하여


class Question(models.Model) :
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.question_text

question에 str 을 추가해줍시다

self.question_text를 하면 자신의 question_text를 리턴하게됩니다

Django shell

장고 셀은 파이썬 셀과 똑같이 장고를 한 단계씩 실행해볼수 있는 환경입니다

polls에 있는 question을 한번 확인해봅시다

from polls.models import *
Question.objects.all()

장고 셀은 전체 프로젝트를 관점으로 실행되기때문에 import를 할때는 정확하게 polls.models 를 찾아줘야합니다

후 Question.objects.all()로 호출해주면 admin화면에서 봤듯이 question이 제목으로 쭉 나오게됩니다

하지만 장고 셀이 열려있는 상태에서 장고 내역이 수정되어도 서버와다르게 바로 반영이되지 않기때문에 셀을 종료후 다시 실행시켜줘야합니다

다시 admin화면으로 가서 choice의 내역을 추가해줍시다

choice = Choice.objects.all()[0]
choice.choice_text
choice.question

을 실행해보면

choice_text는 입력한 choice_text가 나오지만
question에서는 choice와 연결된 question의 값이 잡히는걸 볼수있습니다

choice.question.question_text

를 입력해보면 question의 제목이 정확하게 잡히고있는것을 볼수있습니다

반대로 진행해봅시다

question = Question.objects.all()[0]
question.Choice

이번에는 choice 가 잡히지않는것을 볼수있습니다

이유는 Choice는 foreign key로 Question을 잡고있지만 Question은 그러지않기때문에 Choice를 읽어올수 없는것입니다

이런 관계에서 choice의 값을 가져오고싶다면

question.choice_set.all()

을 입력하면 해당 question을 foreign key로 사용하는 Choice를 가져올수있습니다

장고의 time

장고는 웹사이트를 서비스하기위한 프레임워크이며 웹사이트는 글로벌서비스가 대부분이기때문에 장고에서 현재시각을 가져올려면 timezone을 가져와야됩니다

from datetime import datetime
from django.utils import timezone
timezone.now()

datetime.datetime(2024, 4, 8, 9, 22, 11, 350319, tzinfo=datetime.timezone.utc)

현재 시각을 가져오는데 뒤쪽에보면 타임존을 같이 가져오는것을 알수있습니다

장고 shell에서 레코드 추가

 q1 = Question(question_text = "커피 vs 녹차")
 q1.question_text
 q1.pub_date

위 내용을 입력하면 q1이 다른 question처럼 정상적으로 출력되는것을 볼수있습니다

하지만 admin페이지로 접속하여 확인하면 해당 내용을 확인할수 없는데 이유는 지금 추가한 데이터가 테이블에 저장된것이 아닌 메모리 상에만 저장되어있는 상태이기 때문입니다

해당 내용을 테이블에 저장하기위해서는

q1.save()

가 필요합니다

이제 다시 admin페이지를 확인해보면 내용이 정상적으로 저장되어있는것을 볼 수 있습니다

이번에는 q1.choice_set을 이용해서 choice를 생성해봅시다

q1.choice_set.create(choice_text="커피")
q1.choice_set.create(choice_text="녹차")

admin페이지를 확인하면 이번에는 바로 커피와 녹차가 등록되는것을 확인할수 있습니다

c1 = Choice(choice_text="콜라", question=q1)
c1.save()

해당 방식으로도 Choice의 추가가 가능합니다

데이터를 추가할때 필수값을 입력하지않을시 save()에서 오류가 발생합니다
반드시 필수입력값은 입력해주도록 합시다

장고 셀에서 레코드 수정하기

 q1.question_text =  q1.question_text + "뭐가더 좋을까요"
 q1.save()

위 방식을 이용해 간단하게 수정이 가능합니다

장고 셀에서 레코드 삭제하기

choice = q1.choice_set.last()
choice.delete()

를 진행하게되면 마지막에 추가되었던 “콜라”가 삭제되게됩니다

q1.choice_set.all()

어드민 페이지 또는 위 코드를 확인하면 콜라가 지워져있는것을 확인할수 있습니다

장고 셀에서 조건 검색하기

Question.objects.get(id=1)
Question.objects.get(question_text__startswith = "커피")

get(조건=값)을 이용해서 결과에 맞는 단 하나의 데이터를 받아올수 있습니다

값이 복수로 있을경우 오류가 발생합니다

값을 몇개더 생성한뒤

Question.objects.filter(pub_date__year=2024)

filter(조건=값)을 이용하면 조건에 맞는 여러개의 값을 가져올수 있습니다

자신이 생각한대로 쿼리가 작동하고있는지 확인하고싶다면 .query를 사용하면 됩니다

print(Question.objects.filter(pub_date__year=2024).query)

filter,exclude 또는 get에서 조건으로 걸수있는 종류는 굉장히 여러가지 있기때문에 자세히 알아보고싶다면
https://docs.djangoproject.com/en/5.0/ref/models/querysets/ 에 field lookups 쪽 설명을 보면 알수있습니다

contain

Question.objects.filter(question_text__contains="커피")

question_text안에 커피가 포함된 모든값을 가져옵니다

gt

Choice.objects.filter(votes__gt=-1)

votes가 -1보다 큰값을 가진 모든 레코드를 가져옵니다

regex

Question.objects.filter(question_text__regex=r'^커피.*차')

특정 field가 정규표현식을 만족하는경우 모두 가져옵니다

여러조건 검색

Question.objects.filter(question_text__startswith="커피").filter(question_text__contains="vs")

filter를 반복해서 사용하여 여러 조건을 한번에 걸어줄 수 도 있습니다

foreign키를 사용하여 검색

Choice.objects.filter(question__question_text__contains="커피")

.query를 사용하여 해당 쿼리를 살펴보게되면

polls_choice에서 검색을 하지만 polls_question에 where을 걸어 inner join을 시켜준 결과값을 보여준다고 되어있습니다

exclude

Question.objects.exclude(question_text__startswith="커피")

question_text가 커피로 시작되지않는 결과를 가져옵니다

.query로 검색해보게되면 where절 뒤에 NOT이 붙어 해당 조건과 일치하지않는 결과들을 가져오는 조건식이 만들어져있는것을 확인할수 있습니다

모델에 메서드 추가

polls에 models 로 다시 돌아와줍니다

class Question(models.Model) :
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField(auto_now_add=True)

    def was_published_recently(self):
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

    def __str__(self):
		    if self.was_published_recently :
            return f'[NEW!!]{self.question_text}'
        return self.question_text

이제 쉘을 재 시작 해준뒤 목록을 전부 보여줍니다

Question.objects.all()

결과로나온 QuerySet을보면 생성날짜가 하루이상지나지않은(pub_date가 timezone.now() - datetime.timedelta(days=1) 이상) 결과들의 앞에 [NEW!!]가 추가되어있는것을 볼수 있습니다

모델에서 반복적으로 사용해야될 기능들은 모델에 메서드를 만들어 등록해두면 쉽게 처리해줄수 있습니다

0개의 댓글