작업환경

- Window10 WSL2(Ubuntu 20.04.3 LTS )

- Python 3.8.10

- Django 4.0.2

- Djangorestframework 3.13.1

 

이번장에서는 Django의 Rest Framework을 이용해 CRUD(Create, Retrieve, Update, Delete)를 할 수 있는 RESTful 서비스를 구현해 보겠습니다.

Rest Framework을 사용하기 위해서는 pip 를 이용해서 해당 모듈을 먼저 설치해야 합니다.

(본 강의는 http://www.django-rest-framework.org 의 튜토리얼을 기반으로 작성되었습니다. 좀 더 자세한 내용을 원하시면 해당 사이트의 API를 참조하시기 바랍니다.)

가. Rest Framework 설치

터미널(CMD) 창에서 아래 명령어를 입력합니다.

  • pip install djangorestframework

나. 프로젝트 생성 및 기본설정

1.프로젝트 및 앱 생성 터미널에서 pjt_bbs 프로젝트를 생성하고 내부에 bbs 앱을 같이 생성해 주기 위해서 아래 명령어를 순서대로 입력합니다.

$ django-admin startproject pjt_bbs
$ cd pjt_bbs
$ python3 manage.py startapp bbs

 

2.모델생성 models.py 파일을 열고 아래와 같이 모델을 정의합니다.

  • pjtbbs/bbs/models.py
from django.db import models

class Bbs(models.Model):
    created = models.DateTimeField(auto_now_add=True)
    title = models.CharField(max_length=100, blank=True, default='')
    author = models.CharField(max_length=20, blank=True, default='')
    pw = models.CharField(max_length=12, blank=True, default='')
    content = models.TextField()

    class Meta:
        ordering = ('created',)

3.앱등록 settings.py 에 생성한 앱을 등록합니다.

  • pbt_bbs/pjt_bbs/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'bbs',
]

4.admin에 모델등록
admin 에 생성한 모델을 등록해줍니다.

  • pjt_bbs/bbs/admin.py
from django.contrib import admin
from bbs.model import Bbs

class BbsAdmin(admin.ModelAdmin):
    list_display=('title','author','created',)

admin.site.register(Bbs, BbsAdmin)

5.url설정
요청 url에 대한 설정을 합니다. 먼저 프로젝트 url 파일을 수정합니다.

  • pjt_bbs/pjt_bbs/urls.py
from django.contrib import admin
from django.urls import path, include

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

그리고 bbs 앱 디렉토리에 urls.py 파일을 생성하고 설정해줍니다.

  • pjt_bbs/bbs/urls.py
from django.urls import path, re_path, include
from rest_framework.urlpatterns import format_suffix_patterns
from bbs import views

urlpatterns = [
    re_path(r'^$', views.bbs_list),
    re_path(r'^(?P<pk>[0-9]+)/$', views.bbs_detail),
]

urlpatterns = format_suffix_patterns(urlpatterns)

 

다. 개발

1.Serializer 작성
Serializer 는 데이터를 직렬화(마치 스트림데이터처럼 변경) 해줍니다. 이 직렬화를 통해서 메모리상에 있는 변수와 값의 세트를 json 데이터로 변환해서 사용할 수 있게 됩니다. serializers.py 파일을 생성하고 아래와 같이 입력해줍니다.

  • bbs_pjt/bbs/serializers.py
from rest_framework import serializers  
from bbs.models import Bbs

class BbsSerializer(serializers.ModelSerializer):
    # ModelSerializer 를 이용해서 아래와 같이 짧은 코드로 직렬화 필드를 정의할 수 있다
    class Meta:
        model = Bbs
        fields = ('id','title','author','pw','content')

    # 신규 Bbs instance를 생성해서 리턴해준다
    def create(self, validated_data):
        return Bbs.objects.create(**validated_data)

    # 생성되어 있는 Bbs instance 를 저장한 후 리턴해준다
    def update(self, instance, validated_data):
        instance.title = validated_data.get('title', instance.title)
        instance.author = validated_data.get('author', instance.author)
        instance.pw = validated_data.get('pw', instance.pw)
        instance.content = validated_data.get('content', instance.content)
        instance.save()
        return instance

2.View 작성
위에서 작성한 serializer를 이용해서 웹으로 부터 요청을 받을 View 파일을 작성합니다. url에서 bbs/ 로 끝나는 요청이 GET일경우 목록으로 처리하고, POST로 들어오면 입력으로 처리합니다. 그리고 bbs/ 다음에 숫자값이 입력되어 있을경우(예를들어 bbs/15)에 GET일 경우 한개의 데이터, PUT은 수정, DELETE 는 삭제처리를 해줍니다. views.py 파일을 열고 아래와 같이 작성해줍니다.

  • 프로젝트디렉토리/bbs/views.py
from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.response import Response
from bbs.models import Bbs  
from bbs.serializers import BbsSerializer

# 요청 url 인 bbs/ 에 대해서 urls.py 에 정의된 view.bbs_list 가 호출된다.
@api_view(['GET', 'POST'])
def bbs_list(request, format=None):  
    if request.method == 'GET':
        bbs = Bbs.objects.all()
        serializer = BbsSerializer(bbs, many=True) # many 값이 True 이면 다수의 데이터 instance를 직렬화할수 있다
        return Response(serializer.data)

    elif request.method == 'POST':
        serializer = BbsSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

# 요청 url 인 bbs/번호 에 대해서 urls.py 에 정의된 view.bbs_detail 이 호출된다
@api_view(['GET', 'PUT', 'DELETE'])
def bbs_detail(request, pk, format=None):
    try:
        bbs = Bbs.objects.get(pk=pk)
    except Bbs.DoesNotExist:
        return Response(status=status.HTTP_404_NOT_FOUND)

    if request.method == 'GET':
        serializer = BbsSerializer(bbs)
        return Response(serializer.data)

    elif request.method == 'PUT':
        serializer = BbsSerializer(bbs, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    elif request.method == 'DELETE':
        bbs.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

3.migration
이제 설정한 파일들을 실제 적용하기 위해 migration 명령어를 실행해 줍니다.

$ python3 manage.py makemigrations # bbs 하위 디렉토리에 마이그레이션 파일 생성
$ python3 manage.py migrate # 정의한 Bbs 모델로 데이터베이스 테이블 생성

 

마. restful API 테스트

1.서버실행
프로젝트 디렉토리에서 서버를 실행합니다.

  • python manage.py runserver

2.포스트맨을 통한 데이터입력 요청
우선 데이터 입력처리 확인을 위해 포스트맨을 열고 아래와 같이 입력한 후 [Send] 버튼을 클릭합니다.

주소 : http://127.0.0.1:8000/bbs/
Method : POST
Headers : JSON
Body (type=Raw) :
{
    "title":"beat it", 
    "author":"michael jacson",
    "pw":"qwer1234",
    "content":"They told him: Dont you ever come around here"
}

 

 

3. 브라우저에서 데이터 요청
위 방식으로 몇개 데이터를 더 입력한 후 브라우저를 통해 목록을 요청하면 아래와 같이 Django restframework 에서 지원하는 json 데이터 페이지가 출력됩니다. 웹 브라우저를 통해 요청하면 아래와 같이 완성된 형태의 페이지가 보여지게 되고, ajax 나 모바일 앱을 통해 요청을 하면 데이터만 받아서 사용할 수 있게 됩니다.

본 예제에서는 이미 id=1과 id=2 데이터를 삭제하여 id=3과 id=4 인 데이터가 조회되고 있습니다.

여기서 id 컬럼은 dajngo framework에서 생성한 컬럼으로 자동증가 속성을 가진 컬럼입니다.

 

포스트맨을 열고 아래와 같이 url을 입력한 후 DELETE를 선택한 후 [Send] 버튼을 클릭하면 id=1 인 데이터가 삭제됩니다. 삭제 대상 데이터가 존재하지 않는 경우, "404Not Found" 메시지가 출력됩니다.

 

포스트맨을 열고 아래와 같이 url을 입력한 후 PUT를 선택한 후 [Send] 버튼을 클릭하면 id=1 인 데이터를 업데이트합니다. 수정 대상 데이터가 존재하지 않는 경우, "404Not Found" 메시지가 출력됩니다. 본 문서에서는 id=3인 데이터로 실행했습니다.

주소 : http://127.0.0.1:8000/bbs/3/
Method : PUT
Headers : JSON
Body (type=Raw) :
{
    "title":"thriller", 
    "author":"michael jacson",
    "pw":"qwer1234",
    "content":"You hear the door slam"
}

아래와 같이 "200 OK" 성공 메시지와 함께 수정된 결과값을 보여줍니다.

브라우저에 http://127.0.0.1:8000/bbs/ 입력 후 조회하면 변경된 데이터가 출력되는 것을 확인 할 수 있습니다.

 

라. 클래스 기반 뷰처리

이번에는 코드를 조금 수정해서 기존 함수기반의 뷰 처리를 클래스 기반으로 변경해 보겠습니다. 클래스 기반으로 변경하는 이유는 rest framework 라이브러리 클래스에 CRUD에 대한 기본처리가 정의되어 있기 때문에 더 짧은 코드로 CRUD 를 완성할수 있기 때문입니다. 먼저 views.py 파일을 열고 아래와 같이 코드전체를 수정합니다.

1.views 수정

  • 프로젝트디렉토리/bbs/views.py
# 클래스 기반의 Rest CRUD 처리
from bbs.models import Bbs
from bbs.serializers import BbsSerializer
from rest_framework import generics

# generics 에 목록과 생성 API 가 정의되어 있다
class BbsList(generics.ListCreateAPIView):
    queryset = Bbs.objects.all()
    serializer_class = BbsSerializer

# generics 에 상세, 수정, 삭제 API가 정의되어 있다
class BbsDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = Bbs.objects.all()
    serializer_class = BbsSerializer

2.urls 수정

  • 프로젝트디렉토리/bbs/urls.py
from django.conf.urls import url
from rest_framework.urlpatterns import format_suffix_patterns  
from bbs import views

urlpatterns = [
    # 함수형 처리시 호출되는 함수
    # url(r'^$', views.bbs_list),
    # url(r'^(?P<pk>[0-9]+)/$', views.bbs_detail),

    # 클래스를 호출하고 해당클래스의 as_view() 함수를 호출
    url(r'^$', views.BbsList.as_view()),
    url(r'^(?P<pk>[0-9]+)/$', views.BbsDetail.as_view()),
]

urlpatterns = format_suffix_patterns(urlpatterns)

이제 브라우저에서 테스트 주소를 다시 입력해보면 이전과 동일하게 동작하는 것을 확인할 수 있습니다.

이와 같이 Django의 Rest Framework을 사용할 경우 클래스기반으로 코드를 작성하게 되면 더 짧은 코드로 빠른 시간안에 완성도 높은 결과물을 만들 수 있게됩니다.

 

참고문서 : https://javafa.gitbooks.io/python-django/content/chapter1_1.html

'장고(Django)' 카테고리의 다른 글

Django REST Framework로 REST API 만들기  (0) 2022.02.11
Python + Django 사용법  (0) 2022.02.09
장고란 무엇인가요?  (0) 2022.01.06

작업환경

- Window10 WSL2(Ubuntu 20.04.3 LTS )

- Python 3.8.10

- Django 4.0.2

- Djangorestframework 3.13.1

 

<참고>

Ubuntu 버전확인 : lsb_release -a

장고 버전확인 : django-admin version

파이썬 버전확인 : python3 -V

Djangorestframework : pip show djangorestframework

 

본 문서는 윈도우10에 설치된 WSL2에서 작업한 내용입니다.

 

이 튜토리얼에서는 DRF를 사용하여 매우 간단한 Star Wars REST API를 만드는 방법을 살펴볼 것입니다. 튜토리얼이 끝나면 다음 4개의 API 엔드포인트가 실행되고 있어야 합니다.

  • /people/(GET/POST)
  • /people/{id}/(GET/PUT)
  • /species/(GET/POST)
  • /species/{id}(GET/PUT)

REST API가 완전히 작동하려면 총 5단계가 있습니다.

  • Django 및 DRF 설치 및 설정
  • Django 모델 설정
  • DRF 직렬 변환기 설정
  • 보기 및 URL 설정
  • API 사용

Django 및 DRF 설치 및 설정

django와 djangorestframework 설치합니다.

$ pip install django
$ pip install djangorestframework

Django 프로젝트와 앱을 생성합니다.

$ django-admin startproject my_django_project
$ cd my_django_project
$ django-admin startapp my_api

$ tree
.
├── manage.py
├── my_api
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── migrations
│   │   └── __init__.py
│   ├── models.py
│   ├── tests.py
│   └── views.py
└── my_django_project
    ├── __init__.py
    ├── asgi.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

앱을 생성한 후 Framework에서 앱 구성에 대한 경로를 추가하여 앱을 등록합니다.

my_django_project/settings.py 파일에 rest_framework을  추가합니다.

INSTALLED_APPS = [
...
    'rest_framework',
    'my_api.apps.MyApiConfig'
]

runserverDjango 명령 을 사용하여 앱이 실행 중인지 확인합니다 .

$ python3 manage.py runserver
Watching for file changes with StatReloader
Performing system checks...
...
Django version 4.0.2, using settings 'my_django_project.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

브라우저로  http://127.0.0.1:8000/ 접속합니다. 아래와 같은 화면이 표시됩니다.

 

Django 모델 설정

my_api/models.py 파일에 Person 과 Species class를 추가합니다.

from django.db import models

class Species(models.Model):
   name = models.CharField(max_length=100)
   classification = models.CharField(max_length=100)
   language = models.CharField(max_length=100)

    #foreignkey 설정할 때 web에서 primary key의 name으로 보여주게됨. but db에는 id로 저장됨
    #아니면 primary key 그대로 1번 2번 이렇게 보임. 
    def __str__(self):
       return self.name
       
class Person(models.Model):
   name = models.CharField(max_length=100)
   birth_year = models.CharField(max_length=10)
   eye_color = models.CharField(max_length=10)
   species = models.ForeignKey(Species, on_delete=models.DO_NOTHING)

모델이 추가된 후 마이그레이션을 실행하여 Django가 데이터베이스에 2개의 새 테이블을 추가할 것임을 알려줍니다.

makemigrations  명령을 실행하여 migrations을 위한 my_api/migrations 디렉토리와 파일을 만듭니다.

$ python3 manage.py makemigrations
Migrations for 'my_api':
  my_api/migrations/0001_initial.py
    - Create model Species
    - Create model Person

migrate 명령을 실행하여 sqlite DB에 테이블들을 생성합니다.

$ python3 manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, my_api, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
... ...
  Applying my_api.0001_initial... OK
  Applying sessions.0001_initial... OK

DRF 직렬 변환기 설정

모델을 추가하고 테이블을 생성했으므로 이제 DRF에 모델을 직렬화합니다. 직렬 변환기는 Person 모델과 Species 모델을 API에서 사용자에게 데이터를 반환하는 데 사용할 JSON으로 변환합니다. 새 파일을 만들어 직렬 변환기를 추가합니다 my_aapi/serializers.py

from rest_framework import serializers
from my_api.models import Person, Species

class PersonSerializer(serializers.ModelSerializer):
   class Meta:
       model = Person
       fields = ('id', 'name', 'birth_year', 'eye_color', 'species')

class SpeciesSerializer(serializers.ModelSerializer):
   class Meta:
       model = Species
       fields = ('id', 'name', 'classification', 'language')

라우터 설정 및 API URL 생성

직렬 변환기가 생성된 후에는 API에 대한 view를 생성하고 Django URL에 연결합니다. 새 파일에서 생성한 각 모델에 대해 2개의 뷰 세트를 추가합니다. 뷰 세트는 여러 논리 세트를 단일 클래스로 결합해 줍니다.

my_api/views.py

from rest_framework import viewsets
from my_api.serializers import PersonSerializer, SpeciesSerializer
from my_api.models import Person, Species

class PersonViewSet(viewsets.ModelViewSet):
   queryset = Person.objects.all()
   serializer_class = PersonSerializer

class SpeciesViewSet(viewsets.ModelViewSet):
   queryset = Species.objects.all()
   serializer_class = SpeciesSerializer

뷰셋이 정의되면 이제 DRF에서 제공하는 라우터 기능을 사용하여 원하는 API 엔드포인트를 주어진 뷰셋으로 라우팅할 수 있습니다. 아래와 같이 새 파일을 만들고 라우터 구성을 추가합니다 . 

my_api/urls.py

from django.urls import include, path
from rest_framework import routers
from my_api.views import PersonViewSet, SpeciesViewSet

router = routers.DefaultRouter()
router.register(r'people', PersonViewSet)
router.register(r'species', SpeciesViewSet)

urlpatterns = [
   path('', include(router.urls)),
]

 

앱의 URL 파일을 가리 키도록 Django URL을 연결합니다.

my_django_project/urls.py

from django.urls import path, include

urlpatterns = [
   path('star-wars/', include('my_api.urls')),
]

라우터에 의해 생성된 URL에는 모든 API 메소드(GET, POST 및 PUT)가 있습니다. 라우터가 자동으로 URL을 핸들러 .get(), .list(), 및 .create()뷰셋에 매핑하기 때문입니다. API를 테스트하고 모든 것이 예상대로 작동하는지 확인합니다.

API 사용 시작

브라우저로 http://127.0.0.1:8000/star-wars/species/ 에 접속하면 API를 사용할 수 있습니다.

API를 사용하여 데이터를 데이터베이스에 추가합니다. 데이터가이 성공적으로 생성되면 서버는 아래와 같이 페이로드와 함께 201 성공 메시지로 응답합니다.

"Raw data" 탭을 사용하여 다른 데이터를 추가합니다.

 

http://127.0.0.1:8000/star-wars/people/ 접속하여 People API에 액세스할 수도 있습니다 . Person 모델에는 Species 모델에 대한 외래 키가 있으므로 Browsable API는 드롭다운을 제공합니다.

[POST] 버튼을 클릭하면 새로운 Person Dooku가 생성됩니다.

[Raw data] 탭을 사용하여 다른 사람을 추가해 보겠습니다. 그 사람에 대해 species의 id를 입력해야 합니다.

[POST] 버튼을 클릭하면 이제 데이터베이스에 새로운 Chewbacca 가 입력됩니다.

 

Chrome 브라우저에 JSONView 확장 프로그램을 설치하면 정리된 JSON을 볼 수 있습니다. 
모든 API 엔드포인트가 올바르게 작동하는지 확인합니다.

아래 내용을 브라우저에 입력한 후 접속하면 species 에 등록된 데이터를 조회할 수 있습니다.

http://127.0.0.1:8000/star-wars/species/?format=json

아래 내용을 브라우저에 입력하면 species의 id 가 1인 데이터를 조회할 수 있습니다.

http://127.0.0.1:8000/star-wars/species/1/?format=json

아래 내용을 브라우저에 입력하면 people 데이터를 조회할 수 있습니다.

http://127.0.0.1:8000/star-wars/people/?format=json

아래 내용을 브라우저에 입력하면 people의 id 가 1인 데이터를 조회할 수 있습니다.

http://127.0.0.1:8000/star-wars/people/1/?format=json

더 자세히 알아보려면 DRF 웹사이트의 문서를 확인합니다 .

React Memo를 사용한 방법에 대한 다른 GinkgoBits 튜토리얼을 확인합니다.

 

 

curl 명령어

 

* GET

아래 내용을 command line으로 실행하면 species 에 등록된 데이터를 조회할 수 있습니다.

curl -X GET http://127.0.0.1:8000/star-wars/species/?format=json

curl -X GET http://127.0.0.1:8000/star-wars/species/?format=json | jq
[
  {
    "id": 1,
    "name": "Human",
    "classification": "Mammal",
    "language": "Galactic Basic"
  },
  {
    "id": 2,
    "name": "Wookie",
    "classification": "Mammal",
    "language": "Shyniwook"
  }  
  ]

아래 내용을 command line으로 실행하면 species 에 등록된 id가 1인 데이터를 조회할 수 있습니다.

curl -X GET http://127.0.0.1:8000/star-wars/species/1/?format=json

 

아래 내용을 command line으로 실행하면 people 에 등록된 데이터를 조회할 수 있습니다.

curl -X GET http://127.0.0.1:8000/star-wars/people/?format=json

 

아래 내용을 command line으로 실행하면 people 에 등록된 id가 1인 데이터를 조회할 수 있습니다.

curl -X GET http://127.0.0.1:8000/star-wars/people/1/?format=json

 

httpie 명령어로도 수행할 수 있습니다.

아래 명령어를 수행하면  species 에 등록된 데이터를 조회할 수 있습니다.

$ http GET 127.0.0.1:8000/star-wars/species/
HTTP/1.1 200 OK
Allow: GET, POST, DELETE, HEAD, OPTIONS
... ...
X-Content-Type-Options: nosniff
X-Frame-Options: DENY

[
    {
        "classification": "Mammal",
        "id": 1,
        "language": "Galactic Basic",
        "name": "Human"
    },

 

* POST

curl POST 명령어로 데이터를 등록합니다. 아래 명령어를 수행하면 species 에 데이터를 추가합니다.

$ curl -X POST -H "Content-Type: application/json" -d '{"name":"R2","classification":"robot", "language":"droid language"}' http://127.0.0.1:8000/star-wars/species/

{"id":6,"name":"R2","classification":"robot","language":"droid language"}

httpie 명령어로도 데이터를 등록할 수 있습니다.

아래 명령어를 수행하면 species 에 데이터를 추가합니다.

http POST http://127.0.0.1:8000/star-wars/species/ name=3pio classification=robot language="droid language"

$ http POST http://127.0.0.1:8000/star-wars/species/ name=3pio classification=robot language="droid language"
HTTP/1.1 201 Created
Allow: GET, POST, DELETE, HEAD, OPTIONS
... ...
X-Frame-Options: DENY

{
    "classification": "robot",
    "id": 8,
    "language": "droid language",
    "name": "3pio"
}

 

 

 

 

 

 

'장고(Django)' 카테고리의 다른 글

Django framework (2)  (0) 2022.02.15
Python + Django 사용법  (0) 2022.02.09
장고란 무엇인가요?  (0) 2022.01.06

Python + Django 설치

수행환경

- Windows 10 WSL 2(Ubuntu 20.04 LTS)

 

1.Python 설치

WSL에 접속하여 python을 설치합니다.

sudo apt install python

설치된 python version을 확인합니다.

$ python3 --version
Python 3.6.1

 

2. Django 설치

설치 전에 장고란 무엇인가 간단히 살펴보겠습니다.

Django(/dʒæŋɡoʊ/ jang-goh/쟁고/장고)는 파이썬으로 만들어진 무료 오픈소스 웹 애플리케이션 프레임워크(web application framework)입니다. 쉽고 빠르게 웹사이트를 개발할 수 있도록 돕는 구성요소로 이루어진 웹 프레임워크입니다.

웹사이트를 구축할 때, 비슷한 유형의 요소들이 항상 필요합니다. 회원가입, 로그인, 로그아웃과 같이 사용자 인증을 다루는 방법이나 웹사이트의 관리자 패널, 폼, 파일 업로드와 같은 것들이 있습니다.

그래서 많은 사람들이 바로 사용할 수 있는 구성요소들을 갖춘 여러 프레임워크를 만들습니다. 장고도 그 중 하나입니다.

비유를 하자면, 편지(request, 요청)가 도착했는지 확인해주는 메일박스(port, 포트)가 있고 이 것은 웹서버가 해주는 일입니다. 웹 서버는 받은 편지를 읽고 웹 페이지와 함께 답장을 준니다. 그런데 무언가를 주고 싶을 때는 그 안에 내용이 있어야 하는데, 장고는 그 특정 콘텐츠를 만들 수 있는 역할을 합니다.

아래 명령어로 장고를 설치합니다.

pip install django

Django 프로젝트

이번장에서는 Django 기본 프로젝트를 생성하고, 생성한 프로젝트로 서버를 실행한 후 브라우저를 통해 접속하는 과정을 알아보겠습니다. Django는 node.js의 express 모듈처럼 간단한 명령어로 기본 프로젝트를 생성할 수 있으며 관리자 기능까지 제공합니다.

 

manage.py는 사이트 관리를 도와주는 유틸리티입니다. 

settings.py는 웹사이트 설정이 있는 파일입니다.

urls.py파일은 urlresolver가 사용하는 패턴 목록을 포함하고 있습니다.

 

가. Django 프로젝트 생성

프로젝트를 생성하기 위해 wsl에 접속하여 프로젝트를 생성할 디렉토리로 이동합니다. 본 문서에서는 /mnt/d/django 아래에 생성하겠습니다. /mnt/d/django 디렉토리에서 아래와 같이 명령어를 입력합니다.

mkdir /mnt/d/django
cd /mnt/d/django
django-admin startproject mysite

그러면 mysite라는 디렉토리가 하나 생성되고, 디렉토리 내부에는 manage.py 파일과 함께 프로젝트이름과 동일한 디렉토리가 하나 더 생성되어 있는것을 확인할 수 있습니다. 아래와 같은 디렉토리와 파일이 생성됩니다.

mysite
├───manage.py
└───mysite
        settings.py
        urls.py
        wsgi.py
        __init__.py

settings.py 파일을 열어 한국시간과 한글로 설정을 변경합니다. 기본은 UTC와 영어(en_us)로 되어 있습니다.

  • timezone 설정 : TIME_ZONE = 'Asia/Seoul'
  • 언어설정 : LANGUAGE_CODE = 'ko'  

 

Database 설정 확인 : 기본적으로 sqlite DB를 사용하는데 DB명 등을 변경할 수 있습니다.

본 문서에서는 데이터베이스를 db.sqlite3 로 사용합니다.

# Database
# https://docs.djangoproject.com/en/4.0/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}

 

 

나. 데이터베이스 생성

데이터베이스를 생성하기 위해서 콘솔 창에서 아래 코드를 실행합니다. 위에서 생성한 /mnt/d/django/mysite 디렉토리에서 

python3 manage.py migrate 명령어를 실행합니다. 데이터베이스와 함께 테이블들을 생성합니다.

/mnt/d/django/mysite$ python3 manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying auth.0012_alter_user_first_name_max_length... OK
  Applying sessions.0001_initial... OK

 

다. Django 웹서버 실행

이제 /mnt/d/django/mysite디렉토리에서 아래 명령어를 입력하여 웹서버를 실행합니다.

  • python3 manage.py runserver

 

/mnt/d/django/mysite$ python3 manage.py runserver
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).
February 09, 2022 - 21:25:47
Django version 4.0.2, using settings 'mysite.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

 

라. 브라우저로 접속 테스트

브라우저를 열고 주소창에 http://127.0.0.1:8000 을 입력합니다. 아래와 같은 화면이 보인다면 정상적으로 수행된 겁니다.

 

장고 모델

블로그를 위한 장고 모델을 만듭니다.

장고 안의 모델은 객체(object)의 특별한 종류입니다. 이 모델을 저장하면 그 내용이 데이터베이스에 저장되는 것이 특별한 점입니다. 데이터베이스란 데이터의 집합입니다. 이곳에 사용자정보나 블로그글 등이 저장되어 있습니다.

sqlite 데이터베이스는 기본 장고 데이터베이스 어댑터입니다.

데이터베이스 안의 모델이란 열(필드)와 행(데이터)로 구성되어 있습니다. 

 

어플리케이션 만들기

프로젝트 내부에 별도의 애플리케이션을 생성합니다. 애플리케이션을 만들기 위해 콘솔 창(mysite 디렉토리에서 수행)에서 아래 명령어를 실행하세요.

 

/mnt/d/django/mysite$ python3 manage.py startapp blog

이제 blog디렉터리가 생성되고 그 안에 여러 파일도 같이 들어있는 것을 알 수 있어요. 현재 디렉리와 파일들은 다음과 같을 거예요. :

    mysite
    ├── mysite
    |       __init__.py
    |       settings.py
    |       urls.py
    |       wsgi.py
    ├── manage.py
    └── blog
        ├── migrations
        |       __init__.py
        ├── __init__.py
        ├── admin.py
        ├── apps.py        
        ├── models.py
        ├── tests.py
        └── views.py

애플리케이션을 생성한 후 장고에 등록합니다. 이 역할을 하는 파일이 mysite/settings.py입니다. 이 파일 안에서 INSTALLED_APPS를 열어  'blog'를 추가합니다. 아래와 다음과 같을 거예요. :

/mnt/d/django/mysite/mysite/settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'blog',
]

블로그 글 모델 만들기

모델의 생성/변경을 적용하는 단계는 아래와 같습니다.

  1. models.py 추가 및 변경
  2. python3 manage.py makemigrations를 실행해 변경사항에 대한 마이그레이션 파일 생성
  3. python3 manage.py migrate를 실행해 변경사항을 데이터베이스에 적용

모든 Model 객체는 blog/models.py 파일에 선언하여 모델을 만듭니다. 이 파일에 블로그 글 모델도 정의합니다.

blog/models.py 파일을 열어서 안에 모든 내용을 삭제한 후 아래 코드를 추가합니다.

/mnt/d/django/mysite/blog/models.py

from django.db import models
from django.conf import settings
from django.utils import timezone


class Post(models.Model):
    author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    title = models.CharField(max_length=200)
    text = models.TextField()
    created_date = models.DateTimeField(default=timezone.now)
    published_date = models.DateTimeField(blank=True, null=True)

    def publish(self):
        self.published_date = timezone.now()
        self.save()

    def __str__(self):
        return self.title

str양 옆에 언더스코어(_) 를 두 개를 써야 합니다. 파이썬에서 자주 사용되는데, "던더(dunder; 더블-언더스코어의 준말)"라고도 합니다.

 

class Post(models.Model):는 모델을 정의하는 코드입니다. (모델은 객체입니다.)

  • class는 객체를 정의합니다.
  • Post는 모델의 이름입니다. 클래스 이름의 첫 글자는 대문자로 써야 합니다.
  • models은 Post가 장고 모델임을 의미합니다. 이 코드 때문에 장고는 Post가 데이터베이스에 저장되어야 한다고 알게 됩니다.

이제 속성을 정의합니다. title, text, created_date, published_date, author 속성을 정의하기 위해, 필드마다 어떤 종류의 데이터 타입을 가지는지를 정해야 합니다. 여기서 데이터 타입에는 텍스트, 숫자, 날짜, 사용자 같은 다른 객체 참조 등이 있습니다.

  • models.CharField - 글자 수가 제한된 텍스트를 정의할 때 사용합니다. 글 제목같이 짧은 문자열 정보를 저장할 때 사용합니다.
  • models.TextField - 글자 수에 제한이 없는 긴 텍스트를 위한 속성입니다.
  • models.DateTimeField - 날짜와 시간을 의미합니다.
  • models.ForeignKey - 다른 모델에 대한 링크를 의미합니다.

모델의 필드와 정의하는 방법에 대해서는 장고 공식 문서를 참고합니다.  https://docs.djangoproject.com/en/2.0/ref/models/fields/#field-types)

def publish(self):는 publish라는 메서드(method) 입니다. def는 이것이 함수/메서드라는 뜻이고, publish는 메서드의 이름입니다. 메서드는 무언가를 되돌려 주기도 합니다. 예로 __str__ 메서드를 보면  __str__를 호출하면 Post 모델의 제목 텍스트(string)를 return 받게 됩니다.

 

데이터베이스에 모델을 위한 테이블 만들기

데이터베이스에 Post 모델을 추가합니다. 먼저 장고 모델에 변화가 생겼다는 걸 알려줍니다.

python manage.py makemigrations blog 를 입력해 봅니다.

/mnt/d/django/mysite$ python3 manage.py makemigrations blog
Migrations for 'blog':
  blog/migrations/0001_initial.py:
  - Create model Post

장고는 데이터베이스에 반영할 수 있도록 마이그레이션 파일(migration file)이 있습니다. 이제 python manage.py migrate blog 명령을 실행해, 실제 데이터베이스에 모델 추가를 반영합니다.

/mnt/d/django/mysite$ python3 manage.py migrate blog
Operations to perform:
  Apply all migrations: blog
Running migrations:
  Applying blog.0001_initial... OK

blog 모델이 데이터베이스에 저장되었습니다. 

 

showmigration

현재 적용된 마이그레이션 파일을 보여줍니다. 

$ python3 manage.py showmigrations

admin
 [X] 0001_initial
 [X] 0002_logentry_remove_auto_add
 [X] 0003_logentry_add_action_flag_choices
auth
 [X] 0001_initial
... ...
 [X] 0012_alter_user_first_name_max_length
blog
 [X] 0001_initial
contenttypes
 [X] 0001_initial
 [X] 0002_remove_content_type_name
sessions
 [X] 0001_initial

 

sqlmigrate

생성된 migrations파일들이 어떤 sql 문장을 실행하는지 보여줍니다.

$ python3 manage.py sqlmigrate blog 0001

BEGIN;
--
-- Create model Post
--
CREATE TABLE "blog_post" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "title" varchar(200) NOT NULL, "text" text NOT NULL, "created_date" datetime NOT NULL, "published_date" datetime NULL, "author_id" integer NOT NULL REFERENCES "auth_user" ("id") DEFERRABLE INITIALLY DEFERRED);
CREATE INDEX "blog_post_author_id_dd7a8485" ON "blog_post" ("author_id");
COMMIT;

 

장고 관리자

모델링한 글들을 장고 관리자에서 추가하거나 수정, 삭제할 수 있습니다.

blog/admin.py 파일을 열어서 내용을 다음과 같이 변경합니다.

/mnt/d/django/mysite/blog/admin.py

from django.contrib import admin
from .models import Post

admin.site.register(Post)

앞에서 정의했던 Post모델을 import 합니다. 관리자 페이지에서 만든 모델을 보려면 admin.site.register(Post)로 모델을 등록해야 합니다.

웹 서버를 실행하려면 콘솔 창에서 python manage.py runserver를 실행합니다.

/mnt/d/django/mysite$ python3 manage.py runserver

Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).
February 09, 2022 - 23:05:26
Django version 4.0.2, using settings 'mysite.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

브라우저를 열고 주소창에 http://127.0.0.1:8000/admin/ 을 입력하면 아래와 같은 로그인 페이지를 볼 수 있습니다.

로그인하기 위해 모든 권한을 가지는 슈퍼 사용자(superuser)를 생성합니다. 커맨드라인으로 돌아가서 python manage.py createsuperuser 를 입력하고 엔터를 누릅니다.

메시지가 나타나면 사용자 이름 (소문자, 공백 없이), 이메일 주소 및 암호를 입력합니다. 

 

/mnt/d/django/mysite$ python3 manage.py createsuperuser
사용자 이름 (leave blank to use 'ypjeong'): admin
이메일 주소: admin@admin.com
Password:
Password (again):
Superuser created successfully.

브라우저에서 장고 관리자 페이지에서 슈퍼 사용자로 로그인한 후 대시보드를 확인합니다.

[+추가] 버튼을 클릭하여 블로그 포스트를 등록합니다. 

Author 항목의 "+" 버튼을 클릭하여 사용자를 추가합니다.

 

Title, Text, Published date 를 입력한 후 [저장] 버튼을 클릭합니다.

장고 관리자에 대해서 좀 더 알고 싶다면 장고 공식 문서를 참고합니다. https://docs.djangoproject.com/en/2.0/ref/contrib/admin/

 

 

장고 urls

 

URL이란?

URL(Uniform Resource Locators)은 웹 주소입니다. 웹 사이트를 방문할 때마다 브라우저의 주소창에 URL을 볼 수 있습니다. 127.0.0.1:8000이 바로 URL이고 https://djangogirls.org/도 URL입니다.

좀더 상세하게 예를 들어 "http://www.abcd.com:80/asd/df/sf.html" 이라는 사이트가 있다면,

  • http:// : 프로토콜
  • www.abcd.com :서버
  • asd/df : 자원의 위치
  • sf.html : 자원을 나타냅니다.

인터넷의 모든 페이지는 고유한 URL을 가지고 있습니다. 애플리케이션은 사용자가 URL을 입력하면 어떤 내용을 보여줘야 하는지 알고 있습니다. 장고는 URLconf (URL configuration)를 사용합니다. URLconf는 장고에서 URL과 일치하는 뷰를 찾기 위한 패턴들의 집합입니다.

장고 URL은 어떻게 작동할까요?

mysite/urls.py파일을 열어 보면 아래 내용이 보입니다.

/mnt/d/django/mysite/mysite/urls.py

"""mysite URL Configuration

[...]
"""
from django.contrib import admin
from django.urls import path

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

세 개의 따옴표들(""", """) 사이에 있는 줄들은 독스트링(docstring)입니다. 독스트링은 파일 제일 첫 부분, 클래스 또는 메서드 윗 부분에 작성해, 이들이 어떤 일을 수행하는지 알려줍니다. comment로 생각하면 됩니다. 파이썬은 이 부분을 실행하지 않습니다.

관리자 URL이 등록되어 있습니다.

 

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

장고는 admin/로 시작하는 모든 URL을 view와 대조해 찾아냅니다. 무수히 많은 URL이 admin URL에 포함될 수 있어 일일이 모두 쓸 수 없어 정규표현식을 사용합니다.

Django url 생성

URL을 생성합니다.  'http://127.0.0.1:8000/' 주소를 블로그 홈 페이지로 지정하고 여기에 글 목록을 보여주도록 합니다.

먼저 blog.urls를 가져오는 행을 추가합니다. blog.urls를 가져오려면 include 함수가 필요합니다. from django.urls 행을 찾아 import 뒤에 include 함수를 추가합니다.

mysite/urls.py 파일을 아래와 같이 작성합니다.

/mnt/d/django/mysite/mysite/urls.py

from django.contrib import admin
from django.urls import path, include

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

장고는 http://127.0.0.1:8000/ 로 들어오는 모든 접속 요청을 blog.urls로 전송해 추가 명령을 찾습니다.

blog.urls

blog/urls.py이라는 새 파일을 생성하고 아래 내용을 추가합니다.

/mnt/d/django/mysite/blog/urls.py

from django.urls import path
from . import views

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

장고 함수인 path와 blog 애플리케이션에서 사용할 모든 views를 가져옵니다. 그 다음, 첫 번째 URL 패턴을 추가합니다.

 

 

이제 post_list라는 view가 루트 URL에 할당되었습니다. 이 URL 패턴은 빈 문자열에 매칭이 되며, 장고 URL 확인자(resolver)는 전체 URL 경로에서 접두어(prefix)에 포함되는 도메인 이름(i.e. http://127.0.0.1:8000/)을 제외하고 받아들입니다. 이 패턴은 장고에게 누군가 웹사이트에 'http://127.0.0.1:8000/' 주소로 들어왔을 때 views.post_list를 보여주라고 말해줍니다.

마지막 부분인 name='post_list'는 URL에 이름을 붙인 것으로 뷰를 식별합니다. 뷰의 이름과 같을 수도 다를 수도 있습니다. 

http://127.0.0.1:8000/ 접속하면 '웹 페이지를 사용할 수 없음(web page not available)'이라는 메시지가 표시됩니다.

서버 콘솔 창을 보면 아래와 같은 에러가 발생한 것을 볼 수 있습니다. 

    path('', views.post_list, name='post_list'),
AttributeError: module 'blog.views' has no attribute 'post_list'

 

 no attribute 'post_list' 라는 메시지가 보이는데 이 메시지는 장고가 사용하고자 하는 뷰가 아직 없다는 메시지입니다. 

 

장고 뷰 만들기

뷰(view) 는 애플리케이션의 "로직"을 넣는 곳입니다. 뷰는 이전 장에서 만들었던 모델에서 필요한 정보를 받아와서 템플릿에 전달하는 역할을 합니다. 뷰는 파이썬 함수입니다.

뷰는 views.py 파일 안에 있습니다. views를 blog/views.py 파일 안에 아래와 같이 추가합니다.

/mnt/d/django/mysite/blog/views.py

from django.shortcuts import render

# Create your views here.
def post_list(request):
    return render(request, 'blog/post_list.html', {})

post_list라는 함수(def)를 만들었습니다. 이 함수는 요청(request)을 넘겨받아 render 메서드를 호출합니다. 이 함수는 render 메서드를 호출하여 받은 blog/post_list.html 템플릿을 보여줍니다.

파일을 저장하고, http://127.0.0.1:8000/ 로 접속해 확인해 봅니다.

TemplateDoesNotExist 에러가 발생하는 것을 확인할 수 있습니다. 장고 템플릿 양식은 HTML을 사용하는데 템플릿 파일이 존재하지 않아 발생하는 오류입니다. 

장고 URL 설정에 대해 더 알고 싶다면 장고 공식 문서를 읽어보세요. : https://docs.djangoproject.com/en/2.0/topics/http/urls/

 

템플릿 생성

템플릿은 blog/templates/blog 디렉토리에 저장됩니다. blog디렉터리 안에 하위 디렉터리인 templates을 생성하고 template 디렉토리 하위에 blog 디렉토리를 생성합니다.

blog
  └───templates
         └───blog

(왜 똑같은 blog디렉토리를 하나 더 만들어야하는지는 나중에 폴더 구조가 복잡해 질 때 좀더 쉽게 찾기 위해 사용하는 관습적인 방법입니다)

blog/templates/blog디렉토리 안에 post_list.html 이라는 새 파일을 만듭니다.

웹 서버를 다시 시작한 후 웹 사이트를 확인해 봅니다. 오류 메시지없이 빈 화면이 표시됩니다.

커맨드라인에서 Ctrl + C를 눌러 웹 서버를 중단한 후 python manage.py runserver명령을 실행해 서버를 재시작합니다.

 

post_list.html템플릿 파일에 아래 내용을 입력합니다.

blog/templates/blog/post_list.html

<html>
    <head>
        <title>Django mysite blog</title>
    </head>
    <body>
        <div>
            <h1><a href="">Django mysite Blog</a></h1>
        </div>

        <div>
            <p>published: 14.06.2014, 12:14</p>
            <h2><a href="">My first post</a></h2>
            <p>Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.</p>
        </div>

        <div>
            <p>published: 14.06.2014, 12:14</p>
            <h2><a href="">My second post</a></h2>
            <p>Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut f.</p>
        </div>
    </body>
</html>

이제 웹 사이트가 아래와 같이 보여집니다. http://127.0.0.1:8000/

 

장고 ORM과 쿼리셋(QuerySets)

장고를 데이터베이스에 연결, 데이터를 저장하는 방법에 대해서 알아봅니다.

ORM이란

Object-Relational Mapping의 약자로 객체(Object)와 관계형 데이터베이스(Relational Database)의 데이터를 매핑(Mapping)해주는 것을 의미합니다. 객체 간의 관계를 바탕으로 SQL을 자동 생성하여 sql쿼리문 없이도 데이터베이스의 데이터를 다룰 수 있게 해줍니다.
데이터베이스의 테이블을 객체지향 프로그래밍에서 사용하는 객체(Class)처럼 사용할 수 있도록 해주는 기술입니다.

 

<예시>

book 이라는 객체에서 저자의 이름이 kim 인 책 목록을 가져오고 싶을 때,

SQL 쿼리문을 사용할 경우, sql 쿼리문을 작성하고 데이터를 가져오는 일련의 과정들을 코드에 적어야 합니다.

book_list = new list();
sql = "SELECT book FROM library WHERE author = 'kim'";
data = query(sql);
while (row = data.next()){
    book = new Book();
    book.setAuthor(row.get('author'));
    book_list.add(book);
}

ORM을 사용할 경우, 간단하게 한 줄로 원하는 객체를 가져올 수 있습니다.

book_list = BookTable.query(author="kim")

 

 

쿼리셋이란 ?

쿼리셋(QuerySet)은 전달받은 모델의 객체 목록입니다(Django ORM에서 발생한 자료형). 쿼리셋은 데이터베이스로부터 데이터를 읽고, 필터를 걸거나 정렬을 할 수 있습니다. 리스트와 구조는 같지만 파이썬 기본 자료구조가 아니기 때문에 파이썬에서 읽고 쓰기 위해 자료형 변환(Casting)을 해줘야 합니다.


 

장고 쉘(shell)

로컬 콘솔에서 아래 명령을 입력합니다.

 

/mnt/d/django/mysite$ python3 manage.py shell

Python 3.8.10 (default, Nov 26 2021, 20:14:08)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>>

장고 인터랙티브 콘솔(interactive console)로 들어왔습니다. 파이썬 프롬프트와 비슷하지만, 장고의 명령어를 수행할 수 있습니다. 물론 파이썬의 모든 명령어를 여기서 사용할 수 있습니다.

모든 객체 조회하기

아래 명령어로 입력했던 글들을 출력합니다.

 

>>> from blog.models import Post
>>> Post.objects.all()
<QuerySet [<Post: 첫번째 블로그입니다.>]>

장고 관리자 인터페이스로 생성했던 글 목록이 출력됩니다.

객체 생성하기

데이터베이스에 새 글 객체를 저장하는 방법에 대해 알아봅시다. 먼저 User 모델과 Post 모델을 import 합니다.

사용자이름(username)이 '홍길동'인 User 인스턴스를 가져옵니다.

 

>>> from blog.models import Post
>>> from django.contrib.auth.models import User
>>> auth = User.objects.get(username='홍길동')
>>> Post.objects.create(author=auth, title='second title', text='두번째 블로그입니다.')
<Post: second title>

다시 입력했던 모든 글들을 출력해 봅니다.

 

>>> Post.objects.all()
<QuerySet [<Post: 첫번째 블로그입니다.>, <Post: second title>]>

 

글 더 추가하기

몇 개 글을 더 추가해서 잘 작동하는지 확인합니다.

필터링하기

쿼리셋의 중요한 기능은 데이터를 필터링입니다. 예를 들어, '홍길동'이라는 사용자가 작성한 모든 글을 찾고 싶다고 가정합니다. 이런 경우 Post.objects.all()에서 all대신, filter를 사용합니다. 쿼리셋 안에 있는 괄호 안에 원하는 조건을 넣어줍니다. 

작성자(author)가 auth 인 조건을 입력합니다.  

 

>>> Post.objects.filter(author=auth)
<QuerySet [<Post: 첫번째 블로그입니다.>, <Post: second title>]>

모든 글들 중, 제목(title)에 '블로그'이라는 글자가 들어간 글들만을 뽑아냅니다.

 

>>> Post.objects.filter(title__contains='블로그')
<QuerySet [<Post: 첫번째 블로그입니다.>]>

title와 contains 사이에 있는 밑줄(_)이 2개(__)입니다. 장고 ORM은 필드 이름("title")과 연산자 필터("contains")를 밑줄 2개를 사용해 구분합니다. 밑줄 1개만 입력한다면, FieldError: Cannot resolve keyword title_contains라는 오류가 발생합니다.

 

게시글 목록을 볼 수 있어요. 게시일(published_date)로 과거에 작성한 글을 필터링하면 목록을 불러올 수 있어요.

command-line

>>> from django.utils import timezone
>>> Post.objects.filter(published_date__lte=timezone.now())
<QuerySet [<Post: 첫번째 블로그입니다.>]>

 

정렬하기

퀘리셋은 객체 목록을 정렬할 수 있습니다. 이제 created_date필드를 정렬해 봅니다.

 

>>> Post.objects.order_by('created_date')
<QuerySet [<Post: 첫번째 블로그입니다.>, <Post: second title>]>

-을 맨 앞에 붙여주면 내림차순으로 정렬합니다.

 

>>> Post.objects.order_by('-created_date')
<QuerySet [<Post: second title>, <Post: 첫번째 블로그입니다.>]>

쿼리셋 연결하기

쿼리셋들을 함께 연결(chaining)할 수 있습니다.

>>> Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')

이 방법은 복잡한 쿼리도 작성할 수 있게 해줍니다.

다음 명령어로 장고 쉘을 종료합니다.

>>> exit()
$

 

템플릿 동적 데이터

블로그 글은 각각 다른 장소에 나눠져 있습니다. Post모델은 models.py파일에, post_list모델은 views.py파일에 있습니다.

템플릿 동적 데이터에서는 콘텐츠(데이터베이스 안에 저장되어 있는 모델)를 가져와 템플릿에 넣는것을 수행해 봅니다.

뷰(view)는 모델과 템플릿을 연결하는 역할을 합니다. post_list를 뷰에서 보여주고 이를 템플릿에 전달하기 위해서는, 모델을 가져와야 합니다. 뷰가 템플릿에서 모델을 선택하도록 만들어야 합니다.

blog/views.py파일을 열어봅니다.

/mnt/d/django/mysite/blog/views.py

from django.shortcuts import render

def post_list(request):
    return render(request, 'blog/post_list.html', {})

models.py 파일에 정의된 모델을 가져기 위해 from .models import Post을 추가합니다.

 

 

from 다음에 있는 마침표(.)는 현재 디렉토리 또는 애플리케이션을 의미합니다. 동일한 디렉터리 내 views.py, models.py파일이 있기 때문에 . 파일명 (.py확장자를 붙이지 않아도)으로 내용을 가져올 수 있습니다.

Post모델에서 블로그 글을 가져오기 위해서는 쿼리셋(QuerySet)을 추가하고, 글 목록을 게시일 published_date기준으로 정렬하기 위해 from django.utils import timezone 을 추가합니다.

 

from django.shortcuts import render
from django.utils import timezone
from .models import Post

def post_list(request):
    posts = Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
    return render(request, 'blog/post_list.html', {})

render함수에는 매개변수 request(사용자가 요청하는 모든 것)와 'blog/post_list.html' 템플릿이 있습니다. {} 이곳에 템플릿을 사용하기 위해 매개변수를 추가합니다. 이 매개변수를 'posts' 라고 정의합니다. {'posts': posts} 이렇게 작성합니다. 

: 이전에 문자열이 와야하고, 작은 따옴표''를 양쪽에 붙입니다.

이제 blog/views.py코드는 아래 코드처럼 작성되어야 합니다.

from django.shortcuts import render
from django.utils import timezone
from .models import Post

def post_list(request):
    posts = Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
    return render(request, 'blog/post_list.html', {'posts': posts})

템플릿 파일로 돌아가 쿼리셋을 보이게 만들어 봅시다.

쿼리셋에 대해 더 알고 싶다면 장고 공식 문서를 읽어보세요. : https://docs.djangoproject.com/en/2.0/ref/models/querysets/

 

장고 템플릿

데이터를 보여주기 위해 장고는 내장된 템플릿 태그(template tags) 라는 기능을 제공합니다.

템플릿 태그는 무엇인가요?

브라우져는 파이썬 코드를 이해할 수 없기 때문에 HTML에 파이썬 코드를 바로 넣을 수 없습니다. HTML는 정적이지만, 파이썬은 동적입니다.

템플릿 태그는 파이썬을 HTML로 바꿔주어 동적인 웹 사이트를 만들 수 있게 합니다.

post 목록 템플릿 보여주기

위 글에서 블로그 목록이 들어있는 posts 변수를 템플릿에 넘겨주었습니다. 이제 넘겨진 posts변수를 받아 HTML에 나타나도록 해봅니다.

장고 템플릿 안에 있는 값을 출력하려면, 변수 이름 안에 {{ posts }} 처럼 중괄호를 넣어 표시합니다.

 

여러 목록을 보여주기 위해 for loop을 이용합니다. 장고 템플릿에서는 아래와 같이 기술합니다.

blog/templates/blog/post_list.html

{% for post in posts %}
    {{ post }}
{% endfor %}

 

HTML과 템플릿 태그를 함께 사용하여 아래와 같이 post_list.html 파일을 수정합니다.

/mnt/d/django/mysite/blog/templates/blog/post_list.html

<html>
    <head>
        <title>Django mysite blog</title>
    </head>
    <body>
        <div>
            <h1><a href="">Django mysite Blog</a></h1>
        </div>

{% for post in posts %}
    <div>
        <p>published: {{ post.published_date }}</p>
        <h1><a href="">{{ post.title }}</a></h1>
        <p>{{ p.text|linebreaksbr }}</p>
    </div>
{% endfor %}

    </body>
</html>

{% for %} 와 {% endfor %}사이에 넣은 모든 것은 목록의 모든 객체를 반복하게 됩니다. 페이지를 새로고침하면 아래 화면이 브라우저에 보여집니다.

{{ post.title }}라던가 {{ post.text }}같이 Post모델에서 정의한 각 필드의 데이터에 접근하기 위해 이 표기법을 사용합니다. 또한 |linebreaksbr같이 파이프 문자(|)도 사용해요. 이건 블로그 글 텍스트에서 행이 바뀌면 문단으로 변환하도록 하라는 의미입니다. 행바뀜을 문단으로 변환하는 필터를 적용한다는 표현을 쓰기도 합니다.

 

 

 

'장고(Django)' 카테고리의 다른 글

Django framework (2)  (0) 2022.02.15
Django REST Framework로 REST API 만들기  (0) 2022.02.11
장고란 무엇인가요?  (0) 2022.01.06

Django(/dʒæŋɡoʊ/ jang-goh/쟁고/장고)는 파이썬으로 만들어진 무료 오픈소스 웹 애플리케이션 프레임워크(web application framework)입니다. 쉽고 빠르게 웹사이트를 개발할 수 있도록 돕는 구성요소로 이루어진 웹 프레임워크입니다.

 

 

웹사이트를 구축할 때, 비슷한 유형의 요소들이 항상 필요합니다. 회원가입, 로그인, 로그아웃과 같이 사용자 인증을 다루는 방법이나 웹사이트의 관리자 패널, 폼, 파일 업로드와 같은 것들 말이지요.

그런데 정말 다행이게도, 오래전에 어떤 웹 개발자들이 새로운 웹 사이트를 개발할 때 서로 비슷한 문제들에 직면한다는 것을 깨달았습니다. 그래서 팀을 조직했고요. 바로 사용할 수 있는 구성요소들을 갖춘 여러 프레임워크를 만들었답니다.

Python 웹프레임워크에는 Django, Flask, FastAPI, Sanic 등이 있습니다.

장고도 그중에 하나인 거죠. 새로운 웹사이트를 개발할 때 뒤따르는 간접비용의 부담을 덜어준답니다.

왜 프레임워크가 필요한가요?

장고라는 것이 실제로 무엇을 위한 것인지 이해하기 위해서는 서버에 대해서 자세히 살펴볼 필요가 있어요. 먼저 서버가 여러분에게 웹 페이지를 제공하길 원하는지 알아야 해요.

편지(request, 요청)가 도착했는지 확인해주는 메일박스(port, 포트)가 있다고 상상해보세요. 이 것은 웹 서버가 해주는 일이에요. 웹 서버는 받은 편지를 읽고 웹 페이지와 함께 답장을 준답니다. 그런데 무언가를 주고 싶을 때는 그 안에 내용이 있어야 하죠. 장고는 그 특정 콘텐츠를 만들 수 있는 역할을 합니다.

누군가가 서버에 웹 사이트를 요청하면 어떤 일이 벌어질까요?

웹 서버에 요청이 오면 장고로 전달됩니다. 장고 urlresolver는 웹 페이지의 주소를 가져와 무엇을 할지 확인합니다.(urlresolver는 웹 사이트 주소인 URL(Uniform Resource Locator)을 통해 이해합니다). 패턴 목록을 가져와 URL과 맞는지 처음부터 하나씩 대조해 식별합니다. 만약 일치하는 패턴이있으면, 장고는 해당 요청을 관련된 함수(view)에 넘겨줍니다

집배원을 생각해보세요. 집배원은 거리를 걸으며 집집이 편지와 대조해서 주소와 번지를 확인합니다. 주소와 번지가 일치하면 그곳에 편지를 배달합니다. urlresolver가 바로 집배원과 같은 역할을 합니다.

모든 일들은 view 함수에서 처리됩니다: 특정 정보를 데이터베이스에서 찾을 수 있습니다. 그런데 만약 사용자가 데이터를 바꿔달라고 수정을 요청한다면 어떻게 될까요? "제 직업에 대한 설명을 바꿔주세요."와 같은 편지를 받았다고 생각해봅시다. view함수는 수정할 수 있는 권한이 있는지 확인하고 나서, 직업에 대한 설명을 수정해 다시 답장을 주겠지요. "완료했습니다!" 라고요. 그러고 나서 view는 답장을 생성하여, 장고는 그 답장을 그 사용자의 웹 브라우저에 보내주는 역할을 합니다.

 

Django의 동작 원리 및 구조

 

Django의 구조 

  • Model (데이터 관리)
  • Template(사용자가 보면 화면, UI)
  • View(중간 관리자)

 

MTV Pattern 

웹 프로그램 개발 시 일반적으로 언급되는 MVC(Model-View-Controller)패턴은 데이터, 사용자 인터페이스, 데이터를 처리하는 로직을 구분해서 한 요소가 다른 요소들에 영향을 주지 않도록 설계하는 방식이다. 이런 방식으로 개발을 진행하면 UI 디자이너와 개발자는 독립적인 영역에서 개발이 가능하게 된다. 

Django 프레임 워크에서는 Model=ModelView=Template, Controller=View,  라고 표현하며 MVC를 MTV라고 한다.

앞서 말한 것 처럼 Model은 데이터 베이스에 저장되는 데이터의 영역, Template은 사용자에게 보여지는 영역, View는 실질적으로 프로그램 로직이 동작하여 적절한 처리 결과를 Template에게 전달하는 역할을 수행 한다. 

 

 

Django의 동작 원리

동작 원리

  • 클라이언트로 부터 요청(Request)를 받으면 URLconf 모듈을 이용하여 URL을 분석한다.
  • URL 분석 결과를 통해 해당 URL에 매칭되는 View를 실행한다.
  • View는 자신의 로직을 실행하고, 데이터베이스 처리가 필요하면 Model을 통해 처리하고 그결과를 반환 받는다.
  • View는 자신의 로직 처리가 끝나면 Template을 사용하여 클라이언트에 전송할 HTML 파일을 생성한다.
  • View는 최종 결과로 HTML 파일을 클라이언트에게 보내 응답(Response)한다.

Django는 MTV Pattern으로 구조화 되어 있습니다.

'장고(Django)' 카테고리의 다른 글

Django framework (2)  (0) 2022.02.15
Django REST Framework로 REST API 만들기  (0) 2022.02.11
Python + Django 사용법  (0) 2022.02.09

+ Recent posts