10 Django Secrets No One Talks About (But You Should Know!) [Part 2]

Django is full of hidden gems that even experienced developers might not be aware of. In Part 1, we explored some lesser-known tricks, but…

10 Django Secrets No One Talks About (But You Should Know!) [Part 2]
Photo by Max Bender on Unsplash

Django is full of hidden gems that even experienced developers might not be aware of. In Part 1, we explored some lesser-known tricks, but there’s more to uncover!

10 Django Secrets No One Talks About (But You Should Know!)
Django is a powerful framework, but there are hidden features and best practices that many developers overlook. These…

Here are 10 more Django secrets that will help you write cleaner, more efficient, and more powerful applications. 🚀


1. You Can Use Database Functions in Querysets

Django provides built-in database functions that let you perform advanced queries without raw SQL.

Example: Case-Insensitive Search with Lower()

from django.db.models.functions import Lower 
 
User.objects.annotate(lower_name=Lower("username")).filter(lower_name="john_doe")

This is more efficient than calling .lower() function in Python. This will keeps logic inside the database layer for better performance.

Example: Extract Year from a Date

from django.db.models.functions import ExtractYear 
 
BlogPost.objects.annotate(year=ExtractYear("published_date")).filter(year=2024)

This is useful for grouping data by year, month, or day and save it from extra processing in Python.

2. You Can Use bulk_create() to Insert Multiple Objects at Once

Instead of creating objects one by one, you can insert thousands of records in a single query using bulk_create().

Bad Practice: Inserting in a Loop

for i in range(1000): 
    User.objects.create(username=f"user{i}")

This will executes 1000 separate queries 😱.

Best Practice: Use bulk_create()

users = [User(username=f"user{i}") for i in range(1000)] # create a list of User objects 
User.objects.bulk_create(users)

This will give 10x faster performance and it executes only one query instead of 1000 separate ones.

3. Use Subquery() and OuterRef() for Advanced Filtering

Django lets you perform subqueries inside Querysets without writing raw SQL.

Example: Get Users with the Latest Order Price

from django.db.models import OuterRef, Subquery, Max 
 
latest_order = Order.objects.filter(user=OuterRef("pk")).order_by("-created_at").values("total")[:1] 
User.objects.annotate(latest_order_price=Subquery(latest_order))

This will reduces extra database queries.

4. Optimize get_or_create() for Better Performance

Using get_or_create() is great, but it can cause performance issues if misused.

Bad Practice: Calling It Without Filtering

obj, created = User.objects.get_or_create(username="john_doe")

Best Practice: Use defaults to Avoid Extra Queries

obj, created = User.objects.get_or_create(username="john_doe", defaults={"email": "john@example.com"})

This Avoids unnecessary lookups and Improves performance by using indexed fields.

5. Django’s case Expression Can Simplify Complex Conditions

Instead of handling conditions in Python, use Case() inside Querysets.

Example: Assign Labels Based on a Field

from django.db.models import Case, When, Value, CharField 
 
users = User.objects.annotate( 
    status_label=Case( 
        When(is_active=True, then=Value("Active")), 
        When(is_active=False, then=Value("Inactive")), 
        default=Value("Unknown"), 
        output_field=CharField(), 
    ) 
)

This is Faster than processing in Python and more efficient for large datasets.

6. Use __in_bulk() for Fast Lookups

When retrieving multiple objects by ID, using filter() can be inefficient. Instead, use in_bulk() for faster lookups.

Bad Practice: Using filter() in a Loop

user_ids = [1, 2, 3, 4, 5] 
users = {user.id: user for user in User.objects.filter(id__in=user_ids)}

Best Practice: Use in_bulk()

users = User.objects.in_bulk([1, 2, 3, 4, 5])

This is More efficient than using filter(id__in=...)and returns a dictionary instead of a queryset.

7. Use Q() Objects for Complex Queries

When filtering with OR conditions, Django’s Q() object is a lifesaver.

Example: Search Users by Email OR Username

from django.db.models import Q 
 
users = User.objects.filter(Q(email="test@example.com") | Q(username="test_user"))

This allows more flexible queries and helps when dealing with multiple conditions.

8. Optimize File Uploads with upload_to

Instead of storing all uploads in a single folder, Django lets you define dynamic paths using upload_to.

Example: Organize User Uploads by ID

def user_directory_path(instance, filename): 
    return f"user_{instance.user.id}/{filename}" 
 
class Profile(models.Model): 
    user = models.OneToOneField(User, on_delete=models.CASCADE) 
    avatar = models.ImageField(upload_to=user_directory_path)

This keeps files organized and Prevents filename conflicts.

9. Speed Up Static File Serving in Development

Django’s default static file handling in development is slow. You can speed it up with WhiteNoise.

Best Practice: Use WhiteNoise

pip install whitenoise

Modify settings.py:

MIDDLEWARE.insert(1, "whitenoise.middleware.WhiteNoiseMiddleware") 
STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"

This serves static files more efficiently and no need for runserver to reload static files.

10. Use reset_queries for Query Performance Testing

Django keeps track of executed SQL queries. You can reset the counter to measure query performance.

Example: Measure Queries for a Function

from django.db import connection, reset_queries 
 
reset_queries()  # Reset query count 
users = User.objects.all()  # Run some queries 
print(len(connection.queries))  # See how many queries were executed

This helps detect unnecessary queries and useful for debugging performance issues.

Final Thoughts

Django has so many hidden secrets that can supercharge your development. The key is to write efficient queries, optimize database performance, and use Django’s built-in features instead of reinventing the wheel.

Which of these Django secrets surprised you the most? Let me know in the comments! 🚀


If you enjoyed this article, I’m sure you’ll love Part 2!

10 Django Secrets No One Talks About (But You Should Know!)
Django is a powerful framework, but there are hidden features and best practices that many developers overlook. These…
Photo by Simone Hutsch on Unsplash