웹 페이지를 위해 장고(django)의 뷰(View)를 사용하는 방법에 대해서 알아보겠습니다.


1. 개요

지금까지 데이터를 저장할 데이터베이스와의 연동과 데이터를 생성(Create)하고 읽고(Read) 갱신(Update)하고 삭제(Delete) CRUD 그리고 사용자가 접속할 URL을 생성하는 방법 등 장고(django)로 웹 서비스를 하기 위한 많은 작업을 진행하였습니다.

 

이번 블로그에서는 사용자에게 보여줄 웹 페이지를 만들기 위해

장고(django)의 뷰(View)를 사용하는 방법에 대해서 알아보겠습니다.

이 블로그는 시리즈로 작성되어 있으며, 아래에 링크를 통해 시리즈의 다른 글을 확인할 수 있습니다.

또한 이 블로그 시리즈에서 다룬 소스는 github에 공개되어 있습니다. 아래에 링크를 통해 확인 가능합니다.


2. URL 확인

이전 블로그(장고(django)의 라우팅(Routing))에서 우리는 사용자가 접속할 URL과 정적 HTML을 연결하는 방법에 대해서 알아보았습니다. 아래에 장고(django) 명령어를 실행하여 테스트 서버를 시작한 후, http://127.0.0.1:8000/에 접속하면 Hello World가 표시되는 웹 페이지를 확인할 수 있습니다.

# source venv/bin/activate
# cd django_exercise/
python manage.py runserver

3. 데이터 전달

이제 이전 블로그(장고(django)의 ORM)에서 생성한 데이터를 웹 페이지에서 보기 위해 뷰(View)에 데이터를 전달해 보도록 하겠습니다. blog/views.py를 열고 아래와 같이 수정합니다.

from django.shortcuts import render
from .models import Post

def posts(request):
    posts = Post.objects.filter(published_at__isnull=False).order_by('-published_at')
    return render(request, 'blog/posts.html', {'posts': posts})
  • from .models import Post: 우리가 만든 Post 모델(Models)을 불러옵니다.
  • posts = Post.objects.filter(published_at__isnull=False).order_by('-published_at')
    • published_at__isnull=False: published_at 필드가 null이 아닌 경우(__isnull=False)에 데이터를 가져옵니다
    • order_by('-published_at'): 데이터를 published_at 필드로 내림차순 정렬합니다.
  • return render(request, 'blog/posts.html', {'posts': posts}): 가져온 데이터를 blog/posts.html 페이지에 {'posts': posts} posts란 변수명으로 전달합니다.

4. 데이터 표시

이제 위에서 전달한 데이터를 화면에 표시해 봅시다. 

blog/templates/blog/posts.html 파일을 열고 아래와 같이 수정합니다.

<html>
  <head><title>Hello World</title></head>
  <body>
    {% for post in posts %}
    <div>
      <h1>
        {{ post.title }}<small>(published: {{ post.published_at }})</small>
      </h1>
      <p>{{ post.content | linebreaksbr }}</p>
    </div>
    {% endfor %}
  </body>
</html>

  • {% for post in posts %}...{% endfor %}: 위에서 blog/views.py에서 전달한 posts 데이터 리스트에서 post로 데이터를 하나씩 가져와 반복문을 돌립니다.
  • {{ post.title }}<small>(published: {{ post.published_at }})</small>: post 데이터의 title / published_at 필드값을 표시합니다.
  • <p>{{ post.content | linebreaksbr }}</p>: 우리가 가지고 있는 post 데이터의 content를 가져와 줄바꿈(\n)을 줄바꿈 태그(<br/>)로 변환하여 표시합니다.

위와 같이 코드를 수정하고 http://127.0.0.1:8000/에 접속하면

아래와 같이 데이터가 표시되는 것을 확인할 수 있습니다.

 

조금 더 연습을 하기 위해 상세 페이지를 제작해 봅시다.

위에서 만든 blog/templates/blog/posts.html 파일을 아래와 같이 수정합니다.

<html>
  <head><title>Hello World</title></head>
  <body>
    {% for post in posts %}
    <a href="{% url 'post_detail' id=post.id %}"> <!-- <<<<<<<<<<<<<<<<<<<<< here -->
      <h1>
        {{ post.title }}<small>(published: {{ post.published_at }})</small>
      </h1>
      <p>{{ post.content | linebreaksbr }}</p>
    </a> <!-- <<<<<<<<<<<<<<<<<<<<< here -->
    {% endfor %}
  </body>
</html>

  • {% url 'post_detail' id=post.id %}: 우리가 정의한 django_exercise/urls.py 와 blog/urls.py에서 post_detail이라는 이름(name)을 찾고 해당 URL로 변경해 줍니다. 이때 id라는 파라메터를 만들고 Post의 id를 넣어줍니다.

아직은 post_detail과 매칭되는 URL을 만들지 않았습니다.

이제 post_detail과 대응하는 URL과 뷰(View)를 제작해 봅시다. 

blog/templates/blog/post_detail.html을 생성하고 아래와 같이 수정합니다.

<html>
  <head><title>Hello World</title></head>
  <body>
    <a href="{% url 'posts' %}">
      Post List
    </a>
    <h1>
      {{ post.title }}
    </h1>
    <p>created: {{ post.created_at }}</p>
    <p>updated: {{ post.updated_at }}</p>
    <p>published: {{ post.published_at }}</p>
    <p>author: {{ post.author.username }}</p>
    <p>{{ post.content | linebreaksbr }}</p>
  </body>
</html>

  • {% url 'posts' %}: URL 파일에서 posts라는 이름(name)을 갖는 URL을 찾고 그 URL로 대체합니다.
  • author: {{ post.author.username }}: 우리는 우리가 만든 Post 모델과 장고(django)에서 기본적으로 제공하는 auth.User과 연결하여 작성자(author) 필드를 만들었습니다. 이렇게 연결한 모델(Models)에서 username을 가져와 표시하였습니다.

이제 화면에 표시할 페이지는 준비되었습니다. 

blog/urls.py를 열고 아래와 같이 수정합니다.

from django.urls import path
from . import views

urlpatterns = [
    path('', views.posts, name='posts'),
    path('post/<int:id>/', views.post_detail, name='post_detail'), # <<<<<<<<<<<< here
]
  • post/<int:id>/: URL에 파라메터로 넘어온 숫자형 데이터 id를 표시합니다.
  • name='post_detail': URL의 이름은 post_detail이며 views.post_detail와 매핑되어있습니다.

이로써 {% url 'post_detail' id=post.id %}을 사용하여

post/<int:id>/ URL을 표시하고 views.post_detail과 매핑 시킬 준비가 되었습니다.

이제 blog/views.py 파일을 열고 아래와 같이 수정합니다.

from django.shortcuts import render, get_object_or_404 # <<<<<<<<<<<< here
from .models import Post


def posts(request):
    posts = Post.objects.filter(
        published_at__isnull=False).order_by('-published_at')
    return render(request, 'blog/posts.html', {'posts': posts})

# <<<<<<<<<<<< here
def post_detail(request, id):
    post = get_object_or_404(Post, id=id)
    return render(request, 'blog/post_detail.html', {'post': post})
  • get_object_or_404: 장고에서 기본적으로 제공하는 함수를 추가하였습니다. 이 함수는 해당 객체(Object)에서 데이터를 가져오는데 데이터가 없으면 404 에러를 발생시키는 함수입니다.
  • def post_detail(request, id):: 새롭게 추가한 URL과 매핑되는 함수입니다. 파라메터로 넘겨준 id를 별도의 변수로 전달받을 수 있습니다.

이것으로 상세 페이지를 제작해 보았습니다. 

http://127.0.0.1:8000으로 접속하면 이전과는 다르게 아래와 같이 링크가 걸린 페이지를 볼 수 있습니다.

해당 링크를 누르면 상세페이지 URL(http://127.0.0.1:8000/post/2/)로 이동하며 아래와 같이 Post의 상세 페이지를 확인할 수 있습니다.


5. 템플릿 파일

이제 뷰(View)와 URL, 그리고 데이터를 표시하는 방법은 어느정도 익숙해진거 같습니다.

하지만 HTML 파일에 중복되는 코드가 많습니다. 아직 css, js나 meta 태그를 넣지 않았지만,

이런 태그들이 많아지면 점점 중복되는 코드들이 많아지기 시작합니다.

이런 중복되는 부분을 새로운 파일로 만들고 가져오는 방법에 대해서 알아보도록 하겠습니다.

 

일단 정적 파일(css, js 등)을 추가하는 방법에 대해서 알아보겠습니다.

blog/static/css/main.css 파일을 생성하고 아래와 같이 수정합니다.

h1 {
  color: red;
}

 

 

여기에서는 디자인에 관해서는 다루지 않겠습니다.

더 이쁘게 꾸미고 싶으신 분들은 이 파일을 수정하시기 바랍니다.

장고(django)는 static이라는 이름의 폴더를 자동으로 찾아 등록하기 때문에 추가적인 등록 과정은 필요하지 않습니다.

이제 blog/templates/blog/layout.html 파일을 생성하고 아래와 같이 수정합니다.

{% load static %}
<html>
  <head>
    <title>Hello World</title>
    <link rel="stylesheet" href="{% static 'css/main.css' %}" />
  </head>
  <body>
    {% block content %} {% endblock %}
  </body>
</html>

  • {% load static %}: 이 파일에서 static 폴더를 사용할 수 있도록 static 폴더를 불러옵니다.
  • <link rel="stylesheet" href="{% static 'css/main.css' %}" />: 우리가 불러온 static 폴더에서 css/main.css를 찾아 URL로 변경합니다.
  • {% block content %} {% endblock %}: 이 레이아웃(layout) 파일에 필요한 데이터(content)를 표시할 위치를 설정합니다. 이렇게 표시하고 싶은 부분을 block [name]으로 설정하고 해당 블록(block)을 대체할 부분을 [name]을 사용하여 대체합니다.

이제 레이아웃(layout) 파일을 활용하기 위해 blog/templates/blog/posts.html 파일을 열고 아래와 같이 수정합니다.

{% extends 'blog/layout.html' %}

{% block content %}
  {% for post in posts %}
    <a href="{% url 'post_detail' id=post.id %}">
      <h1>
        {{ post.title }}<small>(published: {{ post.published_at }})</small>
      </h1>
      <p>{{ post.content | linebreaksbr }}</p>
    </a>
  {% endfor %}
{% endblock %}

  • {% extends 'blog/layout.html' %}: 이 파일(posts.html)은 우리가 만든 레이아웃(layout.html) 파일을 활용합니다.
  • {% block content %}...{% endblock %}: 우리가 레이아웃(layout.html) 파일에 만든 블록(block), 그중에 이름이 content인 블록(block)을 여기에 작성한 내용으로 대체합니다.

그리고 blog/templates/blog/post_detail.html 파일을 열고 아래와 같이 수정합니다.

{% extends 'blog/layout.html' %}

{% block content %}
  <a href="{% url 'posts' %}">
    Post List
  </a>
  <h1>
    {{ post.title }}
  </h1>
  <p>created: {{ post.created_at }}</p>
  <p>updated: {{ post.updated_at }}</p>
  <p>published: {{ post.published_at }}</p>
  <p>author: {{ post.author.username }}</p>
  <p>{{ post.content | linebreaksbr }}</p>
{% endblock %}

위에서 설명한 내용과 동일하게 레이아웃(layout.html) 파일을 활용하고 이름이 content인 블록(block)을 여기에 작성한 내용으로 대체합니다.


6. 확인

실제 작업한 내용을 확인하기 위해 http://127.0.0.1:8000/에 접속해 봅니다.

그러면 우리가 작성한 css가 적용된 화면을 아래와 같이 볼 수 있습니다.

(화면이 제대로 표시되지 않는 다면 테스트 서버를 재실행 해 보세요.)

링크를 눌러 상세 페이지(http://127.0.0.1:8000/post/2/)에 이동해도

아래와 같이 css가 적용된 것을 확인할 수 있습니다.

이것으로 우리는 장고(django)의 템플릿을 활용하여 정적 파일(css, js 등)을 가져오는 방법과 HTML의 중복 줄이기 위한 방법에 대해서 알아보았습니다.


7. 완료

이번 블로그에서는 장고(django)의 뷰(View)를 활용하는 전박적인 방법에 대해서 살펴보았습니다.

데이터를 가져와 화면에 출력하고, 출력하는 화면을 잘 관리하기 위한 장고(django)의 템플릿도 확인해 보았습니다.

또한 css와 js같은 정적 파일(static)을 가져오는 방법에 대해서도 알아 보았습니다.

이제 우리는 이것들을 활용하여 일반적인 웹 서비스 사이트를 제작할 수 있게 되었습니다!

장고(django)의 ORM(Object-Relational Mapping)을 사용하여 데이터를 생성하고 읽고 갱신하고 삭제하는 방법(CRUD - Create Read Update Delete)에 대해서 알아봅시다.


1. 개요

장고(django)의 ORM(Object-Relational Mapping)을 사용하여 데이터베이스에 데이터를 생성(Create)하고, 읽고(Read), 갱신(Update)하고, 삭제(Delete)하는 방법(CRUD - Create Read Update Delete)에 대해서 알아봅니다.

이 블로그는 시리즈로 작성되어 있으며, 아래에 링크를 통해 시리즈의 다른 글을 확인할 수 있습니다.

또한 이 블로그 시리즈에서 다룬 소스는 github에 공개되어 있습니다. 아래에 링크를 통해 확인 가능합니다.


2. ORM이란?

ORM(Object-Relation Mapping)란, 객체(Object)와 관계형 데이터베이스(Relational)을 연결(Mapping)해 주는 것을 의미한다. 간단하게 설명하면 데이터베이스의 테이블을 객체(Object)와 연결하여 테이블에 CRUD를 할 때, SQL 쿼리를 사용하지 않고도, 가능하게 하는 것을 말합니다.

 

우리는 이전 블로그(장고(django) 모델(models) 사용해보기)를 통해 이미 장고(django)의 ORM(Object-Relational Mapping)을 사용하기 위한 준비를 하였습니다. 이전 블로그에서 생성한 Post 모델(Models)은 데이터베이스의 blog_post 테이블과 연결(Mapping)되어 있습니다. 우리는 이 모델(Models)을 사용하여 데이터베이스에 CRUD을 함으로써 장고(django)의 ORM(Object-Relational Mapping)을 이해해 보도록 하겠습니다.

아래에 장고(django) 명령어를 통해 장고(django)가 기본적으로 제공하는 쉘(Shell)을 실행 시킵니다.

# source venv/bin/activate
# cd django_exercise
python manage.py shell

 

아래에 코드로 우리가 이전 블로그에서 만든 Post 모델(Models)을 가져옵니다.

>>> from blog.models import Post

 

 

(1) 데이터 조회(Read)

아래에 코드로 Post의 내용을 조회(Read)합니다.

Post.objects.all()

 

정상적으로 실행되었다면 아래와 같은 결과를 볼 수 있습니다.

>>> Post.objects.all()
<QuerySet [<Post: this is a test1 title>, <Post: this is a test2 title>]>

 

나중에 사용하기 위해, 아래에 코드로 사용자(User) 모델(Models)을 가져오고, 데이터를 조회(Read)하여 변수에 저장합니다.

>>> from django.contrib.auth.models import User
>>> admin = User.objects.get(username='dev-yakuza')

 

(2) 데이터 생성(Create)

아래에 코드를 실행하여 Post의 새로운 데이터를 생성(Create)해 봅니다.

Post.objects.create(author=admin, title='This is a test title from django shell', content='This is a test title from django shell. This is a test title from django shell.')

 

정상적으로 실행되었다면 아래와 같은 결과를 볼 수 있습니다.

>>> Post.objects.create(author=admin, title='This is a test title from django shell', content='This is a test title from django shell. This is a test title from django shell.')
<Post: This is a test title from django shell>

 

(3) 데이터 생성 확인

다시 한번 Post 모델(Models)을 조회하면 아래와 같이 데이터가 잘 추가된 것을 확인 할 수 있습니다.

>>> Post.objects.all()
<QuerySet [<Post: this is a test1 title>, <Post: this is a test2 title>, <Post: This is a test title from django shell>]>

 

새로운 터미널에서 아래에 장고(django) 명령어로 테스트 서버를 실행한 후,

관리자 화면에서 데이터를 확인하면 아래와 같이 데이터가 잘 추가된 것을 확인할 수 있습니다.

# source venv/bin/activate
# cd django_exercise
python manage.py runserver

 

데이터베이스 툴을 사용하여 확인해도 아래와 같이 저장이 잘 된 것을 확인할 수 있습니다.

 

(4) 데이터 업데이트(Update)

아래에 코드로 데이터를 조회(Read)하고 업데이트(Update) 해 봅니다.

post = Post.objects.get(title='This is a test title from django shell')
post.title = 'This is a test title updated from django shell'
post.save()

 

아래에 코드로 업데이트된 내용을 확인할 수 있습니다.

Post.objects.get(title__contains='updated')
# or
Post.objects.filter(title__contains='updated')

 

또한 이전 블로그에서 작성한 Post 모델(Models)의 함수를 통해서도 업데이트가 가능합니다.

post = Post.objects.get(title__contains='updated')
# post.published_at
post.publish()
# >>> post.published_at
# datetime.datetime(2019, 5, 21, 13, 1, 58, 970677)

 

(5) 데이터 삭제(Delete)

아래에 코드로 위에서 만든 데이터를 삭제(Delete)해 봅니다.

post = Post.objects.get(title__contains='updated')
post.delete()
# >>> Post.objects.all()
# <QuerySet [<Post: this is a test1 title>, <Post: this is a test2 title>]>

 

(6) 조회 조건

지금까지 데이터베이스의 CRUD(Create Read Update Delete)에 대해서 살펴보았습니다.

아래는 데이터를 조회(Read)할 때 사용할 수 있는 일반적인 검색 조건에 대해서 설명하고 있습니다.

 

- 조회 조건

 

조회 조건설명사용 방법

__contains 지정한 문자열을 포함하는 데이터 조회 Post.objects.filter(title__contains=’test’)
__icontains 지정한 문자열의 대소문자 구분없이 포함하는 데이터 조회 Post.objects.filter(title__icontains=’this’)
__lt 값이 작은 경우(lt: less than) Post.objects.filter(published_at__lt=timezone.now())
__lte 값이 작거나 같은 경우(lte: less than or equal) Post.objects.filter(published_at__lt=timezone.now())
__gt 값이 큰 경우(gt: greater than) Post.objects.filter(published_at__gt=timezone.now())
__gte 값이 크거나 같은 경우(gt: greater than or equal) Post.objects.filter(published_at__gte=timezone.now())
__in 주어진 리스트에 포함되는 데이터 조회 Post.objects.filter(id__in=[1, 2, 3])
__year 해당 년도 조회 Post.objects.filter(created_at__year=’2019’)
__year 해당 월로 조회 Post.objects.filter(created_at__month=’5’)
__day 해당 일로 조회 Post.objects.filter(created_at__day=’21’)
__isnull 해당 열이 null인 데이터 조회 Post.objects.filter(published_at__isnull=True)
__startswith 해당 문자열로 시작하는 데이터 조회 Post.objects.filter(title__startswith=’This’)
__istartswith 대소문자를 가리지 않고 해당 문자열로 시작하는 데이터 조회 Post.objects.filter(title__istartswith=’this’)
__endswith 해당 문자열로 끝나는 데이터 조회 Post.objects.filter(title__endswith=’title’)
__iendswith 대소문자를 가리지 않고 해당 문자열로 끝나는 데이터 조회 Post.objects.filter(title__iendswith=’title’)
__range 범위를 지정하여 조회(sql의 between) Post.objects.filter(id__range=(1, 10))

 

- 제외 조건(exclude): 아래와 같이 특정 조건을 제외한 데이터를 조회할 수 있다.

Post.objects.all().exclude(title__contains='This')

 

- 여러 조건으로 조회: 아래와 같이 여러 조건을 걸어 데이터를 조회할 수 있다.

Post.objects.filter(title__contains='this', title__endswith='title')
Post.objects.filter(title__contains='this').filter(title__endswith='title')

from django.db.models import Q
Post.objects.filter(Q(title__contains='this') | Q(title__endswith='title'))
Post.objects.filter(Q(title__contains='this') & Q(title__endswith='title'))

 

- 조회 범위: 아래와 같이 가져올 데이터의 범위(limit)을 지정할 수 있다.

Post.objects.all().exclude(title__contains='This')[:1]

 

(7) 정렬

아래와 같이 조회할 데이터를 오름차순 또는 내림차순으로 정렬할 수 있습니다.

  • 오름 차순: Post.objects.order_by(‘created_at’)
  • 내림 차순: Post.objects.order_by(‘-created_at’)

 

(8) 쉘(Shell) 종료

지금까지 장고(django)의 쉘(Shell)을 이용하여 간단하게 장고(django)의 ORM(Object-Relational Mapping)에 대해서 연습해 보았습니다. 아래에 코드로 장고(django)의 쉘(Shell)을 종료합니다.

exit()

 

(9) 완료

이것으로 장고(django)의 ORM(Object-Relational Mapping)에 대해 알아보았습니다.

ORM(Object-Relational Mapping)은 장고(django)이외에도 많은 프레임워크에서 사용되는 개념이므로 잘 기억에 두면 좋을거 같네요. 이것으로 우리는 장고(django)의 모델(Models)을 사용하여 데이터를 읽고 쓰고 업데이트하고 삭제(CRUD - Create Read Update Delete)할 수 있게 되었습니다!


출처

https://dev-yakuza.posstree.com/ko/django/admin/

장고(django)의 URL 관리 기능을 사용하여 웹 서비스의 라우팅(Routing)을 관리해 봅시다.


1. 개요

이제 본격적으로 장고(django)를 사용하여 웹 서비스를 작성하려고 합니다.

웹 서비스를 작성하려면 사용자가 접속하는 URL별 페이지를 만들고 그 페이지를 서비스할 필요가 있습니다.

이 블로그 포스트에서는 장고(django)에서 기본적으로 제공하는 URL 관리 기능을 통해 웹 서비스의 라우팅(Routing)을 관리하는 방법에 대해서 설명합니다.

이 블로그는 시리즈로 작성되어 있으며, 아래에 링크를 통해 시리즈의 다른 글을 확인할 수 있습니다.

또한 이 블로그 시리즈에서 다룬 소스는 github에 공개되어 있습니다. 아래에 링크를 통해 확인 가능합니다.


2. 라우팅 확인

장고(django)는 크게 프로젝트(Project) 단위와 어플리케이션(Application) 단위가 존재합니다.

장고(djanog) 프로젝트는 여러 어플리케이션을 가질 수 있습니다.

 

이것은 곧

프로젝트(Project) 단위의 라우팅(Routing) 관리와

어플리케이션(Application) 단위의 라우팅(Routing) 관리가 존재한다는 것을 의미합니다.

 

우선 장고(django)의 프로젝트 단위의 라우팅(Routing) 관리를 확인하기 위해 

django_exercise/urls.py 파일을 확인 합니다.

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

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

파일을 열면 위와 같은 화면을 볼수 있습니다.

이전 블로그(장고(django)의 관리자 페이지)에서 http://127.0.0.1:8000/admin URL로 관리자 페이지에 접속하였습니다. 우리가 아무 설정도 하지 않아도 관리자 화면이 표시된 이유는 django_exercise/urls.py 파일에 위와 같은 설정이 기본적으로 설정되어있기 때문입니다. 우리는 이곳에 우리가 만든 새로운 장고(django) 어플리케이션(Application)의 라우팅 파일을 등록하여 어플리케이션(Application)별 라우팅을 관리할 예정입니다.


3. views.py 생성

일단 어플리케이션(Application)의 라우팅(Routing)을 통해 URL에 연결할 뷰(Views)를 생성할 필요가 있습니다. blog/views.py를 열고 아래와 같이 수정합니다.

from django.shortcuts import render

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

4. html 파일 생성

이제 뷰(Views) 파일에서 참고하고 있는 blog/posts.html 파일을 생성해야 합니다. 

blog/templates/blog/posts.html 파일을 생성하고 아래와 같이 코딩합니다.

<html>
  <head>
    <title>Hello World</title>
  </head>
  <body>
    Hello World
  </body>
</html>

이것으로 라우팅(Routing)을 통해 URL에 연결할 화면 준비가 끝났습니다.

이제 실제로 라우팅(Routing)을 통해 URL과 화면을 연결하는 방법에 대해서 알아보겠습니다.


5. 어플리케이션의 라우팅 파일 urls.py 생성

우리가 제작중인 블로그 웹 사이트에 해당하는 장고(django) 어플리케이션(Application)을 위한 라우팅(Routing) 파일을 생성할 필요가 있습니다. blog/urls.py 파일을 생성하고 아래에 내용을 추가합니다.

from django.urls import path
from . import views

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

6. 어플리케이션의 라우팅 등록

위에서 생성한 장고(django) 어플리케이션(Application)의 라우팅(Routing) 파일인 blog/urls.py를 장고(django) 프로젝트(Project)에 등록할 필요가 있습니다. django_exercise/urls.py 파일을 열고 아래와 같이 수정합니다.

from django.contrib import admin
from django.urls import path, include # <<< here

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

7. 확인

아래에 장고(django) 명령어로 테스트 서버를 실행한 후, 

http://127.0.0.1:8000/에 접속하여 우리가 설정한 라우팅(Routing)이 동작하는지 확인합니다.

# source venv/bin/activate
# pip install -r requirements.txt
# cd django_exercise
python manage.py runserver

브라우저에 Hello World가 잘 표시되는 것을 확인할 수 있습니다.


8. 완료

이것으로 장고(django)의 라우팅(Routing)에 대해서 알아보았습니다.

이제 라우팅(Routing)을 통해 자신이 만든 화면과 URL을 연결할 수 있습니다.

장고(django)에서 기본적으로 제공하는 관리자 페이지를 사용하는 방법에 대해서 알아봅니다.


1. 개요

파이썬(python)의 장고(django)로 서버사이드를 개발해보려고 합니다.

이 블로그 포스트에서는 장고(django)에서 기본적으로 제공하는 관리자 페이지를 사용하는 방법에 대해서 알아보려고 합니다. 장고(django)의 관리자 페이지를 phpmyadmin과 같이 데이터베이스의 정보를 보는 페이지를 의미합니다.

이 블로그는 시리즈로 작성되어 있으며, 아래에 링크를 통해 시리즈의 다른 글을 확인할 수 있습니다.

또한 이 블로그 시리즈에서 다룬 소스는 github에 공개되어 있습니다. 아래에 링크를 통해 확인 가능합니다.


2. 언어 설정

장고(django)가 기본적으로 제공하는 관리자 페이지의 기본 언어를 변경하고 싶으신 분은, django_exercise/settings.py를 열고 아래와 같이 수정합니다.

...
# LANGUAGE_CODE = 'en-us'
LANGUAGE_CODE = 'ko'
...

여기서는 기본 설정인 영어를 그대로 사용하고 진행하겠습니다.


3. 슈퍼 유저 생성

장고(django)가 기본적으로 제공하는 관리자 페이지에 로그인하기 위해서는 슈퍼 유저(superuser)를 만들 필요가 있습니다. 아래와 같이 장고(django) 명령어를 통해 슈퍼 유저(superuser)를 생성합니다.

# source venv/bin/activate
# pip install -r requirements.txt
# cd django_exercise
# python manage.py migrate
python manage.py createsuperuser

위에 명령어를 실행하면 아래와 같이 슈퍼 유저(superuser)를 등록하는 절차가 진행됩니다.

venv > ~/django_exercise/django_exercise > python manage.py createsuperuser
Username (leave blank to use '...'): dev-yakuza
Email address: dev.yakuza@gmail.com
Password:
Password (again):
Superuser created successfully.

절차에 맞게 자신이 사용할 슈퍼 유저(superuser)를 등록합니다.


4. 관리자 페이지 접속

아래에 URL로 들어가 장고(django)가 기본적으로 제공하는 관리자 페이지에 접속할 수 있습니다.

# python manage.py runserver
http://127.0.0.1:8000/admin

 

정상적으로 진행되었다면 아래와 같은 페이지을 볼 수 있습니다.

 

위에서 생성한 슈퍼 유저(superuser) 정보를 입력하고 로그인 하면 아래와 같은 페이지를 볼 수 있습니다.


5. 관리자 페이지에 모델(Models) 등록

장고(django)가 기본적으로 제공하는 관리자 페이지에서 우리가 만든 장고(django) 어플리케이션의 모델(Models)을 관리하기 위해서는 장고(django) 어플리케이션의 모델(Models)을 등록할 필요가 있습니다. 

blog/admin.py 파일을 열고 아래와 같이 우리가 만든 Post 모델을 등록 시킵니다.

 

장고(django)의 모델(Models) 생성에 관해서는 이전 블로그를 참고하시기 바랍니다.

(장고(django) 모델(models) 사용해보기)

from django.contrib import admin
from .models import Post

admin.site.register(Post)

 

그리고 관리자 페이지를 새로고침하면

아래와 같이 우리가 생성한 장고(django) 어플리케이션의 모델(Models)가 화면에 표시되는 것을 확인할 수 있습니다.


6. 관리자 페이지로 블로그 글 작성

장고(django)가 기본적으로 제공하는 관리자 페이지를 활용하여 우리가 만들 블로그 사이트에 글을 작성해 봅시다.

아래와 같은 관리자 메인 페이지에서 BLOG 하단에 Posts 옆에 Add를 눌러줍니다.

 

아래와 같이 테스트용 데이터를 작성합니다.

 

그리고 하단에 있는 Save and add another을 누르고, 추가적으로 테스트 데이터를 더 넣어 줍니다.

이번엔 테스트를 위해 published_at를 작성해서 저장합니다.

 

이번엔 Save를 눌러 저장하고, 저장한 데이터 리스트 화면으로 이동합니다.

위와 같이 데이터가 잘 저장된 것을 확인할 수 있습니다.


7. 확인

데이터가 정말 잘 저장되었는지 확인하기 위해 데이터베이스 툴을 사용하여 직접 데이터베이스안을 확인해 봅니다.

위에서 장고(django)가 기본적으로 제공하는 관리자 페이지로 등록한 데이터가 데이터베이스에 잘 저장된 것을 확인할 수 있습니다.


8. 완료

이것으로 장고(django)가 기본적으로 제공하는 관리자 페이지를 사용하는 방법에 대해서 알아보았습니다.

또한 이전 블로그에서 생성한 장고(django)의 모델(Models)을 관리자 화면에 표시하기 위한 방법도 함께 살펴보았습니다. 이로써 데이터베이스 툴이 없어도 간단하게 데이터를 다룰 수 있게 되었습니다.


출처

https://dev-yakuza.posstree.com/ko/django/admin/

장고(django) 프로젝트에서 어플리케이션을 생성하고 새로운 어플리케이션에 필요한 데이터를 저장할 모델(models)을 생성하고 사용하는 방법에 대해서 알아봅니다.


1. 개요

파이썬(python)의 장고(django)로 서버사이드를 개발해보려고 합니다. 이 블로그 포스트에서는 장고(django) 명령어를 새로운 어플리케이션을 생성하고, 그 어플리케이션에서 사용할 데이터를 저장하기 위해 모델(models)를 생성하고 사용하는 방법에 대해서 알아보려고 합니다.

이 블로그는 시리즈로 작성되어 있으며, 아래에 링크를 통해 시리즈의 다른 글을 확인할 수 있습니다.

 

또한 이 블로그 시리즈에서 다룬 소스는 github에 공개되어 있습니다. 아래에 링크를 통해 확인 가능합니다.


2. 장고(django) 어플리케이션 생성

장고(django)는 큰 단위에 프로젝트가 있고 그 안에 작은 단위로 어플리케이션이 존재합니다.

한 프로젝트에는 여러개의 어플리케이션이 존재할 수 있습니다.

여기에서는 장고(django)로 블로그를 개발한다고 가정하고 진행하도록 하겠습니다.

그럼 본격적으로 장고(django)로 개발하기 위해 아래에 장고(django) 명령어로 blog 어플리케이션을 생성합니다.

# virtualenv venv
# source venv/bin/activate
# pip install -r requirements.txt
# django-admin --version
# 2.2
python manage.py startapp blog

 

장고(django)의 어플리케이션이 잘 생성되었다면 아래와 같은 폴더 구조를 확인할 수 있습니다.

|-- django_exercise
|   |-- __init__.py
|   |-- settings.py
|   |-- urls.py
|   |-- wsgi.py
|-- blog
|   |-- __init__.py
|   |-- admin.py
|   |-- apps.py
|   |-- models.py
|   |-- tests.py
|   |-- views.py
|-- manage.py

 

새로 생성된 어플리케이션 하단의 파일들은 아래와 같은 역할을 합니다.

  • admin.py: 장고(django)에서 기본적으로 제공하는 관리화면 설정
  • apps.py: 어플리케이션 메인 파일
  • models.py: 어플리케이션의 모델(models) 파일
  • tests.py: 테스트 파일
  • views.py: 어플리케이션의 뷰(views) 파일

 

이 밖에도 아래와 같이 장고(django)에서 사용하는 파일들이 있습니다.

  • urls.py: 어플리케이션의 url 관리
  • forms.py: 입력 폼 관리
  • behaviors.py: 모델 믹스인 위치에 대한 옵션
  • constants.py: 어플리케이션 상수 관리
  • decorators.py: 데코레이터 관리
  • factories.py: 테스트 데이터 팩토리 파일
  • helpers.py: 뷰(views)와 모델(models)을 도와주는 함수 관리
  • managers.py: 커스텀 모델 매니저 파일
  • signals.py: 커스텀 시그널 관리
  • viewmixins.py: 뷰(views) 믹스인 관리

뭔 소리인지 하나도 모르겠네요.

나중에 하나씩 공부하다보면 저절로 알게 될테니 그냥 이런 파일이 있다고 생각하고 넘어가면 될거 같습니다.

장고(django) 어플리케이션을 생성하였으니, 장고(django) 프로젝트에 새롭게 생성한 어플리케이션을 등록해야합니다. 장고(django) 프로젝트를 관리하는 django_exercise/settings.py를 열고 아래와 같이 장고(django) 어플리케이션을 등록합니다.

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

3. 모델(models) 생성하기

이제부터 블로그 사이트를 개발하기 위해 필요한 모델(models)을 생성합니다.
blog/models.py를 열고 아래의 내용을 추가합니다.

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

class Post(models.Model):
    author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
    title = models.CharField(max_length=100)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    published_at = models.DateTimeField(blank = True, null = True)

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

    def __str__(self):
        return self.title

 

작성한 코드를 자세히 살펴보도록 하겠습니다.

  • Post는 author, title, content, created_at, updated_at, published_at 필드를 가지고 있습니다.
  • author는 ForeignKey 함수를 사용하여, 장고(django)에서 기본적으로 제공하는 auth 어플리케이션의 User 모델을 참조하게 만들었습니다.(auth.User: 앱이름.모델)
  • title은 블로그의 제목으로 CharField 함수를 사용하여 길이가 정해진 문자열을 저장하도록 하였습다. max_length 옵션을 사용해 길이가 100인 문자열을 저장하도록 설정하였습니다.
  • content는 블로그의 내용으로 TextField 함수를 통해 길이가 정해져있지 않는 문자열을 저장할 수 있도록 하였습니다
  • created_at은 블로그 생성 날짜로 DateTimeField을 통해 날짜와 시간을 저장할 수 있도록 하였으며, auto_now_add 옵션을 사용하여 데이터 생성시 현재 시간을 저장하도록 하였습니다.
  • updated_at는 블로그 수정일로 역시 DateTimeField을 통해 날짜와 시간을 저장할 수 있도록 하였으며, auto_now 옵션을 사용하여 데이터가 갱신될 때 현재 시간을 저장하도록 하였습니다.
  • published_at는 블로그를 공개한 날짜로 역시 DateTimeField을 통해 날짜와 시간을 저장할 수 있도록 하였습니다.

 

위에서는 설명하지 않은 blank = True, null = True는 별도로 설명하려고 합니다.

  • blank: 유효성(validation) 처리와 관련이 있는 옵션으로, form.is_valid()를 사용하여 입력폼의 유효성 검사를 할때 사용됩니다. 데이터의 공백(blank)을 허용합니다.
  • null: 데이터베이스와 관련이 있는 옵션으로, 데이터베이스의 null을 저장할 수 있도록 하는 옵션(nullable)

 

이 모델에는 publish, __str__ 함수를 가지고 있습니다.

  • publish: 블로그 서비스에서 자주 사용되는 기능인 공개(publish) 기능을 함수로 만들었습니다. 이 함수를 통해 블로그를 공개(publish)할 때 날짜를 갱신하기 위해 만들었습니다.
  • __str__: 표준 파이썬 클래스 메소드이며 사람이 읽을 수 있는 문자열을 반환하도록 합니다.

4. 모델(models)을 이용하여 테이블 생성

지금까지 만든 모델(models)을 가지고 데이터베이스(database)의 테이블을 생성하는 방법에 대해서 알아봅니다.

 

(1) 마이그레이션 파일 생성

우선 아래에 장고(django) 명령어로 우리가 만든 모델(models)로부터 데이터베이스(database)의 테이블을 생성하기 위한 마이그레이션(migration) 파일을 생성합니다.

python manage.py makemigrations blog

 

명령이 제대로 실행되었다면 아래와 같은 결과를 볼 수 있습니다.

 

그리고 폴더를 확인하면 마이그레이션 폴더와 파일이 생성된 것을 확인할 수 있습니다.

|-- django_exercise
|   |-- __init__.py
|   |-- settings.py
|   |-- urls.py
|   |-- wsgi.py
|-- blog
|   |-- migrations
|   |   |-- __init__.py
|   |   |-- 0001_initial.py.py
|   |-- __init__.py
|   |-- admin.py
|   |-- apps.py
|   |-- models.py
|   |-- tests.py
|   |-- views.py
|-- manage.py

 

(2) 테이블 생성

아래에 장고(django) 명령어로 모델(models)로부터 생성한 마이그레이션(migration) 파일을 이용하여 데이터베이스의 테이블을 생성합니다.

python manage.py migrate blog

 

명령어가 잘 실행되면 아래와 같은 결과를 확인할 수 있습니다.

 

데이터베이스 툴을 사용하여 데이베이스를 보면 우리가 모델(models)에 설정한 테이블이 생성된 것을 확인할 수 있습니다.


5. 완료

이것으로 장고(django)에서 모델(models)을 생성하고 생성한 모델(models)을 활용하여 DB 테이블을 생성하는 방법을 알아보았습니다. 이로써 개발에 필요한 정보를 저장할 수 있게 되었습니다. 이제 서비스에 필요한 DB를 설계하고 그에 따른 모델(models)과 마이그레이션(migration)을 생성하여 DB 테이블을 생성해 봅시다!


6. 참고

모델 데이터 타입

아래는 장고(django) 모델에서 사용 가능한 데이터 타입입니다.

Data typeDjango model type

Binary models.BinaryField()
Boolean models.BooleanField()
Boolean models.NullBooleanField()
Date/time models.DateField()
Date/time models.TimeField()
Date/time models.DateTimeField()
Date/time models.DurationField()
Number models.AutoField()
Number models.BigIntegerField()
Number models.DecimalField(max_digits=X,decimal_places=Y)
Number models.FloatField()
Number models.IntegerField()
Number models.PositiveIntegerField()
Number models.PositiveSmallIntegerField()
Number options.SmallIntegerField()
Text models.CharField(max_length=N)
Text models.TextField()
Text (Specialized) models.CommaSeparatedIntegerField(max_length=50)
Text (Specialized) models.EmailField()
Text (Specialized) models.FileField()
Text (Specialized) models.FilePathField()
Text (Specialized) models.ImageField()
Text (Specialized) models.GenericIPAddressField()
Text (Specialized) models.SlugField()
Text (Specialized) models.URLField()
Text (Specialized) models.UUIDField()

출처

https://dev-yakuza.posstree.com/ko/django/models/

장고(django)의 명령어를 통해 장고(django) 프로젝트를 생성하고 시작해 봅시다. 또한 설정, DB(mysql) 연동을 통해 실제로 장고(django)로 프로젝트를 개발할 수 있는 상태를 만들어 봅시다.


1. 개요

파이썬(python)의 장고(django)로 서버사이드를 개발해보려고 합니다.

이 블로그 포스트에서는 장고(django) 명령어를 통해 장고(django) 프로젝트를 설치하고 시작하는 방법에 대해서 알아봅니다.

이 블로그는 시리즈로 작성되어 있으며, 아래에 링크를 통해 시리즈의 다른 글을 확인할 수 있습니다.

또한 이 블로그 시리즈에서 다룬 소스는 github에 공개되어 있습니다. 아래에 링크를 통해 확인 가능합니다.

 

GitHub - dev-yakuza/django_exercise

Contribute to dev-yakuza/django_exercise development by creating an account on GitHub.

github.com


2. 장고(django) 프로젝트

아래에 명령어로 파이썬(python)의 가상 환경(Virtual Environment)를 실행하고 장고(django)가 잘 설치되어있는지 확인합니다.

source venv/bin/activate
django-admin --version
# 2.2

 

파이썬(python)의 가상 환경(Virtual Environmet) 설정이나 장고(django) 설치에 대한 내용은 이전 블로그를 참고해 주세요.

 

아래에 명령어로 장고(django) 프로젝트를 생성합니다.

django-admin startproject django_exercise

3. 기본 폴더 구조

장고(django) 명령어로 프로젝트를 생성하면 아래와 같이 폴더가 생성되는 것을 확인할 수 있습니다.

|-- django_exercise
|   |-- __init__.py
|   |-- settings.py
|   |-- urls.py
|   |-- wsgi.py
|-- manage.py

 

각 파일은 아래와 같은 기능을 합니다.

  • django_exercise/settings.py: 전반적인 설정을 가지고 있는 파일
  • django_exercise/urls.py: 프로젝트의 url을 관리하는 파일
  • django_exercise/wsgi.py: 웹서버(apache, nginx등)과 연동하기 위한 파일
  • manage.py: 프로젝트를 관리. 예를 들어, DB의 migration 생성 및 실행, 로컬에서 다른 설치없이 웹 서버를 기동 등

4. 설정

설정 파일인 django_exercise/settings.py을 열고 아래와 같이 타임존을 설정합니다.

...
TIME_ZONE = 'Asia/Seoul'
...
USE_TZ = False
...

 

위에서 설정한 USE_TZ 옵션은 True인 경우, templates와 forms에서만 위에서 설정한 타임존을 따르게 됩니다. 

False인 경우, models에서도 타임존을 따르게 되므로 모든 곳에서 동일한 타임존을 따르게 됩니다.

또한 static 파일을 다루기 위해 아래와 같이 STATIC_ROOT를 추가합니다.

...
STATIC_URL = '/static/'
...

 

마지막으로, 프로젝트를 실서버에 배포할 경우, 아래와 같이 DEBUG 설정을 False로 변경한 후 배포하시기 바랍니다.

...
DEBUG = False
...

5. DB 설정

여기에서는 장고(django)와 mysql을 연동하는 방법에 대해서 소개합니다.

맥(Mac)에 mysql을 설치하는 방법에 대해서는 아래에 링크를 통해 확인하시기 바랍니다.

 

맥(Mac) 개발 환경 구축(3) - 개발 환경

새로운 맥(Mac)에 개발 환경을 구축하려고 합니다. 지금 현재 개발에 사용하고 개발 환경을 설정하는 방법에 대해서 설명합니다.

dev-yakuza.posstree.com

 

장고(djanog)의 설정 파일인 django_exercise/settings.py를 열고 아래와 같이 수정합니다.

...
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': '...',  # DB name
        'USER': 'root',  # DB account
        'PASSWORD': '...',  # DB account's password
        'HOST': '127.0.0.1',  # DB address(IP)
        'PORT': '3306',  # DB port(normally 3306)
    }
}
...

위에 내용에서 NAME과 PASSWORD는 환경에 맞게 수정하시기 바랍니다.

아래에 명령어로 mysql과 연동하기 위해 필요한 모듈인 mysqlclient를 설치합니다.

pip install mysqlclient

 

만약 설치중에 아래와 같은 에러 메세지가 나오면,

...
ld: library not found for -lssl
clang: error: linker command failed with exit code 1 (use -v to see invocation)
error: command 'clang' failed with exit status 1
...

 

아래에 명령어를 사용하여 mysqlclient를 설치하시기 바랍니다.

LDFLAGS=-L/usr/local/opt/openssl/lib pip install mysqlclient

 

모듈 설치가 완료되었다면 다른 환경에서도 사용할 수 있도록 아래에 명령어로 requirements.txt 파일을 갱신합니다.

# cd django_excercise
pip freeze > requirements.txt

 

Database가 잘 연동되었지 확인하기 위해

장고(django)가 기본으로 제공하는 관리화면에 필요한 기본 테이블을 아래에 명령어를 통해 생성해 봅니다.

python manage.py migrate

 

장고(django)와 mysql 연동을 잘 수행했다면 아래와 같은 화면을 볼 수 있습니다.

 

database 툴을 이용하여 확인하면 아래와 같이 성공적으로 테이블이 생성된 것을 확인할 수 있습니다.


6. 테스트

지금까지 장고(django)에 설정에 대해서 알아보았습니다.

이제 아래에 명령어를 통해 장고(django)에서 지원하는 테스트 웹서버를 기동하여 우리가 만든 프로젝트가 잘 실행되는지 확인합니다.

python manage.py runserver
# http://127.0.0.1:8000/

장고(django) 설치와 설정을 무사히 진행하였다면 아래와 같이 장고(django)에서 지원하는 기본 화면을 확인할 수 있습니다.


7. 완료

이것으로 장고(django)의 명령어를 통해 프로젝트를 생성하고 시작하는 방법에 대해서 알아보았습니다.

간단하게 프로젝트 폴더 구조 설명과 설정에 대해서도 알아보았습니다.

또한 앞으로 사용할 mysql과의 연동과 로컬에서 테스트하기 위해 장고(django)에서 기본적으로 제공하는 웹 서버를 사용하여 프로젝트를 실행해 보았습니다.

 

이제 개발할 준비가 완료되었습니다. 장고(django)를 통해 개발을 시작해 봅시다!


출처

https://dev-yakuza.posstree.com/ko/django/start/

 

장고(django) 프로젝트 시작하기

장고(django)의 명령어를 통해 장고(django) 프로젝트를 생성하고 시작해 봅시다. 또한 설정, DB(mysql) 연동을 통해 실제로 장고(django)로 프로젝트를 개발할 수 있는 상태를 만들어 봅시다.

dev-yakuza.posstree.com

 

장고(django) 개발을 위해 장고(django)를 설치하고 설정하는 방법에 대해서 알아봅니다.


1. 개요

파이썬(python)의 장고(django)로 서버사이드를 개발해보려고 합니다.

이 블로그 포스트에서는 장고(django)로 개발하기 위한 설치와 설정에 대해서 설명합니다.

이 블로그는 시리즈로 작성되어 있으며, 아래에 링크를 통해 시리즈의 다른 글을 확인할 수 있습니다.

또한 이 블로그 시리즈에서 다룬 소스는 github에 공개되어 있습니다. 아래에 링크를 통해 확인 가능합니다.


2. 설치

장고(django)를 사용하기 위해서는 파이썬(python)을 설치해야합니다.

아래에 링크를 통해 자신의 OS에 맞는 파이썬(python)를 다운로드 받은 후 설치합니다.

저는 주로 맥(Mac)을 사용하여 개발합니다. 또한 터미널로는 zsh를 사용하고 있습니다.

아래에 링크를 통해 맥(Mac)과 zsh를 사용하여 파이썬(python)을 설정하는 방법을 확인하세요.

위에 링크를 통해 zsh와 파이썬(python)을 설정하였다면 아래에 명령어로 버전을 확인합니다.

python --version
Python 3.7.2

아래에 명령어를 통해 파이썬의 가상 환경(Virtual Environment)을 간단하게 사용할 수 있게 도와주는 virtualenv 모듈을 설치합니다.

pip install virtualenv pylint autopep8

 

아래에 명령어를 통해 장고(django)를 사용하기 위한 환경을 만듭니다.

mkdir server
cd server
virtualenv venv

 

아래에 명령어로 가상 환경(Virtual Environment)을 활성화시킵니다.

source venv/bin/activate

 

아래 명령어로 장고(django)를 가상 환경(Virtual Environment)에 설치합니다.

pip install django

 

설치가 완료되었다면 아래에 명령어로 장고(django)가 잘 설치되었는지 확인합니다.

django-admin --version
# 2.2

 

아래에 명령어로 설치된 개발 환경을 파일로 저장합니다.

# cd server
pip freeze > requirements.txt

 

설치가 확인되었다면 아래에 명령어로 가상 환경(Virtual Environment)을 종료합니다.

deactivate

 

다시 아래에 명령어를 실행하여 가상 환경(Virtual Environment)가 정상적으로 종료되었는지 확인합니다.

django-admin --version
# zsh: command not found: django-admin

 

위에 명령어를 통해 가상 환경(Virtual Environment)을 이해할 수 있을거 같습니다.

위에서 설치한 장고(django)는 가상 환경(Virtual Enviroment)에 설치하였습니다.

따라서 가상 환경(Virtual Environment)가 종료된 환경에서 장고(django) 명령어를 실행하면 장고(django)를 찾을 수 없다는 에러가 나옵니다. 이처럼 파이썬 가상 환경(python virtual environment)를 사용하여 파이썬(python) 개발 환경을 고립시킬 수 있습니다.


3. 다른 머신에서 사용하기

파이썬(python)의 가상 환경(Virtual Environment)는 말 그대로 환경입니다.

따라서 이 환경을 git로 버전 관리를 할 필요하 없습니다. .gitignore에 아래에 내용을 추가합니다.

# .gitignore
...
venv

 

그리고 git에는 requirements.txt를 저장합니다.

다른 머신에서는 git를 가져오고 명령어로 가상 환경(Virtual Environment)을 설치하고 실행한 후

아래에 명령어로 장고(django)를 설치합니다.

# cd server
pip install -r requirements.txt

 

개발을 하면서 여러 모듈을 설치할텐데,

설치가 완료되면 항상 아래에 명령어를 실행하여 requirements.txt를 갱신합니다.

# cd server
pip freeze > requirements.txt

4. 완료

장고(django)를 사용하기 위해 파이썬(python)과 파이썬(python)의 가상 환경(Virtual Environment)을 구성하고 장고(django)를 설치해 보았습니다. 이로써 장고(django) 개발에 준비를 맞췄습니다. 앞으로는 장고를 사용하여 서버사이드를 개발하는 방법에 대해서 설명하도록 하겠습니다.

 


출처

https://dev-yakuza.posstree.com/ko/django/installation/

 

https://simpleisbetterthancomplex.com/packages/2016/10/08/isort.html

 

How to Use Python isort Library

isort is a Python utility / library to sort imports alphabetically, and automatically separated into sections. It’svery useful in Django projects, specially ...

simpleisbetterthancomplex.com

 

https://github.com/PyCQA/isort#readme

 

GitHub - PyCQA/isort: A Python utility / library to sort imports.

A Python utility / library to sort imports. Contribute to PyCQA/isort development by creating an account on GitHub.

github.com

 

Git의 pre-commit 훅(hook)은 우리가 작성한 코드를 커밋할 때 마다 자동으로 특정 작업을 실행해줍니다.

 

많은 프로젝트들이 이를 통해 포멧터(formatter)를 실행하여 코드 스타일을 통일하고, 린터(linter)를 실행하여 코드에 잠재하고 있는 문제들을 찾아냅니다.

 

이번 포스팅에서는 Git의 pre-commit hook을 편리하게 사용할 수 있도록 도와주는 pre-commit라는 도구에 대해서 알아보겠습니다.

1. 설치

pre-commit은 자신의 컴퓨터에 파이썬이 설치가 되어 있다면 파이썬의 패키지 매니저인 pip를 사용하여 설치할 수 있습니다.

$ pip install pre-commit
Collecting pre-commit
  Downloading pre_commit-2.8.2-py2.py3-none-any.whl (184 kB)
     |████████████████████████████████| 184 kB 3.2 MB/s
Collecting toml
  Downloading toml-0.10.2-py2.py3-none-any.whl (16 kB)
Requirement already satisfied: pyyaml>=5.1 in /opt/virtualenvs/python3/lib/python3.8/site-packages (from pre-commit) (5.3.1)
Collecting cfgv>=2.0.0
  Downloading cfgv-3.2.0-py2.py3-none-any.whl (7.3 kB)
Collecting nodeenv>=0.11.1
  Downloading nodeenv-1.5.0-py2.py3-none-any.whl (21 kB)
Collecting virtualenv>=20.0.8
  Downloading virtualenv-20.1.0-py2.py3-none-any.whl (4.9 MB)
     |████████████████████████████████| 4.9 MB 4.6 MB/s
Collecting identify>=1.0.0
  Downloading identify-1.5.9-py2.py3-none-any.whl (97 kB)
     |████████████████████████████████| 97 kB 7.4 MB/s
Collecting distlib<1,>=0.3.1
  Downloading distlib-0.3.1-py2.py3-none-any.whl (335 kB)
     |████████████████████████████████| 335 kB 43.6 MB/s
Requirement already satisfied: six<2,>=1.9.0 in /opt/virtualenvs/python3/lib/python3.8/site-packages (from virtualenv>=20.0.8->pre-commit) (1.15.0)
Requirement already satisfied: appdirs<2,>=1.4.3 in /opt/virtualenvs/python3/lib/python3.8/site-packages (from virtualenv>=20.0.8->pre-commit) (1.4.4)
Collecting filelock<4,>=3.0.0
  Downloading filelock-3.0.12-py3-none-any.whl (7.6 kB)
Installing collected packages: toml, cfgv, nodeenv, distlib, filelock, virtualenv, identify, pre-commit
Successfully installed cfgv-3.2.0 distlib-0.3.1 filelock-3.0.12 identify-1.5.9 nodeenv-1.5.0 pre-commit-2.8.2 toml-0.10.2 virtualenv-20.1.0
WARNING: You are using pip version 20.1.1; however, version 20.2.4 is available.
You should consider upgrading via the '/opt/virtualenvs/python3/bin/python3 -m pip install --upgrade pip' command.

 

파이썬이 설치되어 있지 않다면, 운영체제의 패키지 매니저를 통해서도 설치할 수 있습니다.

예를 들어, MacOS 사용자는 Homebrew를 사용하면 됩니다.

$ brew install pre-commit

 

설치가 제대로 되었는지 확인해보기 위해서 버전을 출력해봅니다.

$ pre-commit -V
pre-commit 2.8.2

2. 설정

pre-commit은 .pre-commit-config.yaml이라는 설정 파일을 필요로 합니다.

터미널에 샘플 설정을 출력해주는 커맨드를 이용하여 설정 파일을 생성해보겠습니다.

$ pre-commit sample-config > .pre-commit-config.yaml

 

생성된 설정 파일을 열어보면, 4개의 훅(hook)이 설정되어 있는 것을 볼 수 있습니다.

# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v3.2.0
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
      - id: check-yaml
      - id: check-added-large-files

 

pre-commit 도구는 인터넷에 공개되어 있는 Git 저장소로 부터 hook을 내려받아서 실행을 합니다.

즉, 우리는 실행하고 싶은 hook이 어느 Git 저장소에 위치하는지 알아야 합니다.

 

pre-commit 공식 홈페이지의 Supported hooks 페이지를 방문하시면 커뮤니티에서 제공하는 다양한 pre-commit hook을 만나볼 수 있습니다.


3. 실행

$ pre-commit run
[INFO] Initializing environment for https://github.com/pre-commit/pre-commit-hooks.
[INFO] Installing environment for https://github.com/pre-commit/pre-commit-hooks.
[INFO] Once installed this environment will be reused.
[INFO] This may take a few minutes...
Trim Trailing Whitespace.............................(no files to check)Skipped
Fix End of Files.....................................(no files to check)Skipped
Check Yaml...........................................(no files to check)Skipped
Check for added large files..........................(no files to check)Skipped

 

보통 초기 셋업 단계에서는 직접 pre-commit를 실행해보면서 설정이 잘 되었는지 확인이 필요합니다.

수동으로 pre-commit을 실행해주는 커맨드를 터미널에서 실행해보겠습니다.

 

설정 파일에 등록된 모든 hook이 설치된 후, 체크할 파일이 없어서 모든 hook의 실행이 생략되는 것을 볼 수 있습니다.

설정 파일을 스테이징 영역에 추가하고 다시 pre-commit 도구를 실행해보겠습니다.

 

$ git add .pre-commit-config.yaml
$ pre-commit run -a
Trim Trailing Whitespace.................................................Passed
Fix End of Files.........................................................Passed
Check Yaml...............................................................Passed
Check for added large files..............................................Passed

 

이번에는 모든 hook이 통과했다고 나오는 것을 확인할 수 있습니다.

 

$ git commit -m "creates .pre-commit-config.yaml"
[master (root-commit) d262bdb] creates .pre-commit-config.yaml
 1 file changed, 10 insertions(+)
 create mode 100644 .pre-commit-config.yaml

본격적인 테스트를 위해 설정 파일을 커밋하겠습니다.

 

4. 테스트

설정한 hook이 제대로 동작하는지 체크하기 위해서,

일부로 불필요한 공백(trailing whitespace)을 넣어서 test.txt 파일을 생성해보겠습니다.

$ echo "test " > test.txt

 

생성된 파일을 스테이징 영역에 추가하고,

pre-commit 도구를 실행해보면 trailing-whitespace hook이 실패한 것을 확인할 수 있습니다.

$ git add test.txt
$ pre-commit run
Trim Trailing Whitespace.................................................Failed
- hook id: trailing-whitespace
- exit code: 1
- files were modified by this hook

Fixing test.txt

Fix End of Files.........................................................Passed
Check Yaml...........................................(no files to check)Skipped
Check for added large files..............................................Passed

 

이렇게 hook이 실패한 파일은 자동으로 수정해 주기 때문에 변경분을 스테이징 영역에 추가 후,

다시 pre-commit를 실행하면 모든 hook이 통과하는 것을 볼 수 있습니다.

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   test.txt

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   test.txt

$ git add test.txt
$ pre-commit run
Trim Trailing Whitespace.................................................Passed
Fix End of Files.........................................................Passed
Check Yaml...........................................(no files to check)Skipped
Check for added large files..............................................Passed

5. 자동화

pre-commit를 사용하는 최종 목적은 Git으로 커밋(commit)을 남길 때 마다 특정 작업을 자동으로 실행하는 것입니다. 이를 위해서는 프로젝트의 모든 개발자들이 Git 저장소를 클론받은 후에 제일 먼저 pre-commit install 커맨드를 실행해야 합니다.

$ pre-commit install

pre-commit installed at .git/hooks/pre-commit

 

이 명령어를 실행한 후에는 매번 pre-commit run 커맨드를 실행하지 않아도,

커밋을 할려고할 때 마다 자동으로 pre-commit이 실행이 됩니다.

$ echo "test " > test.txt
$ git add test.txt
$ git commit -m "adds test"
Trim Trailing Whitespace.................................................Failed
- hook id: trailing-whitespace
- exit code: 1
- files were modified by this hook

Fixing test.txt

Fix End of Files.........................................................Passed
Check Yaml...........................................(no files to check)Skipped

6. 마치면서

이상으로 pre-commit 도구를 어떻게 사용하는지에 대해서 간단히 살펴보았습니다.

pre-commit의 가장 큰 장점은 Git이 언어에 구애받지 않듯이, pre-commit도 언어와 상관없이 사용할 수 있다는 것입니다. 추후 기회가 되면 언어별로 자주 사용되는 hook에 대해서 다뤄보도록 하겟습니다.

 


출처

https://www.daleseo.com/pre-commit/

 

pre-commit 도구로 Git Hook 사용하기

Engineering Blog by Dale Seo

www.daleseo.com

 

'Django > TIL etc' 카테고리의 다른 글

스웨거란? Open API  (0) 2022.01.31
[Django 패키지] isort  (0) 2022.01.21
[Django 패키지] flake8 사용법  (0) 2022.01.21
파이썬 패키지 관리툴 poetry 소개  (0) 2022.01.21
Poetry 와 장고 프로젝트  (0) 2022.01.21

1. 코드 스타일

파이썬과 같이 사용차층이 넓은 범용 프로그래밍 언어의 경우, 개발자들이 선호하는 코드 스타일이 다양해지게 됩니다. 개인 프로젝트에서는 자신이 선호에 따라 어떤 방식으로 코드를 포멧팅하든지 코드가 돌아가기면 하면 큰 상관이 없지만, 협업 프로젝트에서는 이러한 개발자 간의 사소한 코드 스타일 차이로 불필요한 감정 싸움이 발생하기도 합니다.

 

예를 들어, 똑같은 문자열을 표현하기 위해서 개발자 A는 홑따옴표를 사용하고 싶은데, 개발자 B는 쌍따옴표를 사용하고 싶습니다. 만약에 개발자 A가 작성한 코드를 나중에 개발자 B가 수정하면서 홑따옴표를 모두 쌍따움표로 바꿨는데, 코드 리뷰 과정에서 개발자 A가 이 사실을 알게된다면? 이게 참 별 일도 아닌데 직접 곁어보면 따지기도 그렇고 모른체 하기도 찝찝하고… 암튼 이렇게 협업 프로젝트에 표준화된 코드 스타일이 없으면 팀워크에 나쁜 영향을 줄 수 있습니다.

이런 경우, 코드 포멧팅 도구(Code Formatter)를 사용해서 코드 스타일을 통일시키면 문제를 해결할 수 있습니다.


2. Black이란?

Black은 최근 파이썬 커뮤니티에서 가장 널리 쓰이고 있는 있는 코드 포멧터입니다.

기존 코드 포멧터와 달리 Black은 설정의 여지가 거의 없어서 정해놓은 특정 포멧팅 규칙을 그대로 따라야합니다.

그래서 처음에 Black을 접햇을 때 Black이 모든 코드를 일률적으로 포멧팅하는 방식에 거부감이 느껴질 수도 있습니다. 이처럼 유연하지 않은 코드 포멧터가 개발자들 사이에서 이렇게 인기를 얻을 수 있었던 이유는 무엇일까요?

 

바로 팀 내에서 개발자간에 코드 스타일을 협의하고 동의 하에 표준화하는 과정 자체에 상당한 소모적이기 때문입니다. 게다가 대부분의 개발자들이 문자열을 표현하기 위해서 홑따옴표를 사용하든 쌍따옴표를 사용하든 크게 개의치 않습니다. 사실 정말 중요한 것은 하나의 코드 스타일을 기준으로 모든 개발자가 일관성 있는 코드를 작성하는 것입니다.

협업 프로젝트에서 Black을 사용하게 되면 더 이상 코드 스타일에 대해서 개발자간에 왈가왈부 할 일이 없어집니다. Black이 자신의 코드를 포멧팅 하는 방식이 좋든 싫든 더 이상 개인의 특정 선호는 중요하지 않게 됩니다.

 

Black에서 정해놓은 코딩 스타일들은 오랜 커뮤니티의 다양한 의견이 수렴을하고 여러 프로젝트에서 여러가지 실험을 통해 결정었습니다. 따라서, Black은 매우 특수한 프로젝트가 아닌 이상 대부분의 프로젝트에서 무난하게 사용할 수 있습니다. 이 것이 수많은 오픈 소스 파이썬 프로젝트들과 파이썬을 사용하는 수많은 기업들에서 Black을 정식 코드 포멧터로 채택해서 사용하는 이유입니다.


3. Black CLI

Black은 기본적으로 터미널 상에서 CLI 도구로 손쉽게 접해볼 수 있습니다.

먼저 pip 패키지 매니저를 이용해서 Black 패키지를 설치합니다.

$ pip install black

 

그 다음, 파이썬 파일을 하나 생성 후에 다음과 같이 코드 스타일이 엉망인 코드를 작성합니다.

  • main.py (black으로 포멧팅 전)
from seven_dwwarfs import Grumpy, Happy, Sleepy, Bashful, Sneezy, Dopey, Doc
x = {  'a':37,'b':42,

'c':927}

x = 123456789.123456789E123456789

if very_long_variable_name is not None and \
 very_long_variable_name.field > 0 or \
 very_long_variable_name.is_debug:
 z = 'hello '+'world'
else:
 world = 'world'
 a = 'hello {}'.format(world)
 f = rf'hello {world}'
if (this
and that): y = 'hello ''world'#FIXME: https://github.com/python/black/issues/26
class Foo  (     object  ):
  def f    (self   ):
    return       37*-2
  def g(self, x,y=42):
      return y
def f  (   a: List[ int ]) :
  return      37-a[42-u :  y**3]
def very_important_function(template: str,*variables,file: os.PathLike,debug:bool=False,):
    """Applies `variables` to the `template` and writes to `file`."""
    with open(file, "w") as f:
     ...

regular_formatting = [
    0,  1,  2,
    3,  4,  5,
    6,  7,  8,
]

 

그 다음, 작성한 파일을 대상으로 black 커맨드를 --check 옵션을 줘서 실행해보면 하나의 파일이 포멧팅이 필요하다고 나옵니다.

$ black --check main.py
would reformat main.py
Oh no! 💥 💔 💥
1 file would be reformatted.

 

이 번에는 --check 옵션을 빼고 실행을 해보면 black이 파일 내의 코드를 포멧팅하여 저장해주는 것을 볼 수 있습니다.

black main.py
reformatted main.py
All done! ✨ 🍰 ✨
1 file reformatted.

 

실제 파일을 열어보면 다음과 같이 읽기 쉽게 깔끔하게 정돈된 코드를 볼 수 있으실 겁니다. 💅

  • main.py (black으로 포멧팅 후)
from seven_dwwarfs import Grumpy, Happy, Sleepy, Bashful, Sneezy, Dopey, Doc

x = {"a": 37, "b": 42, "c": 927}

x = 123456789.123456789e123456789

if (
    very_long_variable_name is not None
    and very_long_variable_name.field > 0
    or very_long_variable_name.is_debug
):
    z = "hello " + "world"
else:
    world = "world"
    a = "hello {}".format(world)
    f = rf"hello {world}"
if this and that:
    y = "hello " "world"  # FIXME: https://github.com/python/black/issues/26


class Foo(object):
    def f(self):
        return 37 * -2

    def g(self, x, y=42):
        return y


def f(a: List[int]):
    return 37 - a[42 - u : y ** 3]


def very_important_function(
    template: str, *variables, file: os.PathLike, debug: bool = False,
):
    """Applies `variables` to the `template` and writes to `file`."""
    with open(file, "w") as f:
        ...


regular_formatting = [
    0,
    1,
    2,
    3,
    4,
    5,
    6,
    7,
    8,
]

4. 코드 편집기 설정

코드의 양이 많은 실제 프로젝트에서는 위와 같이 터미널에서 매번 Black을 실행하여 포멧팅을 하는 것은 어리석은 일일 것입니다. 다행이도 대부분의 파이썬 코드 편집기에서 변경된 코드를 저장할 때 마다 Black이 자동으로 샐행되도록 설정을 해줄 수 있습니다.

 

예를 들어, 제가 주로 쓰는 VSCode의 경우, 다음과 같은 설정을 .vscode/settings.json에 추가해주기만 하면 됩니다.

첫번째 설정은 코드가 저장할 때 마다 자동으로 포멧팅을 하기 위함이고, 두번째 설정은 VSCode의 기본 포멧터 대신에 Black을 사용하기 위함입니다.

{
  "editor.formatOnSave": true,
  "python.formatting.provider": "black"
}

다른 코드 편집기의 설정 방법에 대해서는 공식 레퍼런스를 참고바라겠습니다.


5. Git hook 설정

코드 편집기 설정은 어디까지나 개인의 선택 사항이기 때문에 프로젝트 차원에서 포멧팅이 되지 않은 코드를 커밋하려고 하는 것을 방지하는 것이 바람직할 것입니다.

먼저, Git hook 스크립트를 실행해주는 pre-commit 패키지를 설치합니다.

$ pip install pre-commit

 

그 다음, .pre-commit-config.yaml 파일을 생성 후에 다음과 같이 설정 내용을 추가합니다.

repos:
  - repo: https://github.com/psf/black
    rev: stable
    hooks:
      - id: black

 

이제, pre-commit 커맨드를 실행하여 방금 작성한 Git hook 스크립트를 설치해줍니다.

$ pre-commit install
pre-commit installed at .git/hooks/pre-commit

 

마지막으로, 코드 에디터의 자동 포멧팅을 해제하고,

일부로 포멧팅이 엉망인 코드를 작성 후에 저장하고 커밋을 시도해봅니다.

$ git commit
black....................................................................Failed
- hook id: black
- files were modified by this hook

reformatted /Users/dale/learn/learn-python/main.py
All done! ✨ 🍰 ✨
1 file reformatted, 9 files left unchanged.

 

위에서 설정한 Git hook 스크립트가 실행되어 커밋이 실패하고 Black이 포멧팅을 해주었습니다! 🤗

이제 Black이 만들어준 변경분을 다시 git add 후에 git commit하면 됩니다.

 

이제부터 git commit을 할 때 마다 Black이 자동으로 포멧팅을 검사하고 필요 시에 코드를 수정해주기 때문에,

코드 에디터에 자동 포멧팅 설정을 안 해놓은 개발자도 자연스럽게 Black을 통해 일관적인 코드 스타일을 유지할 수 있습니다.

pre-commit 도구에 대한 자세한 설명은 관련 포스팅를 참조바랍니다.


6. 마치면서

이상으로 파이썬 코드 포멧터인 Black을 이용하는 방법에 대해서 간단히 살펴보았습니다.

Black에 대한 더 자세한 내용은 아래 링크를 참고바라겠습니다.

 

The uncompromising code formatter — Black 21.12b0 documentation

The uncompromising code formatter By using Black, you agree to cede control over minutiae of hand-formatting. In return, Black gives you speed, determinism, and freedom from pycodestyle nagging about formatting. You will save time and mental energy for mor

black.readthedocs.io

 

Black Playground

Playground for Black, the uncompromising Python code formatter.

black.vercel.app

 

GitHub - psf/black: The uncompromising Python code formatter

The uncompromising Python code formatter. Contribute to psf/black development by creating an account on GitHub.

github.com


출처

https://www.daleseo.com/python-black/

+ Recent posts