Sau khi chúng ta đã tạo các lớp model, Django sẽ tự động tạo các phương thức mới trong model đó cho phép bạn thao tác với CSDL, bạn có thể tạo, sửa, xóa, cập nhật dữ liệu.
Trong bài này chúng ta sẽ tạo và sử dụng các lớp model sau đây để thực hành với các phương thức do Django cung cấp.
from django.db import models class Blog(models.Model): name = models.CharField(max_length=100) tagline = models.TextField() def __str__(self): return self.name class Author(models.Model): name = models.CharField(max_length=50) email = models.EmailField() def __str__(self): return self.name class Entry(models.Model): blog = models.ForeignKey(Blog) headline = models.CharField(max_length=255) body_text = models.TextField() pub_date = models.DateField() mod_date = models.DateField() authors = models.ManyToManyField(Author) n_comments = models.IntegerField() n_pingbacks = models.IntegerField() rating = models.IntegerField() def __str__(self): return self.headline
Ở đây chúng ta có 3 model là Blog
, Author
và Entry
, các model này đại diện cho các lớp model cơ bản của một website blog.
Sau khi bạn đã tạo các lớp model trên thì bạn chạy 2 lệnh python manage.py makemigrations
và python manage.py migrate
để Django cập nhật các bảng mới trong CSDL. Sau đó bạn chạy trình shell bằng lệnh python manage.py shell
để bắt đầu thao tác với CSDL (nếu bạn muốn chạy trong file .py riêng thì phải thiết lập biến môi trường DJANGO_SETTINGS_MODULE
đến mysite.settings
trước).
Tạo đối tượng
Mỗi bản ghi hay mỗi dòng trong từng bảng CSDL sẽ tương ứng với một đối tượng cụ thể. Để tạo một bản ghi trong CSDL thì chúng ta chỉ cần tạo một đối tượng tương ứng với trong Python rồi gọi phương thức save()
là xong. Vd:
>>> from blog.models import Blog >>> b = Blog(name='J.R.R Blog', tagline='All the latest J.R.R news.') >>> b.save()
Đoạn code trên sẽ thực hiện câu lệnh INSERT
, bạn phải gọi phương thức save()
thì dữ liệu mới được cập nhật lên CSDL.
Ngoài ra nếu bạn muốn vừa tạo đối tượng vừa cập nhật thẳng lên CSDL luôn thì dùng phương thức create()
trong đối tượng objects
, đối tượng này là một đối tượng tĩnh do Django tạo ra cho chúng ta để đơn giản hóa việc thao tác với CSDL. Vd:
>>> Blog.objects.create(name='J.R.R Blog', tagline='All the latest J.R.R news.')
Cập nhật đối tượng
Bạn có thể thay đổi giá trị của các đối tượng trong Python rồi chỉ cần gọi phương thức save()
là Django sẽ cập nhật mới trong CSDL.
>>> b.name = 'New name' >>> b.save()
Cập nhật các thuộc tính khóa ngoại
Chúng ta tạo đối tượng Author
mới như sau:
>>> from blog.models import Entry, Author >>> a = Author(name='J.R.R. Tolkien', email='jrr@middleeast.com') >>> a.save()
Bây giờ chúng ta sẽ tạo đối tượng Entry, đối tượng này chứa 2 thuộc tính khóa ngoại, một thuộc tính many-to-one là blog
và many-to-many là authors
.
>>> from django.utils import timezone >>> e = Entry(blog=b, ... headline='The lord of the rings', ... body_text='Chapter 0', ... pub_date=timezone.now(), ... mod_date=timezone.now(), ... n_comments=0, ... n_pingbacks=0, ... rating=0) >>> e.save()
Việc gán giá trị cho các thuộc tính khóa ngoại many-to-one (ForeignKey) rất đơn giản, bạn chỉ cần gán thuộc tính khóa ngoại với đối tượng cần trỏ đến là xong, trong đoạn code trên chúng ta gán khóa ngoại blog = b
, trong đó b
là đối tượng Blog mà chúng ta đã tạo ra ở đầu bài.
>>> e.blog = Blog.create(...) >>> e.save()
Khi cần thay đổi chúng ta cũng chỉ cần dùng phép gán như thường là được.
Đối với các thuộc tính khóa ngoại many-to-many thì chúng ta không được phép gán trực tiếp như đối với ForeignKey
mà phải dùng phương thức riêng của thuộc tính khóa ngoại đó, bởi vì khóa ngoại ForeignKey
chỉ lưu trữ các đối tượng đơn lẻ trong khi khóa ngoại ManyToManyField
thì lại lưu trữ một danh sách các đối tượng khác nhau:
>>> e.authors.add(a) >>> e.save()
Chúng ta lưu đối tượng a
vào trong khóa ngoại authors
, trong đó a
là đối tượng Author
mà chúng ta đã tạo ở trên.
Truy xuất dữ liệu
Khi chúng ta tạo một đối tượng thuộc lớp model do chúng ta tự định nghĩa, chẳng hạn như b=Blog(...)
, thì mặc định đối tượng b
sẽ được Django cung cấp cho các phương thức để thao tác với CSDL trên chính bản ghi của b
, chúng ta đã học một số phương thức này trong các ví dụ trên.
Ngoài cách thao tác với dữ liệu thông qua từng bản ghi như trên thì Django còn cung cấp cho chúng ta một đối tượng thuộc lớp django.db.models.manager.Manager
để chúng ta thao tác với chính bảng được tạo ra đó, đối tượng này mặc định được đặt tên là objects
.
>>> Blog.objects >>> <django.db.models.manager.Manager object at 0x....>
Lấy toàn bộ dữ liệu
Khi chúng ta lấy dữ liệu từ CSDL về thì objects
sẽ trả về một đối tượng QuerySet
.
>>> Blog.objects.all() >>> [<Blog: New name>]
Để lấy toàn bộ bản ghi hiện có trong bảng thì chúng ta dùng phương thức all()
.
>>> type(Blog.objects.all()) <class 'django.db.models.query.QuerySet'>
Như mình đã nói, danh sách được trả về là một đối tượng QuerySet
.
Lọc dữ liệu
Có 2 phương thức hỗ trợ lọc dữ liệu là filter()
và exclude().
Tham số của 2 phương thức là một biểu thức tìm kiếm, trong đó phương thức filter()
sẽ trả về dữ liệu khớp với biểu thức tìm kiếm, còn exclude()
sẽ trả về dữ liệu không khớp. Chúng ta sẽ tìm hiểu thêm về các biểu thức tìm kiếm ở cuối bài.
Ví dụ:
>>> Entry.objects.filter(pub_date__year==2016)
Đoạn code trên sẽ lọc những bản ghi Entry
có pub_date
(ngày đăng) vào năm 2016.
Bạn cũng có thể lọc theo nhiều điều kiện liên tiếp như sau:
>>> Entry.objects.filter(headline__startswith='What') ... .exclude(pub_date__gte=datetime.date.today()) ... .filter(pub_date__gte=datetime(2016, 1, 30))
Đoạn code trên lọc các bản ghi có chuỗi bắt đầu là “What” và có pub_date
nằm trong phạm vi từ ngày 30/1/2016 đến thời điểm hiện tại.
Lấy một dòng dữ liệu
Django cung cấp phương thức get()
giúp bạn lấy một bản ghi duy nhất, tham số của phương thức này cũng là một biểu thức tìm kiếm như 2 phương thức filter()
và exclude()
. Bạn cũng chỉ dùng get()
khi biết dữ liệu trả về chỉ có 1 bản ghi thôi, nếu có nhiều bản ghi khớp với biểu thức tìm kiếm thì get()
sẽ báo lỗi exception MultipleObjectsReturned
.
>>> one_entry = Entry.objects.get(pk=1)
Một sự khác nhau nữa giữa get()
và filter()/exclude()
là nếu get()
không tìm thấy bản ghi nào thì sẽ trả về một lỗi exception là DoesNotExist
còn 2 phương thức kia sẽ trả về một đối tượng QuerySet
rỗng.
Ngoài 3 phương thức lọc dữ liệu trên là get()
, filter()
và exclude()
thì bạn có thể tìm hiểu thêm các phương thức khác tại đây.
Lọc số lượng bản ghi
Bạn có thể lọc số lượng bản ghi cần lấy theo cú pháp của Python. Ví dụ:
>>> Entry.objects.all()[:5] # lấy 5 phần tử đầu tiên >>> Entry.objects.all()[5:10] # lấy các phần tử từ vị trí 5 đến 10
Python không hỗ trợ lọc theo chỉ số âm.
>>> Entry.objects.all()[-1]
Đoạn code trên sẽ báo lỗi.
Biểu thức tìm kiếm
Các biểu thức tìm kiếm sẽ thực hiện câu truy vấn SQL WHERE
trong CSDL. Biểu thức tìm kiếm là tham số cho các phương thức lọc dữ liệu filter()
, exclude()
và get()
.
Cú pháp lọc có dạng <tên thuộc tính>__<kiểu tìm kiếm>=<giá trị>
(lưu ý ở đây có 2 dấu gạch dưới).
Ví dụ
>>> Entry.objects.filter(pub_date__lte='2016-01-01')
Đoạn code trên tương đương với câu lệnh SQL sau:
SELECT * FROM blog_entry WHERE pub_date <= '2016-01-01';
Trong biểu thức tìm kiếm thì <tên thuộc tính>
bao giờ cũng là tên do chúng ta đặt khi định nghĩa model, ngoại trừ thuộc tính khóa ngoại phải thêm vào _id
ở cuối tên. Ví dụ:
>>> Entry.objects.filter(blog_id=4)
Django
cung cấp rất nhiều cú pháp <kiểu tìm kiếm>
khác nhau, bạn có thể xem thêm ở đây. Ở đây mình giới thiệu một số.
exact
: dữ liệu tìm được phải giống chính xác với giá trị cần tìm. VdEntry.objects.get(headline__exact='Cat bites dog')
chỉ trả về những bản ghi cóheadline
là “Cat bites dog“.iexact
: dữ liệu tìm được chỉ cần giống kí tự với giá trị cần tìm, không phân biệt chữ HOA-thường. VdBlog.objects.get(name__iexact='beatles blog')
, những bản ghi cóheadline
là “Beatles Blog”, “beatles blog” hoặc “BeAtlES blOG” đều được nhận.contains
: dữ liệu chỉ cần chứa chuỗi giá trị là được. VdEntry.objects.get(headlines__contains='Lennon').
Ngoài raicontains
cũng có chức năng như contains nhưng không phân biệt chữ HOA-thường.
startswith, endswith
: dữ liệu có chuỗi bắt đầu hoặc kết thúc giống với giá trị.
Tìm kiếm đa bảng
Các bảng trong CSDL có quan hệ với nhau nhờ vào các khóa ngoại, khi truy vấn dữ liệu, SQL cho phép bạn truy vấn các bản ghi có liên quan với nhau bằng cách nối các bảng lại bằng câu lệnh JOIN
, Django cũng cho phép bạn làm điều đó, bạn chỉ cần đưa vào biểu thức tìm kiếm cú pháp <tên khóa ngoại>__<tên thuộc tính của bảng khác>=<giá trị>.
Ví dụ:
>>> Entry.objects.filter(blog__name='Beatles Blog')
Câu lệnh trên sẽ tìm các bản ghi Entry
có quan hệ với bảng Blog
với name là “Beatles Blog”.