IntroWhy Allauth's Headless Mode is the Optimal Choice for Authentication in DjangoBest Practices for Handling Operations on Django Model Properties
Â
Note: This is a living document!
Intro
Django is an amazing framework. If you landed here, you probably already know that but let me try to highlight a few key functions.
Batteries included… yes, the famous tagline. It does indeed come with lots of incredible features built-in. You get authentication, a super-nice admin panel and an opinionated way to do certain things for your app or api.
However, Django does get tangled because in certain areas, there are no concise opinions. The community is divided on such things. I’ve tried to capture all such thoughts, comments and criticisms on this page.
Â
Why Allauth's Headless Mode is the Optimal Choice for Authentication in Django
The tried and tested allauth package provides a headless mode, I recommend using that as it provides native integration with allauth and minimizes the code you need to override.
I’ve used dj-rest-auth and django-rest-auth in the past and both are fantastic packages however I try to minimize the use of extra dependencies and prefer keeping logic for one module contained. Using allauth’s headless mode allows you to do that.
Â
Â
Best Practices for Handling Operations on Django Model Properties
In Django, best practices for handling operations on model properties revolve around maintaining clean, maintainable, and efficient code. Here are the guidelines for what types of operations you can and cannot (or should not) put on a Django model's properties.
Operations You CAN Put on a Django Model's Properties
- Simple Computed Properties
- Use Python's
@property
decorator for computed attributes based on other model fields. - Example:
class Product(models.Model): price = models.DecimalField(max_digits=10, decimal_places=2) discount = models.DecimalField(max_digits=10, decimal_places=2) @property def discounted_price(self): return self.price - self.discount
- Data Formatting
- Add methods or properties to format data for display or use in templates.
- Example:
@property def formatted_price(self): return f"${self.price:.2f}"
- Business Logic That Doesn't Change Database State
- You can use methods or properties to encapsulate non-database-changing logic.
- Example:
@property def is_eligible_for_free_shipping(self): return self.price > 100
- Foreign Key/Related Field Computations
- Safely compute values based on related fields.
- Example:
@property def total_order_price(self): return sum(item.price for item in self.order_items.all())
- Serialization Helpers
- Add properties for structured or human-readable representations, e.g.,
full_name
for combiningfirst_name
andlast_name
.
Operations You CANNOT/SHOULD NOT Put on a Django Model's Properties
- Database Queries in Properties
- Avoid making database queries within properties, especially in loops or iterative logic, as they can lead to inefficient queries (N+1 problem).
- Example (Bad Practice):
- Better Alternative: Use
annotate()
orprefetch_related()
in your query to calculate related data at the database level.
@property def expensive_property(self): return self.related_set.count() # Avoid if accessed frequently
- State-Changing Operations
- Avoid modifying or saving data in a property method. Properties should remain read-only.
- Example (Bad Practice):
@property def update_status(self): self.status = 'completed' # Don't do this self.save()
- Long or Complex Logic
- Properties should remain concise and focused. Use helper methods or utility classes for complex logic.
- Example:
def calculate_complex_value(self): # Perform complex operations here pass
- External API Calls
- Avoid embedding API calls or any external dependencies inside properties. This can slow down your application and make debugging harder.
- Error-Prone or Unintended Mutations
- Avoid mutable state within properties, as it can lead to bugs and unintended side effects.