Daily Archives: 24/03/2016

Django – Hệ thống Admin

Trong phần này chúng ta sẽ tìm hiểu về hệ thống Admin có sẵn trong Django.

Thường thì khi viết một ứng dụng nào đó, chẳng hạn như website bán hàng, blog, web tin tức, diễn đàn…v.v. ngoài các trang hiển thị thông tin thì chúng ta còn phải xây dựng một trang nữa là trang admin, trong đó lại bao gồm nhiều trang nhỏ hơn như thêm, sửa, xóa bài viết, cài đặt trang web… việc làm các trang này khá đơn giản, không cầu kỳ nhưng cũng rất nhàm chán. Chính vì vậy Django cung cấp sẵn một trang admin cho riêng chúng ta.

 Tạo user

Để có thể đăng nhập vào admin thì trước hết chúng ta phải tạo một tài khoản admin đã vì Django không tạo sẵn cho chúng ta khi tạo project.

C:\Project\mysite>python manage.py createsuperuser

Để tạo tài khoản thì chúng ta chạy file manage.py với tham số createsuperuser.

Username: admin
Email address: admin@example.com
Password:
Password (again):
Superuser created successfully.

Tiếp theo bạn cung cấp username, passwordemail là xong.

 Truy cập trang admin

Capture

Để truy cập vào trang admin thì bạn chỉ cần thêm /admin vào đường dẫn trang chủ là được.

Capture

Sau đó bạn đăng nhập bằng usernamepassword mà chúng ta đã tạo hồi nãy là sẽ được chuyển đến giao diện admin.

Mặc định Django đã bật chức năng dịch nên có thể trang admin sẽ được hiển thị bằng ngôn ngữ mà bạn dùng trên trình duyệt.

Tại trang admin chúng ta có thể thao tác với 2 bảng là UserGroup. Các bảng QuestionChoice mà chúng ta đã tạo ra không được hiển thị ở đây là vì chúng ta chưa đăng ký các bảng đó với trang admin.

from django.contrib import admin

# Register your models here.
from .models import Question, Choice

admin.site.register(Question)
admin.site.register(Choice)

Để đăng ký các bảng (hay các mô hình) với admin thì chúng ta chỉ cần dùng phương thức admin.site.register() trong file admin.py mà Django đã tạo cho chúng ta.

Capture

Sau khi đã đăng kí xong thì 2 bảng QuestionChoice sẽ hiện ra trong giao diện admin.

Giao diện admin mặc định của Django rất đơn giản, bạn có thể thực hiện thêm, sửa, xóa các bảng này một cách dễ dàng.

Django – Model

Trong phần này chúng ta sẽ học cách tạo các Model để có thể tương tác với cơ sở dữ liệu.

Thiết lập cơ sở dữ liệu

Trong thư mục mysite chứa một file tên là settings.py, file này chứa các thông tin cấu hình server của bạn.

Mặc định thì Django server sử dụng cơ sở dữ liệu SQLite, và trong bài này mình cũng sẽ sử dụng SQLite cho đơn giản, nếu bạn dùng SQLite thì bạn không cần quan tâm đến việc tạo CSDL và cấu hình user, nhưng nếu bạn muốn sử dụng CSDL khác thì trong file settings.py, bạn tìm đến đối tượng DATABASES và thay đổi các giá trị sau:

  • ENGINE: tên module dành cho từng CSDL, mặc định sử dụng SQLite
    • django.db.backends.sqlite3 – cơ sở dữ liệu  SQLite
    • django.db.backends.postgresql – cơ sở dữ liệu PostgreSQL
    • django.db.backends.mysql – cơ sở dữ liệu MySQL
    • django.db.backends.oracle – cơ sở dữ liệu Oracle
  • NAME: tên CSDL, mặc định là file db.sqlite3 được tạo ra ở thư mục gốc của server. Nếu bạn không dùng CSDL SQLite thì bạn phải tạo CSDL với tên trùng với NAME trong CSDL mà bạn dùng (bằng câu lệnh CREATE DATABASE <name>)

Ngoài ra nếu bạn không dùng SQLite thì bạn cũng phải cung cấp thêm các thông tin USER, PASSWORD, HOST nữa và user phải có quyền truy cập CSDL cũng như một số quyền như ghi, xem…

Trong file settings.py còn có một list có tên là INSTALLED_APPS, mặc định khi tạo một project, Django cung cấp cho chúng ta một số ứng dụng thường dùng trong list này. Trong bài sau chúng ta sẽ dùng một ứng dụng trong list này đó là django.contrib.admin.

Mỗi ứng dụng trong list này sẽ giúp Django tìm các model để tạo bảng tương ứng trong file CSDL, nhưng khi tạo project thì các bảng này không tự động được tạo trong file db.sqlite3, để tạo các bảng này thì chúng ta chạy lệnh sau:

C:\Project\mysite>python manage.py migrate

Lệnh migrate sẽ tìm các module được liệt kê trong list INSTALLED_APPS (trong file mysite/settings.py) và tạo các bảng CSDL tương ứng.

Tạo mô hình dữ liệu cho ứng dụng

Mô hình ở đây giống như lớp trong lập trình hướng đối tượng hoặc Model trong mô hình MVC vậy thôi, không có gì khó hiểu cả 🙂

Mặc định khi tạo một ứng dụng web trong một project Django thì Django đã tạo sẵn cho chúng ta một file có tên là models.py để chúng ta khai báo các mô hình trong này rồi nhưng bạn cũng có thể viết trong các file khác nếu thích.

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, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

Chúng ta sẽ tạo 2 mô hình (2 lớp…) là QuestionChoice.

class Question(models.Model):
...
class Choice(models.Model):

Mỗi mô hình được tạo ra phải được kế thừa từ lớp django.db.models.Model.

question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
...
votes = models.IntegerField(default=0)

Mỗi thuộc tính trong mô hình được kế thừa từ một lớp Field, đây là một lớp ảo trong Django, lớp này lại có nhiều lớp kế thừa khác đại diện cho mỗi kiểu dữ liệu ví dụ như CharField là kiểu text, DateTimeField là kiểu DateTime

Tham số max_length là số lượng ký tự tối đa, đây là tham số bắt buộc phải có. Các tham số còn lại như default… là tham số tùy chọn, không có cũng được.

question = models.ForeignKey(Question, on_delete=models.CASCADE)

Ngoài các kiểu dữ liệu thường dùng thì chúng ta còn có kiểu khóa ngoại được định nghĩa trong lớp ForeignKey, tham số đầu tiên là bảng mà khóa ngoại này tham chiếu tới, on_delete=models.CASCADE tức là khi dữ liệu trong bảng cha có sự thay đổi thì dữ liệu trong bảng con cũng sẽ thay đổi theo, chẳng hạn như bản ghi trong bảng Question bị xóa thì các bản ghi trong bảng Choice có tham chiếu tới bản ghi trong bảng Question này cũng sẽ bị xóa.

Tạo bảng trong CSDL từ Model

Sau khi đã tạo các lớp mô hình trong Python, Django sẽ nhìn các thuộc tính trong từng lớp để tạo các bảng tương ứng trong CSDL và tạo thêm các lớp mới trong Python cung cấp các hàm để bạn thao tác với các bảng trong CSDL.

INSTALLED_APPS = [
    'polls.apps.PollsConfig',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

Để Django tạo các bảng mới trong CSDL thì chúng ta phải khai báo trước trong list INSTALLED_APPS đã bằng cách thêm dòng polls.apps.PollsConfig.

C:\Project\mysite>python manage.py makemigrations polls

Tiếp theo bạn chạy lệnh makemigration polls để báo cho Django biết là bạn đã thay đổi một số mô hình, ở đây là thêm 2 lớp mới trong gói polls.

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

Django sẽ tạo một file python để lưu các thông tin về sự thay đổi này, ở đây là file 0001_initial.py.

C:\Project\mysite>python manage.py migrate
Operations to perform: 
Apply all migrations: admin, contenttypes, polls, auth, sessions
Running migrations:
Rendering model states... DONE
Applying polls.0001_initial... OK

Chúng ta chạy lại lệnh migrate để Django cập nhật lại CSDL. Lúc này CSDL chúng ta sẽ có thêm 2 bảng mới là polls_choicepolls_question (tên bảng được đặt theo cú pháp <tên package>_<tên lớp>).

Thao tác với các bảng

Sau khi Django đã tạo các bảng bạn có thể bắt đầu thực hiện các công việc thường dùng như thêm-sửa-xóa… bản ghi.

C:\Project\mysite>python manage.py shell

Bạn có thể sử dụng trình shell mà Django cung cấp sẵn trong file manage.py. Nếu bạn không muốn chạy trực tiếp trong Command Prompt mà muốn chạy trong file .py riêng thì trong file .py đấy bạn phải khai báo các dòng dưới đây:

import os
import django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings");
django.setup()

Các dòng này sẽ thiết lập biến môi trường DJANGO_SETTINGS_MODULE trỏ đến module mysite.settings, mục đích là để chỉ cho Python biết đường dẫn import. Mặc định khi chạy file manage.py từ cmd thì biến này sẽ được Django thiết lập luôn.

>>> from polls.models import Question, Choice
>>> Question.objects.all()
[]

Chúng ta import 2 lớp QuestionChoice. Phương thức Question.objects.all() liệt kê toàn bộ đối tượng Question đang có trong CSDL, hiện tại là không có bản ghi nào nên kết quả trả về list rỗng.

>>> from django.utils import timezone
>>> q = Question(question_text="What's new?", pub_date=timezone.now())

Chúng ta tạo một đối tượng Question và thiết lập pub_date là ngày giờ hiện tại của máy tính, chúng ta lấy thông tin này từ phương thức timezone.now() trong module django.utils.timezone.

>>> q.save()

Để lưu đối tượng Question mới này vào CSDL thì chỉ cần gọi phương thức save() là được.

>>> q.id
1

Khi viết lớp QuestionChoice chúng ta không cung cấp thuộc tính id hay bất cứ thuộc tính nào để làm khóa chính, vì vậy khi tạo CSDL Django sẽ tự động thêm 1 thuộc tính id để làm khóa chính và thuộc tính này sẽ tự động tăng. 

>>> q.question_text
What's new?
>>> q.question_text = "What's up?"
>>> q.save()

Bạn có thể thay đổi trực tiếp giá trị trên các đối tượng này sau đó gọi phương thức save() là dữ liệu trên CSDL sẽ được cập nhật.

from django.db import models
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)
    def __str__(self):
        return self.choice_text

Chúng ta override phương thức __str__(), nếu không khi gọi phương thức str() mặc định sẽ cho output khá kì quái.

Sau đó chúng ta tắt và mở lại shell, rồi chạy thử đoạn lệnh sau sẽ được kết quả khác:

>>> from polls.models import Question, Choice
>>> Question.objects.all()
[<Question: What's up?>]

Phương thức objects.all() sẽ gọi đến phương thức __str__().

>>> Question.objects.filter(id=1)
[<Question: What's up?>]
>>> Question.objects.filter(question_text__startswith='What') 
[<Question: What's up?>]

Bạn có thể lọc các bản ghi theo thuộc tính bằng phương thức filter().

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

Bạn cũng có thể lấy từng bản ghi đơn lẻ bằng phương thức get(), ở trên chúng ta lấy theo khóa chính pk (Primary Key).

>>> q.choice_set.all()
[]

Bất cứ bảng nào có một bảng khác chứa khóa ngoại tham chiếu đến khóa chính của nó đều sẽ có một thuộc tính được tạo tự động là một tập hợp các đối tượng của bảng kia. Ở đây bảng Choice chứa khóa ngoại tham chiếu đến bảng Question, do đó bảng Question sẽ có một danh sách các đối tượng Choice, chúng ta có thể lấy danh sách này qua choice_set.all() (tên danh sách được đặt theo <tên bảng>_set). Ở đây chúng ta vẫn chưa tạo đối tượng Choice nào nên danh sách trả về rỗng.

>>> 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)

Chúng ta tạo 3 đối tượng Choice bằng phương thức choice_set.create().

>>> q.choice_set.all()
[<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]
>>> q.choice_set.count()
3

Chúng ta có thể lấy số lượng các bản ghi trong bảng bằng phương thức count().

>>> c = q.choice_set.filter(choice_text__startswith='Just hacking')
>>> c.delete()

Để xóa một bản ghi trong bảng thì chúng ta dùng phương thức delete().