This document outlines the conventions and best practices for models in this Django project. Following these guidelines ensures consistency, maintainability, and best practices throughout the codebase.
- Models inherit from
models.Model - Common behaviors are implemented as mixins (e.g.,
Timestampable) - Abstract base classes are used for shared functionality (e.g.,
AbstractUser)
- Fields are grouped logically
- Field options are consistently ordered:
max_length,null,blank,default, other options - Proper use of
null=Trueandblank=Truebased on field type- CharField/TextField: Use
blank=True, default="" - Other fields: Use both
null=True, blank=Truewhen optional
- CharField/TextField: Use
The standard model structure follows this order:
- Field definitions
- Model properties (using
@propertydecorator) - Model methods
- Meta class (if needed)
- Related forms (in same file)
- Use lowercase with underscores (snake_case)
- Boolean fields should start with
is_orhas_ - Date/time fields should end with
_at(e.g.,activated_at,reviewed_at) - Foreign keys should use the model name in singular form and reference with a string (e.g.,
"app.Author","common.User") - Related names should be plural (e.g.,
related_name="addresses")
- Use descriptive names that indicate the return value
- Property names should be nouns (e.g.,
inline_string,serialized) - Boolean properties should start with
is_orhas_ - Methods should use verb phrases (e.g.,
get_absolute_url())
- Complex models should have docstrings explaining their purpose
- Include key attributes and properties in the docstring
- Document any special behaviors or important notes
- Example:
class Upload(models.Model): """ A model representing an uploaded file, including its metadata and properties. Attributes: original (str): The original URL of the uploaded file name (str): The name of the file ... """
- Properties should be used for computed values
- Complex properties should include type hints
- Properties that require heavy computation should be cached if frequently accessed
The project uses abstract behavior mixins to encapsulate common model behaviors. These are located in apps/common/behaviors/.
Timestampable: Addscreated_atandmodified_atfields with automatic updatesPublishable: Manages content publishing workflow withis_published,published_at, andunpublished_atAuthorable: Tracks content authors with anonymous option (author,authored_at,is_author_anonymous)Locatable: Adds location data with address and coordinate fieldsPermalinkable: Manages URL slugs and permalink generation withslugfieldExpirable: Handles content expiration withexpired_atfield and validity trackingAnnotatable: Provides notes relationship management for adding annotations to models
For detailed usage examples of these behaviors, see the BlogPost model in apps/common/models/blog_post.py, which demonstrates all available behaviors in a real-world example.
-
Abstract Base Classes
- All behaviors must inherit from
models.Model - Must include
abstract = Truein Meta class - Should focus on a single responsibility
- All behaviors must inherit from
-
Documentation
- Include comprehensive docstrings
- List all fields and their purposes
- Document any properties or methods
- Include usage examples if complex
-
Field Naming
- Use consistent suffixes:
- Timestamps end with
_at(e.g.,created_at,published_at) - Boolean flags start with
is_(e.g.,is_published,is_author_anonymous) - Foreign keys use singular form (e.g.,
author)
- Timestamps end with
- Use consistent suffixes:
-
Properties and Methods
- Implement property getters and setters for boolean states
- especially when the state is defined by a datetime field (eg.
is_expiredforexpired_at < now())
- especially when the state is defined by a datetime field (eg.
- Include helper methods for common operations
- Use clear, action-oriented names for methods (e.g.,
publish(),unpublish())
- Implement property getters and setters for boolean states
-
Related Names
- Use
%(class)sfor dynamic related names - This allows the same behavior to be used in multiple models
- Use
class MyModel(Timestampable, Publishable, models.Model):
# Your model fields here
pass- Override
__str__method for human-readable representation - Implement
serializedproperty for API responses - Keep model methods focused on model-specific logic
- Use proper error handling in model methods
- Use type hints for all methods and properties
- Follow verb phrases for methods, nouns for properties
- Use appropriate field types for the data
- Set reasonable field lengths for CharFields
- Use JSONField for flexible schema data
- Implement proper on_delete behavior for foreign keys
- Never store sensitive information in plain text
- Use proper field types for sensitive data (e.g., encrypted fields)
- Implement proper access controls at the model level
- Index fields used in frequent lookups
- Use select_related() and prefetch_related() for related field queries
- Consider adding db_index=True for frequently queried fields
- Forms related to a model should be defined in a separate file in the
apps/<app_name>/forms/directory - Use ModelForm when possible
- Explicitly specify fields in Meta class
- Add appropriate widgets and validation
- Each model should have corresponding test cases in
apps/<app_name>/tests/test_models/ - Test edge cases and validation
- Include tests for model methods and properties
- Test database constraints and unique fields
- Use factory classes in
apps/common/tests/factories.pyto create test instances - Test behavior mixins in
apps/common/tests/behaviors.pywith both database-backed and direct approaches - Aim for 100% test coverage for models and behavior mixins
- For more details on testing behavior mixins, see BEHAVIOR_MIXINS.md
- Keep migrations focused and atomic
- Review migration files before committing
- Test migrations, especially for large data sets
- Document any manual steps required for migrations
- Include meaningful commit messages for model changes
- Document breaking changes in model structure
- Keep track of deprecated fields and methods
Remember to follow these conventions when creating or modifying models to maintain consistency across the project.