Dev/Django

Django 이해하기 Part2. 많이 사용하는 파일(urls.py, models.py)

sincerely10 2020. 7. 12. 21:09
반응형

지난번 Django의 MTV를 다루는 내용의 포스트에서 많이 사용되는 파일인 urls.py, models.py, views.py를 다루는 포스트를 작성한다 하였습니다.

각 파일의 실제적 사용을 다뤄보겠습니다.

들어가기 전에 예시로 사용되는 Django Project 구조를 안내드립니다.

westagram이라는(인스타그램의 일부 기능 구현) Django Project를 생성하였습니다.
그리고 Django App으로 posts와 users가 있습니다.

1. urls.py

먼저 urls.py 입니다.
처음 Django Project를 생성하면 프로젝트 directory 안에 urls.py 파일이 같이 생성됩니다.
이 urls.py는 주로 '/'로 구분되어 url을 연결하는데 사용됩니다.
이렇게 구성하면 EndPoint를 구조적인 형태로 만들 수 있고, 효과적으로 App의 url을 만들 수 있습니다.

자동으로 생성된 파일에 주석으로 사용법이 친절하게 나와 있습니다.

Function views
1. Add an import:  from my_app import views
2. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')
Class-based views
1. Add an import:  from other_app.views import 
2. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')
Including another 
1. Import the include() function: from django.conf.urls import url, 
2. Add a URL to urlpatterns:  url(r'^blog/', include('blog.urls'))

이 메뉴얼에 따라 저는 urls.py 파일을 아래와 같이 크게 두 가지로 활용하고 있습니다.

1.1 메인 프로젝트 urls에서 include 하여 넘겨주기

처음에는 위에서 말씀드린 내용으로 프로젝트 생성시 자동으로 생성되는 urls,py 입니다.
django.conf.urls에서 url과 include를 import 합니다.
include는 찾은 url 패턴에 대해 다른 urls 파일로 넘겨주는 역할을 합니다.
제가 만든 Django 프로젝트의 프로젝트 디렉토리에 있는 urls.py는 다음과 같습니다.

#westagram/urls.py
from django.contrib import admin
from django.urls    import path,include

urlpatterns = [
    path('user',include('users.urls')),
    path('post',include('posts.urls')),
]

위와 같은 형태로 직접 url pattern을 가지고 함수를 호출하지는 않습니다.
즉, user라는 단어가 있는 url을 만나면 include를 통해 users App의 urls 파일로 넘겨줍니다.
예를 들어 url이 'user/sign-in'의 형태로 들어온다면 urlpatterns라는 list에서 넘겨받은 url의 첫 계층인 user가 보일 때 까지 하나씩 찾습니다.
user 다음에 오는 / <- 이 부분부터는 'users.urls' 파일에서 처리해 주어야 합니다.
(user와 user/는 전혀 다른 엔드포인트 입니다.)

만약 HTTP Request에 해당하는 url 패턴이 오지 않는다면 page not Found 에러로 처리 되어야 합니다.

1.2 Django App의 urls에서 Views 함수 호출하기

1.1에서 Project의 urls.py 파일이 처음 들어오는 url을 구분하고 해당하는 App urls.py에 넘겨주었습니다. 이제 다른 url을 가지고 목적에 맞게 함수를 불러오면 됩니다.

조금 전 사용한 예를 가지고 한다면, http://127.0.0.1:8000/user/sign-in 이라는 url이 들어왔다고 해보겠습니다. user App에서의 urls.py는 sign-in만을 바라보고 처리해줍니다. 예제코드는 제가 구성한 urls.py 입니다.

#users/urls.py
from django.urls    import path
from .              import views

urlpatterns = [
    path('/sign-up',views.SignUpView.as_view()),
    path('/sign-in',views.SignInView.as_view()),
    path('/follow-user',views.FollowUserView.as_view()),
]

코드에서처럼 user라는 url 계층은 전혀 보이지 않습니다. 조금 전 말씀드린 것 처럼 urlpatterns라는 list는 sign-in이라는 패턴을 순차적으로 탐색합니다. 그 결과로 두 번째에 있는 패턴이 실행될 것 입니다. 그리고 path 함수에서 import된 같은 디렉토리의 views.py 파일의 SignInView 클래스의 as_view 함수가 실행되는 것 입니다.

이 이후부터는 Views의 역할입니다. 즉, Template을 사용하지 않는 MTV 구조입니다.

정리하자면 django.urls의 path 함수의 사용에 따라 두 가지 역할을 한다고 볼 수 있습니다.

path(route, view, kwargs=None, name=None)
1. path('user',include('users.urls'))
django urls의 include를 사용해, 다른 url로 넘겨주어 사용

2. path('/sign-in',view.SignInView.as_view(),name='login')
특정 패턴을 찾으면 해당 패턴에 대해 view 함수를 호출,
지정한 Template이 있으면 name=''으로 rendering이 가능

 

2. models.py

다음으로 models.py 입니다. models에서는 class로 데이터 모델을 작성합니다. 작성한 이 모델은 django-admin의 makemigrations와 migrate 명령어로 DB에 테이블로 저장됩니다.
class에서 만드는 데이터 모델은 makemigrations로 DDL(CREATE, DROP, ALTER..)로 상응됩니다. 즉, DB에 적용되는 SQL 구문이 나오고 이 SQL문을 DB에 적용시키는 것 입니다.

마찬가지로 언급한 Django Project 예시에서 models.py를 확인해보겠습니다.
posts라는 App에서의 models.py입니다.

# posts/models.py
from django.db import models

class Post(models.Model):
    user            =   models.ForeignKey('users.user',on_delete=models.CASCADE)
    post_text       =   models.CharField(max_length=1500)
    likes           =   models.IntegerField(default=0)
    image_url       =   models.URLField(max_length=1000)
    created_at      =   models.DateTimeField(auto_now_add=True)
    updated_at      =   models.DateTimeField(auto_now=True)

    class Meta:
        db_table = 'posts'

class Comment(models.Model):
    post            =   models.ForeignKey(Post,on_delete=models.CASCADE)
    comment_text    =   models.CharField(max_length=300)
    created_at      =   models.DateTimeField(auto_now_add=True)
    updated_at      =   models.DateTimeField(auto_now=True)

    class Meta:
        db_table = 'comments'

class Like(models.Model):
    post            =   models.ForeignKey(Post,on_delete=models.CASCADE)
    user            =   models.ForeignKey('users.user',on_delete=models.CASCADE)

    class Meta:
        db_table = 'likes'

우선 사용을 위해서 django.db의 models 모듈을 import 해줍니다.

그리고 class를 통해 각 model을 생성합니다. 중요한 것은 이 클래스가 models.Model을 상속받는 다는 것입니다. 그렇기 때문에 관련한 data format을 지정할 수 있는 것입니다.

Django의 model 관련해서 다양한 field와 기능들이 있습니다. 정말 많기 때문에 다 적기는 어렵고 생소하면서도 중요하다고 여겨지는 것만 적겠습니다.
공시문서에 models 관련 내용을 확인하실 수 있습니다.(아래 참조)

docs.djangoproject.com/ko/3.0/ref/models/fields/#module-django.db.models.fields.related

 

Model field reference | Django 문서 | Django

The Django Software Foundation deeply values the diversity of our developers, users, and community. We are distraught by the suffering, oppression, and systemic racism the Black community faces every day. We can no longer remain silent. In silence, we are

docs.djangoproject.com

2.1 Django Model ForeignKey(One to Many)

기본적으로 One to Many 또는 Many to Many 관계에서 사용됩니다.
Django Tutorial에도 있는 내용으로 질문과 객관식 답변이 있다면, 질문-답변 내용은 One to Many(1대 多) 입니다.

위에 적힌 예제코드와 같이 Comment(댓글)은 Post(작성글)과 One to Many의 관계에 있습니다. 또한 User(사용자)도 Post(작성글)과 One to Many 관계에 있습니다.

예제 코드로 models.ForeignKey(Post,on_delete=models.CASCADE) 이 구문이 바로 Foreign Key(참조키)의 설정입니다. Post라는 하나의 객체가 지워지면, 그에 해당하는 Comment 객체도 지워집니다.
Field 안의 arguments를 보시면 아시겠지만, 다양한 arguments를 줄 수 있습니다. 마치 옵션처럼 필요한 기능에 맞춰 설정할 수 있습니다.

2.2 Django Model ForeignKey(Many to Many)

 해당 내용에 대한 학습이 아직 진행되지 않아 추후 업데이트 하겠습니다.

2.3 class Meta로 테이블명 지정하기

예제코드에서 처럼 db에 저장될 때 이름을 지정할 수 있습니다. 지정하지 않는다면 이름은 'App name_Class name'으로 자동생성 됩니다. 위의 Post class의 경우도 별도 지정이 없다면, DB에서는 'posts.post'가 됩니다.

2.4 class 내에 함수 만들기

class 안에 각 class의 함수를 만들 수 있습니다. 객체를 호출할 때 자동으로 특정 문자열을 return 해주는 생성자 함수인 __str__ 의 경우, 별도 지정이 없다면 숫자로 된 id값만 return 해줍니다.

Django Tutorial의 예제를 확인해보겠습니다.

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

# Create your models here.
class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')
    def __str__(self):
        return self.question_text

class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)
    def __str__(self):
        return self.choice_text
    def was_published_recently(self):
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

Question class를 보면 __str__ 생성자 함수를 보면 호출 시, 객체의 question_text를 return 하게 하였습니다.

이 return을 비교해서 확인해 보면 다음과 같습니다.

# __str__ 함수 Deafault
>>> Question.objects.get(pub_date__year=current_year)
<Question: Question object (1)>

# __str__ 함수 설정 후
>>> Question.objects.get(pub_date__year=current_year)
<Question: What's up?>

그리고 예제 코드에서 Choice class의 was_published_recently 함수와 같이 별도 함수를 만들고 return 시켜 줄 수 있습니다.

 

반응형