티스토리 뷰

*장고가 깔려있는지 확인을 해보자.

$ python -c "import django; print(django.get_version())"

1.8.3


프로젝트 생성하기
-코드를 넣고 싶은 디렉토리에 위치한 후 다음의 커맨드를 입력한다.

$ django-admin startproject mysite


커맨드 입력 후 현재 디렉토리에 다음과 같은 구조의 프로젝트가 생성된다.

Let’s look at what startproject created:

mysite/
    manage.py
    mysite/
        __init__.py
        settings.py
        urls.py
        wsgi.py

These files are:

  • The outer mysite/ root directory is just a container for your project. Its name doesn’t matter to Django; you can rename it to anything you like.
  • manage.py: A command-line utility that lets you interact with this Django project in various ways. You can read all the details about manage.py in django-admin and manage.py.
  • The inner mysite/ directory is the actual Python package for your project. Its name is the Python package name you’ll need to use to import anything inside it (e.g. mysite.urls).
  • mysite/__init__.py: An empty file that tells Python that this directory should be considered a Python package. (Read more about packages in the official Python docs if you’re a Python beginner.)
  • mysite/settings.py: Settings/configuration for this Django project.  Django settings will tell you all about how settings work.
  • mysite/urls.py: The URL declarations for this Django project; a “table of contents” of your Django-powered site. You can read more about URLs in URL dispatcher.
  • mysite/wsgi.py: An entry-point for WSGI-compatible web servers to serve your project. See How to deploy with WSGI for more details.


*우선 데이터베이스를 셋업해야한다.
mysite.settings.py로 가보자.
거기서 DATABASES 의 default 를 바꿔야하는데, 나는 mysql을 쓸꺼기에

 'ENGINE': 'django.db.backends.mysql',

을 해주고,
NAME은 사용할 database의 name을 입력해야한다. 이것은 database file의 전체 경로이다.

-이 경로를 찾는 방법(http://stackoverflow.com/questions/6232238/where-is-the-mysql-table-data-stored-mac)
1. root 계정으로 mysql 접속
$ mysql -u root -p 
mysql> show variables where Variable_name = 'datadir';

mysql> show variables where Variable_name = 'datadir';

+---------------+-----------------------+

| Variable_name | Value                 |

+---------------+-----------------------+

| datadir       | /usr/local/var/mysql/ |

+---------------+-----------------------+


경로는 /usr/local/var/mysql/ 이라고 한다.


등등등

DATABASES = {

    'default': {

        'ENGINE': 'django.db.backends.mysql',

        'NAME': 'junkyu',

        'USER': 'dev',

        'PASSWORD': '0000',

        'HOST': 'localhost',

        'PORT': '',

    }

}


일단 확실하진 않지만 이렇게 설정하였다.
자세한 내용은 
https://docs.djangoproject.com/en/1.8/ref/settings/#std:setting-DATABASES
를 확인 할것.

그리고 TIME_ZONE도 바꿔야하는데, 

https://docs.djangoproject.com/en/1.8/ref/settings/#std:setting-TIME_ZONE

현재 시스템의 시간과 일치 하여야 한다.

TZ List: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones

내 시스템의 시간대는 서울이므로

KR+3733+12658Asia/Seoul+09:00+09:00

TIME_ZONE = 'Asia/Seoul'

'Asia/Seoul'을 이용한다.

우리는 테이블을 쓰기 위해 테이블들을 생성할 필요가 있다. 이걸 하기위해 다음의 커맨드를 입력하자.

$ python manage.py migrate

그런데 에러가 난다.

django.core.exceptions.ImproperlyConfigured: Error loading MySQLdb module: No module named MySQLdb

It looks like you don't have the python mysql package installed, try:

$pip install mysql-python

or if not using a virtual environment(on *nix hosts):

$sudo pip install mysql-python

그 후 다시 커맨드를 입력하자.

$ python manage.py migrate

Operations to perform:

  Synchronize unmigrated apps: staticfiles, messages

  Apply all migrations: admin, contenttypes, auth, sessions

Synchronizing apps without migrations:

  Creating tables...

    Running deferred SQL...

  Installing custom SQL...

Running migrations:

  Rendering model states... DONE

  Applying contenttypes.0001_initial... OK

  Applying auth.0001_initial... OK

  Applying admin.0001_initial... 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 sessions.0001_initial... OK

EminentStarui-MacBook-Pro:mysite eminentstar$ 


The 'migrate' command looks at the INSTALLED_APP setting and create s any necessary database tables according to the database settings in your mysite/settings.py file and the database migrations shipped with the app. 

mysql> show tables;

+----------------------------+

| Tables_in_junkyu           |

+----------------------------+

| auth_group                 |

| auth_group_permissions     |

| auth_permission            |

| auth_user                  |

| auth_user_groups           |

| auth_user_user_permissions |

| django_admin_log           |

| django_content_type        |

| django_migrations          |

| django_session             |

| test                       |

+----------------------------+

11 rows in set (0.00 sec)


mysql> 


*The development server
mysite 디렉터리의 밖으로 나오고(manage.py가 있는 곳으로 이동하라.)  다음의 커맨드를 입력하라.

$ python manage.py run server

그러면 다음의 텍스트들을 볼 수 있을 것이다.

Performing system checks...


System check identified no issues (0 silenced).

July 29, 2015 - 08:34:52

Django version 1.8.3, using settings 'mysite.settings'

Starting development server at http://127.0.0.1:8000/

Quit the server with CONTROL-C.

방금 장고 개발 서버를 시작했다.(A lightweight Web server written purely in Python)

간단한 웹서버로 빠르게 개발이 가능하고, Apache와 같은 production server를 configuring하는 것과 고군분투 할 필요가 없다.(production할 준비가 되기 전까지는)

Now's a good time to note: don't use this server in anything resembling a production environment. It's intended only for use while developing.(We're in the business of making Web frameworks, not Web servers.)

방금 서버가 실행 됬고, http://127.0.0.1:8000을 웹 브라우저와 함꼐 방문하라. 그럼   "Welcome to Django" 페이지가 뜰 것 이다. (라이트 블루 파스텔과 함께)


디폴트로 runserver 커맨드는 개발 서버를 내부 IP상에서 8000 포트에서 시작한다.

만약 포트를 바꾸고 싶다면 커맨드 라인 매개변수를 넘겨야한다.

$ python manage.py runserver 8080

서버의 IP도 바꾸고 싶다면 바꿀 아이피를 포트 이전에 pass시켜야 한다.

$ python manage.py runserver 0.0.0.0:8000



*Creating models
이제 우리의 환경(a "project")가 set up 됬고, you're set to start doing work.

내가 장고에서 만드는 각각의 앱은 파이썬 패키지로 구성되어있는데 그것은 특정한 convention을 따른다. 장고는 기본 directory structure를 자동적으로 발생시킨다. 그래서 우리는 directory의 생성보다는 writing code에 중점을 둬야한다.

우리의 앱들은 나의 Python path위의 어디에도 살 수 있다. 이 튜토리얼에선, 앱이 그것의 가장 최상위 레벨 모듈로서 import될 수 있게 하기 위해서, 우리는 우리의 poll app을 manage.py의 바로 옆에 생성할 것이다.

앱을 생성하기 위해 manage.py와 같은 디렉토리에 있는지 확인 하고, 다음의 커맨드를 입력하라.

$ python manage.py startapp polls


이것은 디렉토리 polls 를 생성할 것인데 이것은 다음의 구조를 지닌다.

polls

├── __init__.py

├── admin.py

├── migrations

│   └── __init__.py

├── models.py

├── tests.py

└── views.py


우리의 간단한 poll 앱에서, 우리는 두개의 model을 생성할 것이다. Question 과 Choice.
Question은 question과 a publication date를 가진다. Choice는 2개의 필드를 가지는데 the text of the choice and a vote tally.
각각의 Choice는 a Question과 연관이 있다.

Edit polls/models.py

from django.db import models


# Create your models here.

class Question(models.Model):

  question_text = models.CharField(max_length=200)

  pub_date = models.DateTimeField('date published')

  

class Choice(models.Model):

  question = models.ForeignKey(Question)

  choice_text = models.CharField(max_length=200)

  votes = models.IntegerField(default=0)


각 모델은 클래스로 표현이 되는데 django.db.models.Model의 서브클래스이다.
각 모델은 많은 클래스 변수를 가지고 있는데 각각의 변수는 모델에서 데이터베이스의 필드를 나타낸다.

각 필드는 Field클래스의 객체들에 의해 표현되는데, character fields를 위한 CharField와  datatimes를 위한 DateTimeField가 있다. 이것은 장고에게 각각의 필드가 무슨 타입의 데이터를 홀드하고 있는지 말해준다.

어떤 Field 클래스들은 매개변수를 요구로 한다. 예를 들면, CharField는 max_length가 필요하다.
또한 Field는 다양한 선택적 매개변수를 가질 수 있다. votes 는 default 가 0으로 설정되었다.

마지막으로 주목해야할게, 관계가 정의 되었는데 ForeignKey를 이용하여. 이것은 장고에게 각각의 Choice는 하나의 Question에 관련이 있다는 것을 말해준다. 장고는 모든 흔한 데이터베이스 관계를 지원한다. (일대다, 다대다, 일대일)

*Activating models
저 위의 the small bit of model code는 장고에게 많은 정보를 준다. 장고는
- 이 앱을 위한 데이터베이스 스키마를 생성할 수 있다.
- Question과  Choice 객체들이 접근을 위한 Python database-access API를 생성 할 수 있다.

그러나, 먼저 우리는 우리의 프로젝트에게 polls 앱이 설치 되었다는 것을 알려줄 필요가 있다.

Philosophy

Django apps are “pluggable”: You can use an app in multiple projects, and you can distribute apps, because they don’t have to be tied to a given Django installation.


mysite/settings.py 파일을 다시 수정하라. INSTALLED_APPS 부분을 'polls'가 포함되도록 변경해라.

INSTALLED_APPS = (

    'django.contrib.admin',

    'django.contrib.auth',

    'django.contrib.contenttypes',

    'django.contrib.sessions',

    'django.contrib.messages',

    'django.contrib.staticfiles',

    'polls',

)


이제 장고는 polls 앱이 포함되었다는 걸 안다. 그리고 다른 커맨드를 실행해보자.

$ python manage.py makemigrations polls

Migrations for 'polls':

  0001_initial.py:

    - Create model Choice

    - Create model Question

    - Add field question to choice


makemigrations 를 실행시킴으로써, 우리는 장고에게 우리가 우리의 모델들에 몇가지 변화를 주었다는 것을 말하고 있다. 그리고 You'd like the changes to be stored as a migration.

Migrations는 장고가 우리의 모델을 저장하는 방법이다. 이들은 단지 파일이며 원한다면 우리는 이것을 읽을 수 있다. 0001_initial.py 가 그 파일이며, 우리는 이것을 다 읽을 필요는 없고, 만일의 상황에 우리가 읽고 싶다면 언제나 읽어서 장고가 어덯게 그것을 바꾸는지 확인할 수 있다.

또한 migrations를 수행하며, 우리의 데이터베이스 스키마를 자동적으로 관리하는 커맨드가 있다. 그것은 migrate라고 불린다. 
이것에 대해 설명하기전에, migration이 실행시키는 SQL을 확인해보자. sqlmigrate 커맨드는 migration 이름을 취하며 그들의 SQL을 반환한다.

$ python manage.py sqlmigrate polls 0001

BEGIN;

CREATE TABLE `polls_choice` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `choice_text` varchar(200) NOT NULL, `votes` integer NOT NULL);


CREATE TABLE `polls_question` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `question_text` varchar(200) NOT NULL, `pub_date` datetime(6) NOT NULL);


ALTER TABLE `polls_choice` ADD COLUMN `question_id` integer NOT NULL;

ALTER TABLE `polls_choice` ALTER COLUMN `question_id` DROP DEFAULT;

CREATE INDEX `polls_choice_7aa0f6ee` ON `polls_choice` (`question_id`);

ALTER TABLE `polls_choice` ADD CONSTRAINT `polls_choice_question_id_246c99a640fbbd72_fk_polls_question_id` FOREIGN KEY (`question_id`) REFERENCES `polls_question` (`id`);


COMMIT;



  • 정확한 아웃풋을 우리가 쓰고있는 데이터베이스에 따라 변할 수 있다.
  • 테이블 명은 자동적으로 우리의 앱이름(polls)와 결합되어 생성된다.
  • Primary keys(IDs)는 자동적으로 추가된다.
  • By convention, 장고는 "_id"를 외래키 필드명에 추가한다.
  • 외래키 관계는 FOREIGN KEY constraint에 의해 명확하게(explicit) 생성된다.
  • 우리가 쓰고있는 데이터베이스에 맞춰서 데이터베이스 특수 필드 타입이 자동적으로 조절된다.
  • sqlmigrate 커맨드는 사실상 우리의 DB에 migration을 실행하지 않는다. 이것은 단지 장고가 어떤 sql이 필요되어지는지를 우리가 볼 수 있게 한다.

만약 관심이 있다면, "python manage.py check"를 실행시켜 봐라.
이것은 migration을 생성하는 것, db에 접근하는 것을 제외한 우리 프로젝트의 어떤 문제라도 체크한다. 

$ python manage.py check;

System check identified no issues (0 silenced).



이제 migrate 커맨드를 실행하여 우리의 db에 models를 생성해보자

$ python manage.py migrate

Operations to perform:

  Synchronize unmigrated apps: staticfiles, messages

  Apply all migrations: admin, contenttypes, polls, auth, sessions

Synchronizing apps without migrations:

  Creating tables...

    Running deferred SQL...

  Installing custom SQL...

Running migrations:

  Rendering model states... DONE

  Applying polls.0001_initial... OK


이 migrate 커맨드는 적용되지 않았던 모든 migration을 실행한다.(django는 django_migrations 라는 특수 테이블을 이용하여 어느 것이 적용되었는지 추적한다.)
필수적으로, 우리가 우리의 디비 스키마와 모델에 가했던 변화를 동기화하는 것들도 실행한다.

Migrations는 매우 강력하고 우리가 데이터베이스나 테이블을 지우고 새로 안만들어도 될게끔 바꾸는 걸 허용한다. 
자세한 설명은 나중에 하고 making model changes 에 대한 3 step guide를 기억하라.
  • Change your models (in models.py)
  • Run "python manage.py makemigrations" to create migrations for those changes.
  • Run "python manage.py migrate" to apply those changes to the database.
이렇게 migrations를 만들고 적용하는 분리된 커맨드가 있는 이유는 우리가 우리의 migrations를 우리의 version control system에 적용하고 그것을 우리의 App에 이동시켜야 할 것이기 때문이다. 이것은 우리의 개발을 쉽게 할 뿐만 아니라, production시 다른 개발자들에게도 유용하다.

Read the django-admin documentation for full information on what the manage.py utility can do.


*Playing with the API

자~ 이제 interactive Python shell로 가서 free API Django와 함께 놀아보자.

$ python manage.py shell

'python' 커맨드를 수행하는 대신 이것을 쓰는데, manage.py는 DJANGO_SETTINGS_MODULE 환경 변수를 설정하기 때문이다. 이 환경 변수는 django에게 python import path to your mysite/settings.py file를 준다.

자 쉘상에서 database API를 탐험해보자.

>>> from polls.models import Question, Choice   # Import the model classes we just wrote.

# No questions are in the system yet.
>>> Question.objects.all()
[]

# Create a new Question.
# Support for time zones is enabled in the default settings file, so
# Django expects a datetime with tzinfo for pub_date. Use timezone.now()
# instead of datetime.datetime.now() and it will do the right thing.
>>> from django.utils import timezone
>>> q = Question(question_text="What's new?", pub_date=timezone.now())

# Save the object into the database. You have to call save() explicitly.
>>> q.save()

# Now it has an ID. Note that this might say "1L" instead of "1", depending
# on which database you're using. That's no biggie; it just means your
# database backend prefers to return integers as Python long integer
# objects.
>>> q.id
1

# Access model field values via Python attributes.
>>> q.question_text
"What's new?"
>>> q.pub_date
datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=<UTC>)

# Change values by changing the attributes, then calling save().
>>> q.question_text = "What's up?"
>>> q.save()

# objects.all() displays all the questions in the database.
>>> Question.objects.all()
[<Question: Question object>]


mysql> select * from polls_question;

+----+-------------------+----------------------------+

| id | question_text     | pub_date                   |

+----+-------------------+----------------------------+

|  1 | What's renew????? | 2015-07-30 16:21:02.316926 |

+----+-------------------+----------------------------+

1 row in set (0.00 sec)


잠깐만....[<Question: Question object>] 이건 완전 도움이 되지 않는 객체의 표현 방식 이다. 그래서 이것을 Question Model을 수정함으로써 고쳐보자.(in the polls/models.py file) 그리고 __str__() 메소드를 Question and Choice 두 모델에 추가해보자.

from django.db import models


# Create your models here.

class Question(models.Model):# Inherited 'django.db.models.Model'

  question_text = models.CharField(max_length=200)

  pub_date = models.DateTimeField('date published')

  def __str__(self):          # __unicode__ on Python 2

    return self.question_text


class Choice(models.Model):

  question = models.ForeignKey(Question)

  choice_text = models.CharField(max_length=200)

  votes = models.IntegerField(default=0)

  def __str__(self):          # __unicode__ on Python 2

    return self.choice_text

대화형 프롬프트에서 다룰때 우리의 편리함을 위함 뿐만 아니라, 객체의 표현이 Django's automatically-generated admin을 통해 사용되기 때문에 __str__ 메소드를 우리의 모델에 추가하는 것은 중요하다. 

__str__ or __unicode__?

On Python 3, it’s easy, just use __str__().

On Python 2, you should define __unicode__() methods returning unicodevalues instead. Django models have a default __str__() method that calls__unicode__() and converts the result to a UTF-8 bytestring. This means that unicode(p) will return a Unicode string, and str(p) will return a bytestring, with characters encoded as UTF-8. Python does the opposite: object has a __unicode__ method that calls __str__ and interprets the result as an ASCII bytestring. This difference can create confusion.

If all of this is gibberish to you, just use Python 3.

Note these are normal Python methods. Let’s add a custom method, just for demonstration:

polls/models.py

import datetime from django.db import models from django.utils import timezone class Question(models.Model): # ... def was_published_recently(self): return self.pub_date >= timezone.now() - datetime.timedelta(days=1)


Save these changes and start a new Python interactive shell by running python manage.pyshell again:

>>> from polls.models import Question, Choice

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

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

# 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()
[<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)
[<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()

mysql> select * from polls_choice;

+----+--------------------+-------+-------------+

| id | choice_text        | votes | question_id |

+----+--------------------+-------+-------------+

|  1 | Not much           |     0 |           1 |

|  2 | The sky            |     0 |           1 |

|  3 | Just hacking again |     0 |           1 |

+----+--------------------+-------+-------------+

3 rows in set (0.01 sec)


// c.delete() 후에


mysql> select * from polls_choice;

+----+-------------+-------+-------------+

| id | choice_text | votes | question_id |

+----+-------------+-------+-------------+

|  1 | Not much    |     0 |           1 |

|  2 | The sky     |     0 |           1 |

+----+-------------+-------+-------------+

2 rows in set (0.00 sec)



























댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함