Describes QuerySets and djangoquerysets In the Python Django framework.

Source: Internet
Author: User

Describes QuerySets and djangoquerysets In the Python Django framework.

Django's QuerySets are cool!

In this article, I will explain what QuerySets are and how they work (if you are familiar with it, you can jump directly to the second part ), I think you should always return the QuerySets object if you can. Let's talk about how to do it.
QuerySets is cool

QuerySet is essentially a list of objects of a given model. I say "list" instead of "group" or a more formal "set" because it is ordered. In fact, you may be familiar with how to obtain QuerySets, because this is the object you get after calling the variousBook. objects. XXX () method. For example, consider the following statement:
 

Book.objects.all()

All () returns a QuerySet of the Book instance, which exactly includes allBookinstances. You may already know the following calls:
 

# Return all books published since 1990Book.objects.filter(year_published__gt=1990) # Return all books *not* written by Richard DawkinsBook.objects.exclude(author='Richard Dawkins') # Return all books, ordered by author name, then# chronologically, with the newer ones first.Book.objects.order_by('author', '-year_published')

The coolest thing about QuerySet s is that, because these function operations and responses are all a QuerySet, you can link them up:
 

# Return all book published after 1990, except for# ones written by Richard Dawkins. Order them by# author name, then chronologically, with the newer# ones first.Book.objects.filter(year_published__gt=1990) \      .exclude(author='Richard Dawkins') \      .order_by('author', '-year_published')

And it's not all. It's faster!

Internally, A QuerySet can be constructed, filtered, sliced, and passed without any actual database query as common variables. Database activities are not generated before the QuerySet is evaluated and processed.

All of us have confirmed that QuerySets are cool, aren't they?

Returns QuerySets as much as possible.

I recently used a model in a Django application to represent a tree (data structure, not Christmas decoration ). This means that each instance has a link to its parent node in the tree. It looks like this:
 

class Node(models.Model):  parent = models.ForeignKey(to='self', null=True, blank=True)  value = models.IntegerField()     def __unicode__(self):    return 'Node #{}'.format(self.id)     def get_ancestors(self):    if self.parent is None:      return []    return [self.parent] + self.parent.get_ancestors()

This job is quite good. The trouble is that I have to add another method, get_larger_ancestors. It should return all the parent nodes whose values are greater than the current node. This is what I can achieve:
 

def get_larger_ancestors(self):    ancestors = self.get_ancestors()    return [node for node in ancestors if node.value > self.value]

The problem is that I will basically review Django twice on the list, once on my own. This makes me take into account-what if get_ancestors returns QuerySet instead of the list? I can do this:
 

def get_larger_ancestors(self):    return self.get_ancestors().filter(value__gt=self.value)

It is very simple. What's more important here is that I didn't traverse objects. I can use any filters I want to use for get_larger_ancestors responses and feel safe-I will not get a list of objects of unknown size. The main advantage is that I have always used the same query interface. When users get a lot of objects, we don't know how they want to slice them. When a QuerySet object is returned, I ensure that the user knows how to handle it.


But how does one implement get_ancestorsto to return a QuerySet? This is a trick. It is impossible to use a simple query to collect the data we need, and it is impossible to use any predefined number of queries. The rule we are looking for is dynamic, and the implementation of the choice looks like it now. Below is a better implementation:
 

class Node(models.Model):  parent = models.ForeignKey(to='self', null=True, blank=True)  value = models.IntegerField()     def __unicode__(self):    return 'Node #{}'.format(self.id)     def get_ancestors(self):    if self.parent is None:      return Node.objects.none()    return Node.objects.filter(pk=self.parent.pk) | self.parent.get_ancestors()     def get_larger_ancestors(self):    return self.get_ancestors().filter(value__gt=self.value)

Wait for a moment, settle down, and tell the details immediately.

What I want to say is that whenever you return a series of objects-you should always return a QuerySet alternative. This will allow users to use a simple, familiar, and better-performing method to freely filter, splice, and sort results.

(From one side, get_ancestors queries the database because I use recursive self. parent. Here is an additional database execution-this function is executed when the actual detection result is returned, and another execution will be performed in the future. When we use more filters or perform high memory consumption operations on database queries, we have improved our performance. Example

Common QuerySet operations

Therefore, it is very easy to return a QuerySet when performing a simple query. When we want to implement something more complex, we need to perform relevant operations (including helper functions ). Below are some tips (as an exercise, try to understand the implementation of get_larger_ancestors ).

  • Union-the Union operator of QuerySet is |, which processes the pipeline "symbol. qs1 | qs2 "returns all querysets from qs1 and qs2 projects (all items in QuerySet will only appear once in the results ).
  • Intersection-there are no special operations on the intersection because you already know how to do it. Linked functions such as filter act as an intersection before the original QuerySet and the new filter.
  • Difference-difference (written as qs1 \ qs2 in mathematics) represents all projects in qs1 rather than qs2. Note that this operation is asymmetric (compared with the previous operation ). I'm afraid there is no built-in method in Python, but you can do this: qs1.exclude (pk _ in = qs2)
  • Starting from the null field is useless, but not actually, as shown in the preceding example. Most of the time, when we dynamically establish a QuerySet Union, we need to start from an empty list. This is the way to get it: MyModel. objects. none ().

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.