π Coding Standards & Style Guide
π Q9 Coding Standards & Style Guide
Overview
This guide documents the coding standards and conventions used throughout the Q9 project. Following these standards ensures consistency, maintainability, and a cohesive user experience.
π URL Conventions
REST-style URLs
β DO
/projects/
/projects/123/
/projects/123/workers/
/tasks/
/contacts/
/projects/
/projects/123/
/projects/123/workers/
/tasks/
/contacts/
Use Underscores (NOT Hyphens)
β DO
path('task_create/', views.TaskCreateView.as_view(), name='task_create')
path('contact_list/', views.ContactListView.as_view(), name='contact_list')
path('task_create/', views.TaskCreateView.as_view(), name='task_create')
path('contact_list/', views.ContactListView.as_view(), name='contact_list')
β DON'T
path('task-create/', ...)
path('contact-list/', ...)
path('task-create/', ...)
path('contact-list/', ...)
URL Namespacing
β DO
# In app's urls.py
app_name = 'events'
# In templates
{% url 'events:event_list' %}
{% url 'events:event_create' %}
ποΈ View Patterns
Class-Based Views for CRUD
β DO
class ContactListView(LoginRequiredMixin, SingleTableMixin, FilterView):
model = Contact
table_class = ContactTable
filterset_class = ContactFilter
template_name = 'contacts/contact_list.html'
class ContactListView(LoginRequiredMixin, SingleTableMixin, FilterView):
model = Contact
table_class = ContactTable
filterset_class = ContactFilter
template_name = 'contacts/contact_list.html'
Always Filter by User
β DO
def get_queryset(self):
return Task.objects.filter(user=self.request.user)
def get_queryset(self):
return Task.objects.filter(user=self.request.user)
β DON'T
def get_queryset(self):
return Task.objects.all() # Security risk!
def get_queryset(self):
return Task.objects.all() # Security risk!
π Template Organization
Directory Structure
app_name/templates/app_name/
βββ model_list.html
βββ model_detail.html
βββ model_form.html (for create/edit)
βββ partials/
βββ _model_row.html
βββ model_list.html
βββ model_detail.html
βββ model_form.html (for create/edit)
βββ partials/
βββ _model_row.html
Template Naming
β DO
contacts/contact_list.html
contacts/contact_detail.html
contacts/contact_form.html
contacts/partials/_contact_row.html
contacts/contact_list.html
contacts/contact_detail.html
contacts/contact_form.html
contacts/partials/_contact_row.html
ποΈ Model Conventions
Required Fields
β DO
class Contact(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
# Optional project association
project = models.ForeignKey(Project, null=True, blank=True)
class Contact(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
# Optional project association
project = models.ForeignKey(Project, null=True, blank=True)
UUID Primary Keys (When Appropriate)
import uuid
class File(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
class File(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
π¨ UI Components
Retro Windows 95 Style
β DO
{% retro_window "π My Notes" %}
{% render_table table %}
{% endretro_window %}
Button Styling
β DO
{% retro_button "Save" btn_type="primary" %}
{% retro_link_button url "Edit" btn_type="secondary" %}
Emoji Usage
β DO
{% block body_title %}π Notes{% endblock %}
π Home
{% retro_button "β Add New" %}
π± Responsive Design
Column Classes
β DO
<div class="retro-col-12 retro-col-md-8">Content</div>
<div class="retro-col-12 retro-col-md-4">Sidebar</div>
<div class="retro-col-12 retro-col-md-8">Content</div>
<div class="retro-col-12 retro-col-md-4">Sidebar</div>
Mobile Touch Targets
.retro-btn {
min-height: 44px; /* Apple's recommendation */
padding: 10px 16px;
font-size: 16px; /* Prevents iOS zoom */
}
min-height: 44px; /* Apple's recommendation */
padding: 10px 16px;
font-size: 16px; /* Prevents iOS zoom */
}
Table Handling
β DO
{% render_table table %}
/* CSS */
.retro-table-wrapper {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
π Dark Mode Support
Forum-Style Light Wrapper Approach
@media (prefers-color-scheme: dark) {
main {
background-color: #c0c0c0 !important;
}
.retro-window-content,
.retro-table-wrapper {
background: #ffffff !important;
color: #000000 !important;
}
}
main {
background-color: #c0c0c0 !important;
}
.retro-window-content,
.retro-table-wrapper {
background: #ffffff !important;
color: #000000 !important;
}
}
Window Titles
.retro-window-title {
background: #000080 !important;
color: #ffffff !important;
}
background: #000080 !important;
color: #ffffff !important;
}
π§ͺ Testing Standards
Test Setup
β DO
# Set environment variable before running tests
export CELERY_BROKER_URL=redis://localhost:6379/0
python manage.py test --settings=q9.settings.test
# Set environment variable before running tests
export CELERY_BROKER_URL=redis://localhost:6379/0
python manage.py test --settings=q9.settings.test
Test User Creation
β DO
from django.contrib.auth import get_user_model
from allauth.account.models import EmailAddress
User = get_user_model()
self.user = User.objects.create_user(
username='testuser',
email='test@example.com',
password='testpass123'
)
# Create verified email for allauth
EmailAddress.objects.create(
user=self.user,
email=self.user.email,
verified=True,
primary=True
)
from django.contrib.auth import get_user_model
from allauth.account.models import EmailAddress
User = get_user_model()
self.user = User.objects.create_user(
username='testuser',
email='test@example.com',
password='testpass123'
)
# Create verified email for allauth
EmailAddress.objects.create(
user=self.user,
email=self.user.email,
verified=True,
primary=True
)
π Security Practices
Row-Level Security
β DO
# Always filter by user
queryset = Model.objects.filter(user=request.user)
# Always filter by user
queryset = Model.objects.filter(user=request.user)
Form Security
β DO
def form_valid(self, form):
form.instance.user = self.request.user
return super().form_valid(form)
def form_valid(self, form):
form.instance.user = self.request.user
return super().form_valid(form)
Never Expose Secrets
β DON'T
SECRET_KEY = 'hardcoded-secret-key'
API_KEY = 'my-api-key-12345'
SECRET_KEY = 'hardcoded-secret-key'
API_KEY = 'my-api-key-12345'
β DO
SECRET_KEY = env('SECRET_KEY')
API_KEY = env('API_KEY')
SECRET_KEY = env('SECRET_KEY')
API_KEY = env('API_KEY')
π Additional Resources
- π¨ Design System - Interactive component showcase
- π Documentation - General documentation
- π§ Django Admin - For superusers