Django's querysets are cool!
In this article I'll explain what querysets is, how it works (if you're already familiar with it, you can skip to the second part), I think you should always return to the Querysets object if you can, so let me talk about how to do it.
Querysets's cool .
QuerySet is essentially a list of objects for a given model. I say "list" instead of "group" or more formal "set" because it is orderly. In fact, you may already be familiar with how to get querysets, because this is the object you get when you call the VariousBook.objects.XXX () method. For example, consider the following statement:
All () returns a queryset of the book instance, which happens to include allbookinstances, and the following other calls you may already know:
# return all books published since 1990
Book.objects.filter (year_published__gt=1990) # return all books
*not* WRI Tten by Richard Dawkins
Book.objects.exclude (author= ' Richard Dawkins ') # return all Books
, ordered by author name , then
# chronologically, with the newer ones.
Book.objects.order_by (' author ', '-year_published ')
The coolest thing about QuerySet S is that because these functions operate and return 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.
Book.objects.filter (year_published__gt=1990) \
exclude (author= ' Richard Dawkins ') \
order_by (' author ', '- Year_published ')
And that's not all, it's faster!
Internally, a queryset can be constructed, filtered, sliced, and easily delivered without actual database queries, as in normal variables, and no database activity is generated until the evaluation process is completed queryset.
All we've identified querysets is cool, isn't it?
Return to Querysets as much as possible
I recently used a model in a Django application to represent trees (data structures, not Christmas decorations). 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 ()
The work is quite good. The trouble is, I have to add another method, Get_larger_ancestors, which should return all values greater than the current node's parent node. This is what I can do to achieve this:
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 the list two times--django at once, myself once. Which makes me think-what if Get_ancestors returns to Queryset instead of the list? I can do this:
def get_larger_ancestors (self): return
self.get_ancestors (). Filter (Value__gt=self.value)
Quite simply, what's more important here is that I'm not traversing the object. I can use any filter I want to use for Get_larger_ancestors's return, and feel secure-I won't get a list of objects of unknown size. The main advantage of this is that I always use the same query interface. When the user gets a whole bunch of objects, we don't know how he wants to slice them. And when I return the Queryset object, I guarantee that the user knows how to handle it.
But how to achieve get_ancestorsto return to a queryset? This is a little trick. It is impossible to collect the data we need with a simple query, and it is impossible to use any predetermined number of queries. The law we are looking for is dynamic, and the implementation of the choice looks much like it is now, and here is the choice, 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)
Pause for a moment, precipitate a moment, and tell the details immediately.
What I want to say is that whenever you return to a series of objects-you should always return a queryset substitution. Doing so will allow users to filter, splice, and sort the results freely using a simple, familiar, and better performing method.
(from one side get_ancestors queried the database because I used recursive self.parent.) Here's an extra database execution--This function is executed when the actual test result is performed, and another one is executed in the future. We get a performance boost when we use more filters on database queries or do high memory operations. Here's an example
Common Queryset Operations
Therefore, it is simple to return a queryset when executing a simple query. When we want to implement something that is more complex, we need to perform related operations (including some helper functions). Here are some tips (as an exercise, try to understand my get_larger_ancestors implementation).
- Union-Queryset's Union operator is |, when processing the replication pipeline "SYMBOL.QS1 | Qs2 "returns all Queryset from QS1 and QS2 projects (all items in Queryset will only appear once in the results).
- Intersection-the intersection has no special operations because you already know how to do it. Link functions such as filter have the effect of intersection before the original Queryset and the new filter.
- Differential-differential (mathematically written as qs1 \ Qs2) represents all projects that are in QS1 and not qs2. Note that this operation is asymmetric (relative to previous operations). Python I'm afraid there's no built-in way, but you can do this: Qs1.exclude (PK__IN=QS2)
- Starting from the air-it's not useful to open but it's not true, as the example above shows. Many times, when we create a queryset union dynamically, we need to start with an empty list, which is the way to get it: MyModel.objects.none ().