A Survey On QuerySet In Django (Part I)
Bài đăng này đã không được cập nhật trong 3 năm
Như các bạn đã biết, với bất kỳ ngôn ngữ lập trình nào, việc truy vấn dữ liệu đều sắm vai trò tối quan trọng. Tất nhiên là trong Django cũng vậy (Django là một web framework trên nền tảng ngôn ngữ Python)
Trong bài viết này, chúng ta sẽ xét đến một số method cơ bản cũng như là QuerySet (Django ORM) được dùng trong truy vấn dữ liệu với Django
Để thuận tiện cho việc minh họa, chúng ta sử dụng một số model với quan hệ như sau:
from django.db import models
class Blog(models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField()
def __str__(self): # __unicode__ on Python 2
return self.name
class Author(models.Model):
name = models.CharField(max_length=50)
email = models.EmailField()
def __str__(self): # __unicode__ on Python 2
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): # __unicode__ on Python 2
return self.headline
Creating objects
Để tạo một object (object), ta phải khởi tạo (instantiate) nó trước. Sau đó, dùng method save()
để lưu vào database
from blog.models import Blog
b = Blog(name='Beatles Blog', tagline='All the latest Beatles news.')
b.save()
Những dòng lệnh này thực hiên một câu lệnh SQL INSERT
. Django chỉ thực sự chọc vào database khi chúng ta gọi method save()
.
Chú ý là method save()
không có giá trị trả về.
Ngoài cách trên, chúng ta cũng có thể sử dụng method create()
(một method thuộc QuerySet
) để tạo object:
author = Author.objects.create(name='TheDeath', email='TheHell@gmail.com')
Saving changes to objects
Để lưu lại các thay đổi đối với một object đã tồn tại trong database, chúng ta sử dụng method save()
Giả sử ta có một instance Blog
là blog
đã được lưu vào trong database, ví dụ dưới đây sẽ thay đổi thuộc tính name
của blog và lưu lại vào database:
blog.name = 'New name'
blog.save()
Ở đây, một câu lệnh SQL UPDATE
đã xảy ra và Django chỉ thực sự chọc vào database khi gọi method save()
Một cách tương tự, chúng ta có thể update trường ForeignKey
như sau:
from blog.models import Entry
entry = Entry.objects.get(pk=1)
cheese_blog = Blog.objects.get(name="Cheddar Talk")
entry.blog = cheese_blog
entry.save()
Tuy nhiên, update trường ManyToManyField
thì có khác một chút. Chúng ta sẽ dùng method add()
:
from blog.models import Author
joe = Author.objects.create(name='Joe')
aladin = Author.objects.create(name='Aladin')
adele = Author.objects.create(name='Adele')
entry.authors.add(joe)
entry.authors.add(aladin, adele)
Retrieving objects
Để lấy ra các object từ database, chúng ta cần phải dựng một QuerySet
thông qua một Manager
trên model class của các object cần lấy.
Một QuerySet
thể hiện một tập các object trong database. Nó có thể gồm 0, 1 hoặc nhiều filter
. Ở đây, filter
dùng để thu hẹp tập kết quả trả về dựa vào các parameter. Trong thuật ngữ SQL, một QuerySet
tương đương với một câu lệnh SELECT
và một filter
là một mệnh đề giới hạn như là WHERE
hoặc LIMIT
.
Chúng ta lấy ra một QuerySet
bằng cách sử dụng Manager
của model. Mỗi model có ít nhất một Manager
, mặc định là objects
. Truy cập Manager
thông qua model class như sau:
Blog.objects
<django.db.models.manager.Manager object at ...>
Chú ý là không truy cập Manager
thông qua model instance. Điều này sẽ gây ra lỗi
b = Blog(name='Foo', tagline='Bar')
b.objects
Traceback:
...
AttributeError: "Manager isn't accessible via Blog instances."
Retrieving all objects
Để lấy tất cả các object của một class, ta sử dụng method all()
của Manager
all_entries = Entry.objects.all()
Method all()
sẽ trả về một QuerySet
bao gồm tất cả các object thuộc class đó.
Retrieving specific objects with filters
Để lấy ra một tập con các object xác định nào đó, ta sử dụng filter()
Ví dụ, để lấy ra tất cả các entry được publish trong năm 2006, ta dùng dòng lệnh sau:
Entry.objects.filter(pub_date__year=2006)
Ngược lại với filter()
, chúng ta có exclude()
dùng để lấy ra các object không thỏa mãn điều kiện filter:
Entry.objects.exclude(pub_date__year=2006)
Câu lệnh trên lấy ra các entry không thuộc năm 2006.
Chaining filters
Chúng ta có thể sử dụng nhiều filter
trong cùng một câu query:
Entry.objects.filter(
headline__startswith='What'
).exclude(
pub_date__gte=datetime.date.today()
).filter(
pub_date__gte=datetime(2005, 1, 30)
)
Retrieving a single object with get
filter()
luôn trả về một QuerySet
, kể cả khi chỉ có một object thỏa mãn câu query.
Khi chúng ta chắc chắn chỉ có một object thỏa mãn query, chúng ta có thể sử dụng method get()
để trực tiếp trả về object thay vì một QuerySet
:
one_entry = Entry.objects.get(pk=1)
Method get()
cũng nhận các parameter như filter()
.
Nếu không có object nào thỏa mãn query, get()
sẽ raise lên exception DoesNotExist
. Exception này là một attribute của model class mà chúng ta đang làm việc với. Ví dụ như trong trường hợp trên, exception được raise lên là Entry.DoesNotExist
.
Một cách tương tự, nếu câu query trả về nhiều hơn một object, Django sẽ raise lên exception MultipleObjectsReturned
.
Phần I của loạt bài viết về QuerySet trong Django xin được kết thúc ở đây
Rất mong nhận được ý kiến đóng góp của các bạn!
Hope you enjoy this and thank you all for reading!
All rights reserved