A Survey On QuerySet In Django (Part I)

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

Python - Django.jpg

Để 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='[email protected]')

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 Blogblog đã đượ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!

equation of life.jpg