Coding Standard - eqraRahman22/ElderEase GitHub Wiki
This document outlines the coding standards for Python Django projects to ensure consistency, readability, maintainability, and quality across the codebase.
- Follow PEP 8 (Python Enhancement Proposal 8) as the primary style guide unless explicitly overridden in this document.
- Maintain consistent coding patterns across the project (e.g., similar structure for views, models, and templates).
- Use tools like flake8, pylint, or black to enforce consistency automatically.
- Use descriptive, lowercase names with underscores for readability (e.g.,
user_profile
,order_total
). - Avoid single-letter variables except for loop counters (e.g.,
i
,j
). - Use meaningful names that reflect the variable's purpose (e.g.,
is_active
instead offlag
).
- Use uppercase with underscores for constants (e.g.,
MAX_RETRIES
,DEFAULT_TIMEOUT
). - Define constants at the module level or in a dedicated
constants.py
file.
- Use lowercase with underscores for function names (e.g.,
calculate_total
,send_notification
). - Use verbs to indicate actions (e.g.,
get_user
,update_order
). - Avoid generic names like
process
orhandle
.
- Use CamelCase for class names (e.g.,
UserProfile
,OrderManager
). - Use nouns to describe the entity or purpose of the class.
- Avoid abbreviations unless widely accepted (e.g.,
HTTPClient
is acceptable).
- Use lowercase, short, and descriptive names for modules (e.g.,
utils
,models
,views
). - Avoid underscores in module names unless necessary for clarity.
- Use singular names for modules (e.g.,
user
instead ofusers
). - Package names should follow the same rules as modules (e.g.,
core
,auth
).
- Use Django-specific conventions:
- Models: Singular, CamelCase (e.g.,
User
,Order
). - Views: Descriptive, lowercase with underscores (e.g.,
user_detail_view
,order_create
). - URLs: Lowercase with hyphens (e.g.,
user-detail
,order-create
). - Templates: Lowercase with underscores (e.g.,
user_detail.html
,order_form.html
).
- Models: Singular, CamelCase (e.g.,
- Write clear, concise comments to explain why code exists, not what it does (unless the logic is complex).
- Use docstrings for all modules, classes, and functions following Google Python Style Guide or NumPy format.
def calculate_total(order_items): """Calculate the total price of all items in an order. Args: order_items (list): List of order item objects. Returns: float: Total price of the order. """ total = sum(item.price for item in order_items) return total
- Avoid redundant comments (e.g.,
# Set x to 0
forx = 0
). - Document complex algorithms or business logic thoroughly.
- Use inline comments sparingly and only when they add value.
- Use 4 spaces for indentation (no tabs).
- Follow black formatter for consistent code style.
- Use a maximum line length of 88 characters (per black default) or 79 characters for strict PEP 8 compliance.
- Break long lines using parentheses or backslashes for readability:
result = some_function( long_argument_name_1, long_argument_name_2, )
- Align arguments or dictionary values for clarity when breaking lines:
config = { "key1": "value1", "key2": "value2", }
- Use specific exceptions instead of bare
except
:try: user = User.objects.get(id=user_id) except User.DoesNotExist: logger.error(f"User with ID {user_id} not found") raise UserNotFoundError
- Log errors with meaningful context using the
logging
module. - Avoid swallowing exceptions unless absolutely necessary; always log or re-raise.
- Use custom exceptions for domain-specific errors (e.g.,
InvalidOrderError
). - Handle edge cases explicitly in views and APIs (e.g., 404, 400 responses).
- Group imports in the following order:
- Standard library imports
- Third-party imports
- Local application imports
import os import sys from django.http import HttpResponse from rest_framework.views import APIView from myapp.models import User from myapp.utils import send_email
- Use absolute imports over relative imports (e.g.,
from myapp.models import User
instead offrom .models import User
). - Avoid wildcard imports (
from module import *
). - Use isort to automatically sort and format imports.
- Use lowercase with hyphens for URL patterns (e.g.,
user-detail
,order-create
). - Use meaningful, resource-based names (e.g.,
users/
for a list,users/<int:id>/
for a detail). - Include version prefixes for APIs (e.g.,
/api/v1/users/
). - Use Django’s
path()
orre_path()
for clarity:from django.urls import path from . import views urlpatterns = [ path("users/", views.UserListView.as_view(), name="user-list"), path("users/<int:pk>/", views.UserDetailView.as_view(), name="user-detail"), ]
- Use lowercase with underscores for template names (e.g.,
user_list.html
,order_detail.html
). - Keep templates simple; avoid complex logic (use template tags or filters instead).
- Use Django’s built-in template tags and filters where possible.
- Organize templates in a directory structure mirroring the app:
myapp/ templates/ myapp/ user_list.html user_detail.html
- Use consistent indentation (2 or 4 spaces, matching Python code).
- Include comments for template blocks or complex logic:
{% comment %} Display user details {% endcomment %} <div class="user-details"> {{ user.name }} </div>
- Write self-explanatory code with meaningful variable and function names.
- Break complex logic into smaller, reusable functions or methods.
- Avoid nested code blocks deeper than 3 levels; refactor if necessary.
- Use list comprehensions and generator expressions for concise, readable code:
# Good squares = [x**2 for x in range(10)] # Bad squares = [] for x in range(10): squares.append(x**2)
- Use type hints for better readability and IDE support:
def get_user(user_id: int) -> User: return User.objects.get(id=user_id)
- Write modular code with reusable components (e.g., mixins, utility functions, custom template tags).
- Use Django’s generic views or class-based views for common patterns.
- Create utility modules for common tasks (e.g.,
utils.py
for email sending, file handling). - Avoid duplicating code; refactor repeated logic into functions or classes.
- Write unit tests for all critical functionality using Django’s
TestCase
orunittest
. - Aim for at least 80% code coverage; use coverage.py to measure.
- Use factories (e.g.,
factory_boy
) for test data creation:import factory from myapp.models import User class UserFactory(factory.django.DjangoModelFactory): class Meta: model = User name = factory.Faker("name") email = factory.Faker("email")
- Test views, models, forms, and APIs separately.
- Use pytest or Django’s test runner for testing.
- Include integration tests for critical workflows.
- Use Django’s built-in security features (e.g., CSRF protection, XSS escaping).
- Validate and sanitize all user inputs using Django forms or serializers.
- Use
settings.SECURE_SSL_REDIRECT
andSECURE_HSTS_SECONDS
for HTTPS. - Avoid raw SQL queries; use Django ORM to prevent SQL injection.
- Store sensitive data (e.g., API keys) in environment variables using
python-decouple
. - Follow OWASP guidelines for secure coding practices.
- Limit lines to 88 characters (black default) or 79 characters (PEP 8).
- Break long lines using parentheses, brackets, or backslashes:
long_query = ( Model.objects.filter(field1=value1) .exclude(field2=value2) .order_by("field3") )
- Avoid breaking lines unnecessarily for short expressions.
- Use single spaces around operators and after commas:
x = 1 + 2 my_list = [1, 2, 3]
- Avoid trailing whitespace; use linters to enforce.
- Use blank lines sparingly to separate logical sections:
def process_data(data): cleaned_data = clean(data) result = analyze(cleaned_data) return result
- Use a single leading underscore for protected attributes or methods (e.g.,
_protected_method
). - Use double leading underscores for private attributes or methods (e.g.,
__private_method
), but sparingly. - Prefer explicit public methods for APIs and interfaces.
- Document access levels in docstrings if non-standard:
class MyClass: def _protected_method(self): """Protected method for internal use.""" pass