[Django 07] API 연습

대화식 Python 쉘을 통해 Django API를 사용해볼 시간

$ python manage.py shell

Python 3.8.3 (default, May 18 2020, 11:25:01) 
[GCC 7.5.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from polls.models import Choice, Question
>>> Question.objects.all()
<QuerySet []>
>>> from django.utils import timezone
>>> q = Question(question_text="What's new?", pub_date=timezone.now())
>>> q
<Question: Question object (None)>
>>> q.save()
>>> q.id
1
>>> q.question_text
"What's new?"
>>> q.pub_date
datetime.datetime(2021, 4, 13, 12, 48, 15, 294472, tzinfo=<UTC>)
>>> q.question_text = "What's up?"
>>> q.save()
>>> Question.objects.all()
<QuerySet [<Question: Question object (1)>]>
>>> 

Question object (1)은 객체 표현에 도움이 되지 않는다.
polls/models.py 파일의 Question 모델을 수정하여, __str__() 메소드를 Question과 Choice에 추가해보자

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

__str__() 메소드를 추가하는 것은 객체의 표현을 대화식 프롬프트에서 편하게 보려는 이유 말고도, Django가 자동으로 생성하는 관리 사이트에서도 객체의 표현이 사용하기 때문이다.

>>> from polls.models import Choice, Question

# Make sure our __str__() addition worked.
>>> Question.objects.all()
<QuerySet [<Question: What's up?>]>

# Django provides a rich database lookup API that's entirely driven by
# keyword arguments.
>>> Question.objects.filter(id=1)
<QuerySet [<Question: What's up?>]>
>>> Question.objects.filter(question_text__startswith='What')
<QuerySet [<Question: What's up?>]>

# Get the question that was published this year.
>>> from django.utils import timezone
>>> current_year = timezone.now().year
>>> Question.objects.get(pub_date__year=current_year)
<Question: What's up?>

# Request an ID that doesn't exist, this will raise an exception.
>>> Question.objects.get(id=2)
Traceback (most recent call last):
    ...
DoesNotExist: Question matching query does not exist.

# Lookup by a primary key is the most common case, so Django provides a
# shortcut for primary-key exact lookups.
# The following is identical to Question.objects.get(id=1).
>>> Question.objects.get(pk=1)
<Question: What's up?>

# Make sure our custom method worked.
>>> q = Question.objects.get(pk=1)
>>> q.was_published_recently()
True

# Give the Question a couple of Choices. The create call constructs a new
# Choice object, does the INSERT statement, adds the choice to the set
# of available choices and returns the new Choice object. Django creates
# a set to hold the "other side" of a ForeignKey relation
# (e.g. a question's choice) which can be accessed via the API.
>>> q = Question.objects.get(pk=1)

# Display any choices from the related object set -- none so far.
>>> q.choice_set.all()
<QuerySet []>

# Create three choices.
>>> q.choice_set.create(choice_text='Not much', votes=0)
<Choice: Not much>
>>> q.choice_set.create(choice_text='The sky', votes=0)
<Choice: The sky>
>>> c = q.choice_set.create(choice_text='Just hacking again', votes=0)

# Choice objects have API access to their related Question objects.
>>> c.question
<Question: What's up?>

# And vice versa: Question objects get access to Choice objects.
>>> q.choice_set.all()
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
>>> q.choice_set.count()
3

# The API automatically follows relationships as far as you need.
# Use double underscores to separate relationships.
# This works as many levels deep as you want; there's no limit.
# Find all Choices for any question whose pub_date is in this year
# (reusing the 'current_year' variable we created above).
>>> Choice.objects.filter(question__pub_date__year=current_year)
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>

# Let's delete one of the choices. Use delete() for that.
>>> c = q.choice_set.filter(choice_text__startswith='Just hacking')
>>> c.delete()

모델의 관계에 대한 더 많은 정보는 관련 객체에 접근하기를 참조하세요. API에서 이중 밑줄(__) 을 이용해서 어떻게 필드를 조회할 수 있는지는 필드 조회를 읽어보세요.데이터베이스 API에 대한 자세한 내용을 보려면, 데이터베이스 API 레퍼런스를 읽어보세요.

[Django 06] SQLite 모델 만들기

이제 모델을 만들겁니다.

장고 프로젝트 폴더로 이동합니다.
아래 명령어를 실행합니다.
마이그레이트를 하는건데, 기본 설정을 잡아주는것으로 알고 있습니다.

python3 manage.py migrate

Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  No migrations to apply.

모델 만들기

모델 : 부가적인 메타데이터를 가진 데이터베이스의 구조(layout)
– 데이터에 관한 단 하나의, 가장 확실한 진리의 원천.
장고는 DRY(Dont Repeat Yourself) 원칙을 따름
http://wiki.c2.com/?DontRepeatYourself

Question과 Choice 모델을 만들거고, Question은 질문과 일자를 가지고 있을 겁니다.
Choice는 두개의 필드를 가집니다.(the text of the choice and a vote tally). 각 Choice는 Question과 관련있습니다.

polls/models.py 파일을 생성합니다.

from django.db import models

# 모델의 활성화
# 앱을 위한 데이터베이스 스키마 생성(CREATE TABLE)
# Question과 Choice 객체에 접근하기 위한 Python 데이터베이스 접근 API 생성

# 현재 프로젝트에게 polls 앱이 설치 되었다는것을 알려야 한다. (앱을 꼈다 뺐다 할수 있다.)
# 앱을 현재의 프로젝트에 포함시키기 위해서는 settings.py > INSTALLED_APPS 설정에 추가해야 한다. 
# PollsConfig 클래스는 polls/apps.py 파일 내에 존재 -> polls.apps.PollsConfig




# django.db.models.Model subclass
# 데이터베이스의 각 Field는 클래스의 인스턴스로 표현
    
# 각 필드 
# CharField는 문자 필드
# DateTimeField는 날짜와 시간(datetime) 필드 등

# 각 필드의 인스턴스 이름(question_text)은 
# 기계가 읽기 좋은 형식(machine-friendly format)의 데이터베이스 필드 이름은
# 필드명을 Python 코드에서 사용할 수 있으며, 데이터베이스에서는 컬럼명으로 사용 

# 필드 클래스의 생성자에 선택적인 첫번째 위치 인수를 전달하여 사람이 읽기 좋은(human-readable)
# 이름을 지정할 수도 있다. -> Question.pub_date

# 몇몇 Field 클래스는 인수가 필요합니다. (CharField의 경우 max_length)
# Field는 다양한 선택적 인수들을 가질수 있다.
class Question(models.Model):    
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')

#  ForeignKey를 사용한 관계설정
#  각각의 Choice가 하나의 Question에 관계된다는 정보.
#  question = models.ForeignKey(Question, on_delete=models.CASCADE)
class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

위와 같은 코드를 작성하고 다음 명령을 통해 변경시킨 모델을 migration으로 저장하고 싶다고 장고에게 알려준다.

python3 manage.py makemigrations polls

-> 결과
Migrations for 'polls':
  polls/migrations/0001_initial.py
    - Create model Question
    - Create model Choice

잘 보면 polls 밑에 migrations 폴더와 0001 이름의 모델이 생성되었다.

아래 코드를 실행해보면, 내부적으로 어떤 SQL 문장이 실행되는지 알수 있다.

python3 manage.py sqlmigrate polls 0001

-> 결과테테테ㅌ
BEGIN;
--
-- Create model Question
--
CREATE TABLE "polls_question" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "question_text" varchar(200) NOT NULL, "pub_date" datetime NOT NULL);
--
-- Create model Choice
--
CREATE TABLE "polls_choice" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "choice_text" varchar(200) NOT NULL, "votes" integer NOT NULL, "question_id" integer NOT NULL REFERENCES "polls_question" ("id") DEFERRABLE INITIALLY DEFERRED);
CREATE INDEX "polls_choice_question_id_c5b4b260" ON "polls_choice" ("question_id");
COMMIT;

테이블 이름은 앱 이름 + _ + 모델의 이름으로 자동 생성한다.
기본키 id도 자동 생성되고, 재지정이 가능하다.
외래 키 필드명에 “_id” 이름이 자동으로 추가된다. (재지정 가능)

python manage.py migrate

migrate 명령은 아직 적용되지 않은 마이그레이션을 모두 수집해 이를 실행하며(Django는 django_migrations 테이블을 두어 마이그레이션 적용 여부를 추적한다), 이 과정을 통해 모델에서의 변경 사항들과 뎅터베이스의 스키마의 동기화가 이루어진다.

마이그레이션은 매우 기능이 강력하여, 데이터베이스나 테이블을 수정하지 않고 모델의 반복적인 변경을 가능하게 해준다. 동작중인 데이터베이스를 자료 손실없이 업그레이드 하는 데 최적화 되어 있다.

모델의 변경을 만드는 세단계의 지침

1. (moles.py에서) 모델을 변경
2. python manage.py makemigrations 
 -> 변경사항에 대해 마이그레이션을 만듬
3. python manage.py migrate
 -> 변경 사항을 데이터베이스에 적용

manage.py 유틸리티로 어떤 일들을 할 수 있는지 django-admin 문서를 읽어보세요.

[Django 04] 데이터베이스 변경 가능 옵션

이제 장고에 디비를 붙여줄 시간이다.
Sqlite3이 기본으로 탑재되어 있으나, 다른놈들을 사용할수 있다고 한다.

settings.py

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

너무 깊게 들어가기 시작한게 아닌가 싶기도 한데..
일단 학습을 시작해보자.

공식 지원은 PostgreSQL, MariaDB, MySQL, Oracle, SQLite이다. Sqlite는 다 쓸만한데 복잡한거 하고 싶으면 커스터마이징 해서 알아서 잘 하라고 하네요.
3rd-party database backend로는 CockroachDB, Firebird, Microsoft SQL Server가 있답니다.

뭐 전 마리아가 맘에 드니.. 마리아를 볼께요.

MySQL 또는 MariaDB를 쓸 경우, DB API driver를 설치해야 합니다.(mysqlclient)
관련 자료

https://www.python.org/dev/peps/pep-0249/

https://pypi.org/project/mysqlclient/

생각보다 쉬워보이지 않는군요.
결국 전 그냥 Sqlite를 그냥 사용해 볼께요.

문서 읽다가 지쳐서 나가 떨어지느니.. 그냥 사용해보다가 필요해지면, 그때 더 자세히 볼께요.

[Django 03] include()와 path()

REST API를 쓰고 싶다는 생각이였는데, 어쩌다보니 장고로 들어와버렸다.
파이썬을 공부하다보니 자연스럽게 흘러들어왔는데, 초보이지만 나름 정리를 하면서 내용을 공유하고 싶어서 글을 작성한다.

내용은 튜토리얼을 정리한 수준이다.

어느정도 시간이 지나고 나면 좋은 글이 나올수도 있겠지..

"""mysite URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/3.1/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import include, path

urlpatterns = [
    # 최상위 URL에서 polls.urls 모듈을 바라보게 설정
    # include() 함수는 다른 URLconf들을 참조할 수 있도록 도와준다.
    # - URL의 그 시점까지 일치하는 부분을 잘라내고, 
    # 남은 문자열 부분을 후속 처리를 위해 include된 URLconf로 전달

    # path()는 route와 view, kwargs, name을 사용 가능
    # - route : URL 패턴을 가진 문자열. 일치하는 패턴을 찾을 때 까지 요청된 URL을 
    #   각 패턴과 리스트의 순서대로 비교한다.
    #   패턴들은 GET이나 POST의 매개 변수들, 혹은 도메인 이름을 검색하지 않는다.
    #   https://www.example.com/myapp/이 요청될 경우, URLconf는 myapp/만 바라본다.
    #   https://www.example.com/myapp/?page=3 이 요청될 경우에도 myapp/만 신경쓴다.
    # - view 
    #   일치하는 패턴을 찾으면, HttpRequest 객체를 첫번째 인수로 하고, 경로로부터 <캡쳐된> 값을
    #   키워드 인수로 하여 특정한 view 함수를 호출
    # - kwargs
    #   view에 전달될 사전형 데이터
    # - name 
    #   URL에 이름을 지으면, 템플릿을 포함한 어디서나 명확하게 참조할 수 있다.
    #   이 강력한 기능을 통해, 단 하나의 파일만 수정해도 project내의 모든 URL 패턴을 바꿀 수 
    #   있도록 도와준다.
    path('polls/', include('polls.urls')),
    path('admin/', admin.site.urls),
]

[Django 02] 시놀로지 도커에 설치하기

1. 터미널에서 apt update를 한다

역시나 내가 뭘 하면 오류가 발생하지. 도커를 내렸다 올리면 해결된다.

apt upgrade
apt update

2. python3.8 설치를 한다.

apt install python3.8

3. pip 설치를 한다.

apt install python3-pip
pip3 --version
pip3 install --upgrade pip

pip3 –version 명령어를 쳐서 python 몇 버전과 연결이 되어 있는지 확인한다.
현재 사용하는 파이썬 버전은 3.8.3인데, 3.6과 연결되어 있다. 이를 조치해주려 한다…

파이썬 제거하기..

sudo apt purge -y python2.7-minimal
sudo apt-get remove --purge python3.6

분명히 삭제했음에도 삭제가 되지 않는 현상이 있다면,

sudo apt autoremove

깔끔하게 제거되었다. ㄲㄲㄲ
다시 1번부터 재설치..

3. Django install

pip3 install Django

장고 실행은 아래글을 참고

[Django 01] 장고를 설치해보자.

실행방법

sudo python3 manage.py rumserver 0:포트번호

오류 발생 – Allowed Host

ALLOWED_HOSTS = [‘magpiebros.com’]


	

[Django 01] 장고를 설치해보자.

목표: restAPI를 제공할 수 있는 서버를 만드는 것이 목표이다.

이를 위해서는 웹서버가 필요하다.
Flask와 고민해보았으나, Django를 선택했다.

먼저 우분투 서버로 들어가서 다음과 같이 장고를 인스톨한다.

sudo python3 -m pip install Django

이제 튜토리얼을 따라서 샘플을 만들어보아야 겠다.
/var/www/html/로 이동해서 다음 명령을 실행한다.

sudo django-admin startproject mysite

다음과 같이 앱을 실행하면, html 폴더 이하에 해당 mysite 폴더가 생성된다.
해당 폴더에는 관련 소스들이 생성된다.
django나 test를 사용하여 프로젝트를 생성한다면 오류가 발생할 수 있으니 주의.

  • 관련글 : 학습해야 할 목록
  • https://docs.djangoproject.com/en/3.1/ref/django-admin/
  • https://docs.python.org/3/tutorial/modules.html#tut-packages
  • https://docs.djangoproject.com/en/3.1/topics/http/urls/

서버를 구동시켜보자

sudo python3 manage.py runserver

그리고, 웹 브라우저로 접속해보자

장고 웹 서버를 구동시켰다.
오늘의 목표는 여기까지.