visit
len()
, count()
etc. Make sure that you make the best use of them.
# models.py
from django.db import models
class Sale(models.Model):
sold_at = models.DateTimeField(
auto_now_add=True,
)
charged_amount = models.PositiveIntegerField()
# models.py
from django.db import models
class Sale(models.Model):
sold_at = models.DateTimeField(
auto_now_add=True,
db_index=True, #DB Indexing
)
charged_amount = models.PositiveIntegerField()
# models.py
from django.db import models
class Sale(models.Model):
sold_at = models.DateTimeField(
auto_now_add=True,
db_index=True, #DB Indexing
)
charged_amount = models.PositiveIntegerField()
class Meta:
indexes = [
["sold_at", "charged_amount"]]
ip:port
values where ip
is the IP address of the Memcached daemon and port
is the port on which Memcached is running, or the URL pointing to your Redis instance, using the appropriate scheme.
To enable database caching with Memcached, install pymemcache
using pip using the following command:
pip install pymemcache
Then, you can configure the cache settings in your settings.py
as follows:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
'LOCATION': '127.0.0.1:11211',
}
}
In the above example, Memcached is running on localhost (127.0.0.1) port 11211, using the pymemcache
binding:
pip install redis
Then configure the cache settings in your settings.py
by adding the following code:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.redis.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379',
}
}
A queryset in Django, typically, caches its result when evaluation happens and for any further operation with that queryset, it first checks if there are cached results. However, when you use iterator()
, it doesn’t check for cache and reads results directly from the database, neither saves the results to the queryset.
Now, you must be wondering how this is helpful. Consider a queryset that returns a large number of objects with lots of memory to cache but has to be used only once, in such case, you should use an iterator()
.
queryset = Product.objects.all()
for each in queryset:
do_something(each)
Whereas if we use iterator()
, Django will hold the SQL connection open and read each record, and call do_something()
before reading the next record:
queryset = Product.objects.all().iterator()
for each in queryset:
do_something(each)
Django creates a new database connection for each request and closes it after the request is complete. This behavior is caused by CONN_MAX_AGE
, which has a default value of 0. But how long should it be set to? That is determined by the volume of traffic on your site; the higher the volume, the more seconds are required to maintain the connection. It is usually recommended to start with a low number, such as 60.
You need to wrap your extra options in OPTIONS
, as detailed in the
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'dashboard',
'USER': 'root',
'PASSWORD': 'root',
'HOST': '127.0.0.1',
'PORT': '3306',
'OPTIONS': {
'CONN_MAX_AGE': '60',
}
}
}
Note: These expressions are defined in django.db.models.expressions
and django.db.models.aggregates
, but for convenience, they’re available and usually imported from django.db.models
.
In the Django Queryset API, F()
expressions are used to refer to the model field values directly. It allows you to refer to model field values and conduct database actions on them without having to fetch them from the database and into Python memory. Instead, Django employs the F()
object to produce a SQL phrase that defines the needed database activity.
products = Product.objects.all()
for product in products:
product.price *= 1.2
product.save()
However, if we use F()
, we can do this in a single query as follows:
from django.db.models import F
Product.objects.update(price=F('price') * 1.2)
select_related()
and prefetch_related()
Django provides select_related()
and prefetch_related()
arguments for optimizing your querysets by minimizing the number of database requests.
select_related()
"follows" foreign-key relationships, selecting additional related-object data when it executes its query.
prefetch_related()
does a separate lookup for each relationship, and does the "joining" in Python.
select_related()
We use select_related()
when the item to be selected is a single object which means forward ForeignKey
, OneToOne
, and backward OneToOne
field.
You may use select_related()
to create a single query that returns all the related objects for a single instance for one-many and one-to-one connections. When the query is performed, select_related()
retrieves any extra related-object data from foreign-key relationships.
select_related()
works by generating a SQL join and includes the related object's columns in the SELECT
expression. As a result, select_related()
returns related items in the same database query.
Though select_related()
produces a more sophisticated query, the data acquired is cached, thus handling of the data obtained does not necessitate any extra database requests.
queryset = Tweet.objects.select_related('owner').all()
prefetch_related()
In contrast, prefetch_related()
is utilized for many-to-many and many-to-one connections. It produces a single query that includes all of the models and filters are given in the query.
Book.objects.prefetch_related('author').get(id=1).author.first_name
Read about the difference between select_related()
and prefetch_related()
in detail .
bulk_create()
and bulk_update()
bulk_create()
is a method that creates the provided list of objects into the database with one query. Similarly, bulk_update()
is a method that updates the given fields on the provided model instances with one query.
class Post(models.Model):
title = models.CharField(max_length=300, unique=True)
time = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
Now, let’s say that we want to add multiple data records to this model, then we can use bulk_create()
like this:
#articles
articles = [Post(title="Hello python"), Post(title="Hello django"), Post(title="Hello bulk")]
#insert data
Post.objects.bulk_create(articles)
>>> Post.objects.all()
<QuerySet [<Post: Hello python>, <Post: Hello django>, <Post: Hello bulk>]>
And if we want to update the data, then we can use bulk_update()
like this:
update_queries = []
a = Post.objects.get(id=14)
b = Post.objects.get(id=15)
c = Post.objects.get(id=16)
#set update value
a.title="Hello python updated"
b.title="Hello django updated"
c.title="Hello bulk updated"
#append
update_queries.extend((a, b, c))
Post.objects.bulk_update(update_queries, ['title'])
>>> Post.objects.all()
<QuerySet [<Post: Hello python updated>, <Post: Hello django updated>, <Post: Hello bulk updated>]>