Django framework part 1

** Creating a project **

Ở đây mình sẽ viết 1 vài bước cơ bản để setup 1 project Django. Bài viết được mình dịch từ documentation hướng dẫn của Django và khá cơ bản kể cả cho những bạn mới lần đầu tiếp xúc với Framework.

Nếu máy bạn chưa được cài đặt Django, hãy cài theo hướng dẫn ở đây.

Bạn có thể check xem Django đã được cài chưa và version bao nhiêu bằng dòng lệnh sau:

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

Bây giờ thì cd vào thư mục nơi bạn định lưu code và chạy dòng lênh sau.

$ django-admin.py startproject mysite

Mình sẽ làm được 1 project mysite như thế này

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

Cấu trúc của Django project sẽ như sau

  • mysite/ ngoài cùng là root directory chứa project.

  • manage.py Đây là 1 command-line utility cho phép mình thao tác với theo nhiều cách. Bạn có thể tìm hiểu về manage.py trong django-admin.pymanage.py.

  • mysite/ bên trong là gói cácpackage Python mình sẽ sử dụng cho project

  • mysite/__init__.pylà 1 file rỗng chỉ định việc cái đường dẫn này sẽ được xem như là 1 Python package.

  • mysite/settings.py Settings/configuration cho project Django

  • mysite/urls.py Khai báo URL cho project

  • mysite/wsgi.py entry-point cho tích hợp web server WSGI

Database setup

Phần tiếp theo sẽ là Database setup. Ở đây mình sẽ chỉnh sửa mysite/settings.py. Đây là 1 module dúng để cài đặt Django.

DB mặc định sẽ là SQLite. Nếu bạn muố sử dụng databse khác, thay đổi các thông số trong DATABASES 'default'

  • ENGINE – bạn có thể sử dụng 'django.db.backends.sqlite3', 'django.db.backends.postgresql_psycopg2', 'django.db.backends.mysql', hoặc 'django.db.backends.oracle'. Ngoài ra còn rất nhiều sự lựa chọn khác về DB.

  • NAME – Nếu bạn ko sử dụng SQLite thì bạn sẽ phải cấu hình thêm 1 số trường như USER, PASSWORD, HOST.

Ngoài ra, hãy chú ý là INSTALLED_APPS nằm ở top của các file. Nó chứa tên của tất cả các applications có thể sử dụng thành instance của Django.

INSTALLED_APPS chứa những app mặc định dưới đây.

  • django.contrib.admin – Site admin
  • django.contrib.auth – An authentication system. Hệ thống authentication
  • django.contrib.contenttypes – Hệ thống content types
  • django.contrib.sessions – Hệ thống session
  • django.contrib.messages – Hệ thống message
  • django.contrib.staticfiles – Hệ thống quản lý các file static

Django cung cấp cho chúng ta câu lệnh cho phép tạo các tables trong DB trước khi sử dụng chúng.

 python manage.py migrate

Lệnh migrate sẽ kiểm tra INSTALLED_APPS setting và tạo ra bất kì tables DB nào theo thông tin setting database trong file mysite/settings.py

** The development server **

Chạy dòng lệnh sau đây để chạy server.

python manage.py runserver

Đây là 1 web server gọn nhẹ được viết thuần bằng ngôn ngữ Python.

Tất nhiên bạn nên nhớ rằng đây là server sử dụng cho môi trường productions. webserver này ko được viết để dùng cho việc release các sản phẩm. Chạy http://127.0.0.1:8000/, bạn sẽ thấy page “Welcome to Django”. It worked !!!!!

** Creating models **

Mỗi application bạn viết bằng Django sẽ bao gồm 1 package Python được theo 1 chuẩn nào đấy. Django cung cấp 1 utility cho phép tạo tự động những cấu trúc cơ bản của app, do đó người lập trình viên sẽ có nhiều time tập trung hơn vào việc viết code.

Trong tutorial này, chúng ta sẽ tạo 1 poll app ngay cạnh manage.py. Làm như thế thì nó sẽ đc import như module level cao nhất của mysite.

Để tạo app, bạn hãy vào directory ngang hàng với manage.py và gõ command dưới đây

python manage.py startapp polls

directory polls sẽ được tạo như thế này:

polls/
    __init__.py
    admin.py
    migrations/
        __init__.py
    models.py
    tests.py
    views.py

Đầu tiên mình sẽ định nghĩa các models.

Chúng ta sẽ tạo 2 loại Models: Question và Choice. Trong Question mình sẽ có 2 trường question và ngày public. Trong Choice mình sẽ có 2 trường là nội dung của Choice và vote tally. Mỗi Choice sẽ liên kết với 1 Question.

Ta sẽ chỉnh sửa file polls/models.py như sau :


from `django.db` import models

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)

Mỗi model được thể hiện bằng 1 class được extend từ django.db.models.Model. Mỗi model có rất nhiều biến calss, vã mỗi thành phần trong đấy sẽ đại diện cho 1 field trong DB.

Mỗi trường thì được đại diện băng 1 instance của trườngFields, ví dụ CharField cho các flied về kí tự, DateTimeField cho thời gian. Việc này sẽ thông báo cho Django biết được type của dữ liệu tương ứng với mỗi trường.

Tên của mỗi instance Field (ví dụ question_text hoặc pub_date) là tên của trường.

1 vài Class của Trường sẽ yêu cầu arguments ví ụ như CharField yêu cầu max_length. Việc này sau này sẽ được sử dụng như validations.

1 trường có thể có rất nhiều argument. Ở đây chúng ta set giá trị default cho votes là 0.

Cuối cùng là việc định nghĩa relationship, sử dụng ForeignKey. Việc làm này sẽ cho phép Django biết được Choice nào liên kết với Question nào.

** Activating model **

Với đoạn code model ở trên Django có thể làm được những việc sau :

  • Tạo 1 schema DB cho app
  • Tạo API Pythonđể truy cập Question & Choice DB.

Nhưng trước hết chúng ta phải xác định với project là poll app đã được cài đặt.

Chỉnh file mysite/settings.py và thay đổi setting INSTALLED_APPS để nó chứa string polls như sau :


INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'polls',
)

Bây giờ, Django đã biết poll app đã được cài đăt. Tiếp, chạy đoạn lênh sau.

$ python manage.py makemigrations polls

Bạn sẽ thấy 1 đoạn thông báo như thế này ở terminal:

Migrations for 'polls':
  0001_initial.py:
    - Create model Question
    - Create model Choice
    - Add field question to choice

Bằng việc chạy makemigrations, Django sẽ hiểu là bạn đang tạo 1 sự thay đổi đến Model (trong trường này bạn đang create new) và sự thay đổi này sẽ được lưu như 1 migration.

Migration là cách mà Django lưu lại nhưng thãy đổi trong model (cũng như DB schema).

The sqlmigrate command takes migration names and returns their SQL:

Đây là command hỗ trợ bạn chạy migration và quản lý DB schema 1 cách tự động. Command

python manage.py sqlmigrate polls 0001

Bạn sẽ thấy 1 đoạn thông báo tương tự như thế này ở terminal:

BEGIN;
CREATE TABLE "polls_choice" (
    "id" serial NOT NULL PRIMARY KEY,
    "choice_text" varchar(200) NOT NULL,
    "votes" integer NOT NULL
);
CREATE TABLE "polls_question" (
    "id" serial NOT NULL PRIMARY KEY,
    "question_text" varchar(200) NOT NULL,
    "pub_date" timestamp with time zone 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")
    DEFERRABLE INITIALLY DEFERRED;

COMMIT;

Chú ý :

  • Format output ra chính xác sẽ dựa trên DB mà bạn đang sử dụng. Ví dụ ở trên được sử dụng cho PostgreSQL.
  • Tên của table sẽ được sinh ra tự động bằng việc kết hợp tên của app (polls) và tên ko viết hoa của models (question & choice)
  • Primary keys (IDs) được add tự động (Bạn có thể override lại được key)
  • Theo convention thì tên của những foreign key sẽ được ghép thêm "_id"

Bây giờ chạy migrate 1 lần nữa để tạo những tables model vào DB:

$ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, contenttypes, polls, auth, sessions
Running migrations:
  Applying <migration name>... OK

Lệnh migrate sẽ lấy tất cả các migration chưa được apply và chạy chúng lại vào DB.

Migration rất mạnh và sẽ cho phép bạn thay đỏi model rất nhiều lần trong quá trình bạn phát triển project mà ko cần phải xóa DB hay tables cũng như tạo mới. Nó sẽ upgrading DB của minh 1 cách "live" mà ko hề mất data. Dưới đây là 3 bước khi thay đổi model :

  • Thay đổi models (trong models.py).
  • Chạy python manage.py makemigrations để tạo migrations cho những thay đổi.
  • Chạy python manage.py migrate để apply những thay đổi đo vào DB.

** Playing with the API **

Bây giờ thì bắt đầu làm quen với shell Pytho. Để chạy Python shell, mình chạy command dưới đây :

$ python manage.py shell

Khi đã vào shell, sử dụng những lệnh sau cho DB API:

>>> from polls.models import Question, Choice   # Import những class model mà mình vừa mới viết.

>>> Question.objects.all()
[]

# Tạo Question mới.
>>> from django.utils import timezone
>>> q = Question(question_text="What's new?", pub_date=timezone.now())

# Lưu object vào DB.
>>> q.save()

# kiểm tra id của object
>>> q.id
1

# Truy cập 1 trường model thông qua Python
>>> q.question_text
"What's new?"
>>> q.pub_date
datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=<UTC>)

# Thay giá trị bằng việc thay các thuộc tính sau đấy gọi hàm save().
>>> q.question_text = "What's up?"
>>> q.save()

# objects.all() hiển thị tất cả các object trong DB
>>> Question.objects.all()
[<Question: Question object>]

Ở đây bạn phải sửa bằng cách chỉnh sửa Question model (trong file polls/models.py) và add thêm __str __ () cho cả Question và Choice:

polls/models.py

from django.db import models

class Question(models.Model):
    def __str__(self):
        return self.question_text

class Choice(models.Model):
    def __str__(self):
        return self.choice_text

Việc add phương thức __str__() vào model rất quan trọng.


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)

Chú ý rằng việc import datetime từ django.utils import timezone là để tham chiếu đến module datetime chuẩn của Python và time-zone-related utilities của Django trong django.utils.timezone.

Lưu những thay đổi và chạy shell Python mới bằng việc chạy python manage.py shell 1 lần nữa.

>>> from polls.models import Question, Choice

# Check xem việc add thêm __str__() có hđộng hay ko
>>> Question.objects.all()
[<Question: What's up?>]

# Tìm kiếm trong DB bằng keyword arguments.
>>> Question.objects.filter(id=1)
[<Question: What's up?>]
>>> Question.objects.filter(question_text__startswith='What')
[<Question: What's up?>]

# Tìm question được publish bằng year.
>>> from django.utils import timezone
>>> current_year = timezone.now().year
>>> Question.objects.get(pub_date__year=current_year)
<Question: What's up?>

# Request đến 1 ID ko tồn tại.
>>> Question.objects.get(id=2)
Traceback (most recent call last):
    ...
DoesNotExist: Question matching query does not exist.

# shortcut để tim kiếm bằng primary-key
 Question.objects.get(id=1).
>>> Question.objects.get(pk=1)
<Question: What's up?>

# Check xem phương thức custom của mình có hđộng ko.
>>> q = Question.objects.get(pk=1)
>>> q.was_published_recently()
True

>>> q = Question.objects.get(pk=1)

# Hiển thị bất kì choices nào từ object set liên kết
>>> q.choice_set.all()
[]

# Tạo 3 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)

# Object Choice sẽ có API có thể truy cập đến Question.
>>> c.question
<Question: What's up?>

# và ngược lại question có thể truy cập lại choice
>>> q.choice_set.all()
[<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]
>>> q.choice_set.count()
3

# Bạn có thể sử dụng double underscores để tách biệt ra 2 quan hệ
# Ví dụ tìm tất cả các Choices cho bất kì câu hỏi nào mà có pub_date là năm nay
# (tái sử dụng 'current_year').
>>> Choice.objects.filter(question__pub_date__year=current_yeare
[<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]

# Xóa 1 choice bằng cách dùng delete()
>>> c = q.choice_set.filter(choice_text__startswith='Just hacking')
>>> c.delete()

Để tìm hiểu thêm về quan hệ giữa Model hãy đọc về Accessing related objects. Để tìm hiểu về DB API, xem tài liệu về Database API reference.

Nguồn: https://docs.djangoproject.com/en/1.7/intro/tutorial01/

Github: https://github.com/duongichi/django_project