chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,264 @@
|
||||
# Django Admin Configuration
|
||||
|
||||
Configure Django admin interface with custom admin classes and functionality.
|
||||
|
||||
## Purpose
|
||||
|
||||
This command helps you create comprehensive Django admin configurations with advanced features and customizations.
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
/admin
|
||||
```
|
||||
|
||||
## What this command does
|
||||
|
||||
1. **Registers models** with custom admin classes
|
||||
2. **Creates advanced admin interfaces** with filtering, search, and actions
|
||||
3. **Adds inline editing** for related models
|
||||
4. **Customizes list displays** and forms
|
||||
5. **Implements admin actions** for bulk operations
|
||||
|
||||
## Example Output
|
||||
|
||||
```python
|
||||
# admin.py
|
||||
from django.contrib import admin
|
||||
from django.utils.html import format_html
|
||||
from django.urls import reverse
|
||||
from django.utils.safestring import mark_safe
|
||||
from .models import Post, Category, Tag, Comment
|
||||
|
||||
@admin.register(Category)
|
||||
class CategoryAdmin(admin.ModelAdmin):
|
||||
"""Admin configuration for Category model."""
|
||||
list_display = ['name', 'slug', 'post_count', 'created_at']
|
||||
list_filter = ['created_at']
|
||||
search_fields = ['name', 'description']
|
||||
prepopulated_fields = {'slug': ('name',)}
|
||||
readonly_fields = ['created_at', 'updated_at']
|
||||
|
||||
def post_count(self, obj):
|
||||
"""Display number of posts in this category."""
|
||||
count = obj.posts.count()
|
||||
url = reverse('admin:blog_post_changelist') + f'?category__id__exact={obj.id}'
|
||||
return format_html('<a href="{}">{} posts</a>', url, count)
|
||||
post_count.short_description = 'Posts'
|
||||
|
||||
class CommentInline(admin.TabularInline):
|
||||
"""Inline admin for comments."""
|
||||
model = Comment
|
||||
extra = 0
|
||||
readonly_fields = ['created_at', 'author']
|
||||
fields = ['author', 'content', 'is_approved', 'created_at']
|
||||
|
||||
@admin.register(Post)
|
||||
class PostAdmin(admin.ModelAdmin):
|
||||
"""Advanced admin configuration for Post model."""
|
||||
list_display = [
|
||||
'title',
|
||||
'author',
|
||||
'category',
|
||||
'status',
|
||||
'view_count',
|
||||
'created_at',
|
||||
'post_preview'
|
||||
]
|
||||
list_filter = [
|
||||
'status',
|
||||
'category',
|
||||
'created_at',
|
||||
'updated_at',
|
||||
('author', admin.RelatedOnlyFieldListFilter)
|
||||
]
|
||||
search_fields = ['title', 'content', 'author__username']
|
||||
prepopulated_fields = {'slug': ('title',)}
|
||||
readonly_fields = ['created_at', 'updated_at', 'view_count', 'post_preview']
|
||||
|
||||
# Custom form layout
|
||||
fieldsets = (
|
||||
('Content', {
|
||||
'fields': ('title', 'slug', 'content', 'status')
|
||||
}),
|
||||
('Metadata', {
|
||||
'fields': ('author', 'category', 'tags'),
|
||||
'classes': ('collapse',)
|
||||
}),
|
||||
('SEO', {
|
||||
'fields': ('meta_description', 'meta_keywords'),
|
||||
'classes': ('collapse',)
|
||||
}),
|
||||
('Timestamps', {
|
||||
'fields': ('created_at', 'updated_at', 'view_count'),
|
||||
'classes': ('collapse',)
|
||||
}),
|
||||
)
|
||||
|
||||
# Many-to-many field display
|
||||
filter_horizontal = ['tags']
|
||||
|
||||
# Inline models
|
||||
inlines = [CommentInline]
|
||||
|
||||
# Custom list display methods
|
||||
def post_preview(self, obj):
|
||||
"""Show thumbnail preview of post."""
|
||||
if obj.featured_image:
|
||||
return format_html(
|
||||
'<img src="{}" width="50" height="50" style="border-radius: 5px;" />',
|
||||
obj.featured_image.url
|
||||
)
|
||||
return "No image"
|
||||
post_preview.short_description = 'Preview'
|
||||
|
||||
# Custom admin actions
|
||||
actions = ['make_published', 'make_draft', 'duplicate_posts']
|
||||
|
||||
def make_published(self, request, queryset):
|
||||
"""Bulk action to publish selected posts."""
|
||||
updated = queryset.update(status='published')
|
||||
self.message_user(
|
||||
request,
|
||||
f'{updated} posts were successfully marked as published.'
|
||||
)
|
||||
make_published.short_description = "Mark selected posts as published"
|
||||
|
||||
def make_draft(self, request, queryset):
|
||||
"""Bulk action to set selected posts as draft."""
|
||||
updated = queryset.update(status='draft')
|
||||
self.message_user(
|
||||
request,
|
||||
f'{updated} posts were successfully marked as draft.'
|
||||
)
|
||||
make_draft.short_description = "Mark selected posts as draft"
|
||||
|
||||
def duplicate_posts(self, request, queryset):
|
||||
"""Bulk action to duplicate selected posts."""
|
||||
count = 0
|
||||
for post in queryset:
|
||||
post.pk = None # Create new instance
|
||||
post.title = f"Copy of {post.title}"
|
||||
post.slug = f"copy-of-{post.slug}"
|
||||
post.status = 'draft'
|
||||
post.save()
|
||||
count += 1
|
||||
|
||||
self.message_user(
|
||||
request,
|
||||
f'{count} posts were successfully duplicated.'
|
||||
)
|
||||
duplicate_posts.short_description = "Duplicate selected posts"
|
||||
|
||||
@admin.register(Tag)
|
||||
class TagAdmin(admin.ModelAdmin):
|
||||
"""Admin configuration for Tag model."""
|
||||
list_display = ['name', 'slug', 'post_count', 'color_preview']
|
||||
search_fields = ['name']
|
||||
prepopulated_fields = {'slug': ('name',)}
|
||||
|
||||
def post_count(self, obj):
|
||||
"""Display number of posts with this tag."""
|
||||
return obj.posts.count()
|
||||
post_count.short_description = 'Posts'
|
||||
|
||||
def color_preview(self, obj):
|
||||
"""Show color preview if tag has color field."""
|
||||
if hasattr(obj, 'color') and obj.color:
|
||||
return format_html(
|
||||
'<span style="background-color: {}; padding: 2px 8px; border-radius: 3px; color: white;">{}</span>',
|
||||
obj.color,
|
||||
obj.name
|
||||
)
|
||||
return obj.name
|
||||
color_preview.short_description = 'Preview'
|
||||
|
||||
@admin.register(Comment)
|
||||
class CommentAdmin(admin.ModelAdmin):
|
||||
"""Admin configuration for Comment model."""
|
||||
list_display = ['author', 'post', 'content_preview', 'is_approved', 'created_at']
|
||||
list_filter = ['is_approved', 'created_at', 'post__category']
|
||||
search_fields = ['content', 'author__username', 'post__title']
|
||||
readonly_fields = ['created_at', 'updated_at']
|
||||
actions = ['approve_comments', 'disapprove_comments']
|
||||
|
||||
def content_preview(self, obj):
|
||||
"""Show truncated content preview."""
|
||||
return obj.content[:50] + "..." if len(obj.content) > 50 else obj.content
|
||||
content_preview.short_description = 'Content'
|
||||
|
||||
def approve_comments(self, request, queryset):
|
||||
"""Bulk approve comments."""
|
||||
updated = queryset.update(is_approved=True)
|
||||
self.message_user(request, f'{updated} comments were approved.')
|
||||
approve_comments.short_description = "Approve selected comments"
|
||||
|
||||
def disapprove_comments(self, request, queryset):
|
||||
"""Bulk disapprove comments."""
|
||||
updated = queryset.update(is_approved=False)
|
||||
self.message_user(request, f'{updated} comments were disapproved.')
|
||||
disapprove_comments.short_description = "Disapprove selected comments"
|
||||
|
||||
# Custom admin site configuration
|
||||
admin.site.site_header = "Blog Administration"
|
||||
admin.site.site_title = "Blog Admin Portal"
|
||||
admin.site.index_title = "Welcome to Blog Administration"
|
||||
```
|
||||
|
||||
## Advanced Features
|
||||
|
||||
### Custom List Display
|
||||
- **Thumbnail previews** for images
|
||||
- **Related object counts** with links
|
||||
- **Status indicators** with colors
|
||||
- **Custom formatting** for data display
|
||||
|
||||
### Filtering and Search
|
||||
- **Advanced filters** including date ranges
|
||||
- **Related field filtering** for foreign keys
|
||||
- **Search across multiple fields** including relations
|
||||
- **Custom filter classes** for complex queries
|
||||
|
||||
### Inline Editing
|
||||
- **TabularInline** for compact editing
|
||||
- **StackedInline** for detailed forms
|
||||
- **Custom inline forms** with additional functionality
|
||||
- **Readonly fields** in inlines
|
||||
|
||||
### Bulk Actions
|
||||
- **Status changes** for multiple objects
|
||||
- **Data export** functionality
|
||||
- **Batch operations** for efficiency
|
||||
- **Custom business logic** in actions
|
||||
|
||||
### Form Customization
|
||||
- **Fieldsets** for organized layouts
|
||||
- **Collapsed sections** for advanced options
|
||||
- **Custom widgets** for better UX
|
||||
- **Validation** and error handling
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- **Permission checks** in custom methods
|
||||
- **Input sanitization** in admin actions
|
||||
- **CSRF protection** (automatic)
|
||||
- **User authentication** (built-in)
|
||||
|
||||
## Performance Optimization
|
||||
|
||||
```python
|
||||
# Optimize queries with select_related/prefetch_related
|
||||
class PostAdmin(admin.ModelAdmin):
|
||||
def get_queryset(self, request):
|
||||
queryset = super().get_queryset(request)
|
||||
return queryset.select_related('author', 'category').prefetch_related('tags')
|
||||
```
|
||||
|
||||
## Custom Admin Templates
|
||||
|
||||
```python
|
||||
# Override admin templates
|
||||
class PostAdmin(admin.ModelAdmin):
|
||||
change_form_template = 'admin/blog/post/change_form.html'
|
||||
change_list_template = 'admin/blog/post/change_list.html'
|
||||
```
|
||||
@@ -0,0 +1,124 @@
|
||||
# Django Model Generator
|
||||
|
||||
Create Django models with proper structure and relationships.
|
||||
|
||||
## Purpose
|
||||
|
||||
This command helps you quickly create Django models with fields, relationships, and best practices.
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
/django-model
|
||||
```
|
||||
|
||||
## What this command does
|
||||
|
||||
1. **Creates model classes** with proper field definitions
|
||||
2. **Adds relationships** (ForeignKey, ManyToMany, OneToOne)
|
||||
3. **Includes meta options** and model methods
|
||||
4. **Generates migrations** automatically
|
||||
5. **Follows Django conventions** and best practices
|
||||
|
||||
## Example Output
|
||||
|
||||
```python
|
||||
# models.py
|
||||
from django.db import models
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
class Category(models.Model):
|
||||
name = models.CharField(max_length=100, unique=True)
|
||||
slug = models.SlugField(unique=True)
|
||||
description = models.TextField(blank=True)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name_plural = "categories"
|
||||
ordering = ['name']
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Post(models.Model):
|
||||
STATUS_CHOICES = [
|
||||
('draft', 'Draft'),
|
||||
('published', 'Published'),
|
||||
('archived', 'Archived'),
|
||||
]
|
||||
|
||||
title = models.CharField(max_length=200)
|
||||
slug = models.SlugField(unique=True)
|
||||
content = models.TextField()
|
||||
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='draft')
|
||||
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='posts')
|
||||
category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True, blank=True)
|
||||
tags = models.ManyToManyField('Tag', blank=True)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
class Meta:
|
||||
ordering = ['-created_at']
|
||||
verbose_name = 'blog post'
|
||||
verbose_name_plural = 'blog posts'
|
||||
|
||||
def __str__(self):
|
||||
return self.title
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('post_detail', kwargs={'slug': self.slug})
|
||||
|
||||
class Tag(models.Model):
|
||||
name = models.CharField(max_length=50, unique=True)
|
||||
slug = models.SlugField(unique=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
```
|
||||
|
||||
## Field Types Supported
|
||||
|
||||
- **CharField** - Text fields with max length
|
||||
- **TextField** - Large text fields
|
||||
- **IntegerField** - Integer numbers
|
||||
- **FloatField** - Floating point numbers
|
||||
- **BooleanField** - True/False values
|
||||
- **DateField** - Date only
|
||||
- **DateTimeField** - Date and time
|
||||
- **EmailField** - Email addresses
|
||||
- **URLField** - URLs
|
||||
- **ImageField** - Image uploads
|
||||
- **FileField** - File uploads
|
||||
- **JSONField** - JSON data (PostgreSQL)
|
||||
|
||||
## Relationships
|
||||
|
||||
- **ForeignKey** - One-to-many relationships
|
||||
- **ManyToManyField** - Many-to-many relationships
|
||||
- **OneToOneField** - One-to-one relationships
|
||||
|
||||
## Best Practices Included
|
||||
|
||||
- Proper field choices and defaults
|
||||
- Appropriate related_name attributes
|
||||
- __str__ methods for admin interface
|
||||
- Meta class with ordering and verbose names
|
||||
- get_absolute_url methods where appropriate
|
||||
- Proper use of null and blank parameters
|
||||
- Field validation and constraints
|
||||
|
||||
## After Creating Models
|
||||
|
||||
```bash
|
||||
# Create and apply migrations
|
||||
python manage.py makemigrations
|
||||
python manage.py migrate
|
||||
|
||||
# Register in admin (optional)
|
||||
# Add to admin.py:
|
||||
from django.contrib import admin
|
||||
from .models import Post, Category, Tag
|
||||
|
||||
admin.site.register([Post, Category, Tag])
|
||||
```
|
||||
@@ -0,0 +1,222 @@
|
||||
# Django Views Generator
|
||||
|
||||
Create Django views with proper structure and best practices.
|
||||
|
||||
## Purpose
|
||||
|
||||
This command helps you quickly create Django views (Function-Based Views and Class-Based Views) following Django conventions.
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
/views
|
||||
```
|
||||
|
||||
## What this command does
|
||||
|
||||
1. **Creates view functions/classes** with proper structure
|
||||
2. **Handles HTTP methods** (GET, POST, PUT, DELETE)
|
||||
3. **Includes form handling** and validation
|
||||
4. **Adds authentication/authorization** checks
|
||||
5. **Follows Django best practices** and security guidelines
|
||||
|
||||
## Example Output
|
||||
|
||||
```python
|
||||
# views.py
|
||||
from django.shortcuts import render, get_object_or_404, redirect
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib import messages
|
||||
from django.http import JsonResponse
|
||||
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.urls import reverse_lazy
|
||||
from .models import Post, Category
|
||||
from .forms import PostForm
|
||||
|
||||
# Function-Based Views
|
||||
def post_list(request):
|
||||
"""Display list of posts with pagination and filtering."""
|
||||
posts = Post.objects.filter(status='published').select_related('author', 'category')
|
||||
|
||||
# Search functionality
|
||||
search_query = request.GET.get('search')
|
||||
if search_query:
|
||||
posts = posts.filter(title__icontains=search_query)
|
||||
|
||||
# Category filtering
|
||||
category_id = request.GET.get('category')
|
||||
if category_id:
|
||||
posts = posts.filter(category_id=category_id)
|
||||
|
||||
context = {
|
||||
'posts': posts,
|
||||
'categories': Category.objects.all(),
|
||||
'search_query': search_query,
|
||||
}
|
||||
return render(request, 'blog/post_list.html', context)
|
||||
|
||||
def post_detail(request, slug):
|
||||
"""Display individual post details."""
|
||||
post = get_object_or_404(Post, slug=slug, status='published')
|
||||
|
||||
context = {
|
||||
'post': post,
|
||||
'related_posts': Post.objects.filter(
|
||||
category=post.category,
|
||||
status='published'
|
||||
).exclude(id=post.id)[:3]
|
||||
}
|
||||
return render(request, 'blog/post_detail.html', context)
|
||||
|
||||
@login_required
|
||||
def post_create(request):
|
||||
"""Create new post."""
|
||||
if request.method == 'POST':
|
||||
form = PostForm(request.POST, request.FILES)
|
||||
if form.is_valid():
|
||||
post = form.save(commit=False)
|
||||
post.author = request.user
|
||||
post.save()
|
||||
form.save_m2m() # Save many-to-many relationships
|
||||
messages.success(request, 'Post created successfully!')
|
||||
return redirect('post_detail', slug=post.slug)
|
||||
else:
|
||||
form = PostForm()
|
||||
|
||||
return render(request, 'blog/post_form.html', {'form': form})
|
||||
|
||||
@login_required
|
||||
def post_edit(request, slug):
|
||||
"""Edit existing post."""
|
||||
post = get_object_or_404(Post, slug=slug, author=request.user)
|
||||
|
||||
if request.method == 'POST':
|
||||
form = PostForm(request.POST, request.FILES, instance=post)
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
messages.success(request, 'Post updated successfully!')
|
||||
return redirect('post_detail', slug=post.slug)
|
||||
else:
|
||||
form = PostForm(instance=post)
|
||||
|
||||
return render(request, 'blog/post_form.html', {
|
||||
'form': form,
|
||||
'post': post
|
||||
})
|
||||
|
||||
# Class-Based Views
|
||||
class PostListView(ListView):
|
||||
"""List view for posts with pagination."""
|
||||
model = Post
|
||||
template_name = 'blog/post_list.html'
|
||||
context_object_name = 'posts'
|
||||
paginate_by = 10
|
||||
|
||||
def get_queryset(self):
|
||||
return Post.objects.filter(status='published').select_related('author', 'category')
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['categories'] = Category.objects.all()
|
||||
return context
|
||||
|
||||
class PostDetailView(DetailView):
|
||||
"""Detail view for individual posts."""
|
||||
model = Post
|
||||
template_name = 'blog/post_detail.html'
|
||||
context_object_name = 'post'
|
||||
|
||||
def get_queryset(self):
|
||||
return Post.objects.filter(status='published')
|
||||
|
||||
class PostCreateView(LoginRequiredMixin, CreateView):
|
||||
"""Create view for new posts."""
|
||||
model = Post
|
||||
form_class = PostForm
|
||||
template_name = 'blog/post_form.html'
|
||||
|
||||
def form_valid(self, form):
|
||||
form.instance.author = self.request.user
|
||||
return super().form_valid(form)
|
||||
|
||||
class PostUpdateView(LoginRequiredMixin, UpdateView):
|
||||
"""Update view for existing posts."""
|
||||
model = Post
|
||||
form_class = PostForm
|
||||
template_name = 'blog/post_form.html'
|
||||
|
||||
def get_queryset(self):
|
||||
return Post.objects.filter(author=self.request.user)
|
||||
|
||||
class PostDeleteView(LoginRequiredMixin, DeleteView):
|
||||
"""Delete view for posts."""
|
||||
model = Post
|
||||
template_name = 'blog/post_confirm_delete.html'
|
||||
success_url = reverse_lazy('post_list')
|
||||
|
||||
def get_queryset(self):
|
||||
return Post.objects.filter(author=self.request.user)
|
||||
|
||||
# API Views
|
||||
def api_post_list(request):
|
||||
"""API endpoint for post list."""
|
||||
posts = Post.objects.filter(status='published').values(
|
||||
'id', 'title', 'slug', 'created_at', 'author__username'
|
||||
)
|
||||
return JsonResponse(list(posts), safe=False)
|
||||
```
|
||||
|
||||
## View Types Supported
|
||||
|
||||
- **Function-Based Views (FBV)** - Simple, explicit control
|
||||
- **Class-Based Views (CBV)** - Reusable, inheritance-based
|
||||
- **Generic Views** - ListView, DetailView, CreateView, etc.
|
||||
- **API Views** - JSON responses for AJAX/API calls
|
||||
|
||||
## Features Included
|
||||
|
||||
- **Authentication checks** with decorators/mixins
|
||||
- **Permission handling** for user authorization
|
||||
- **Form processing** with validation
|
||||
- **Error handling** and user feedback
|
||||
- **SEO-friendly URLs** with slugs
|
||||
- **Database optimization** with select_related/prefetch_related
|
||||
- **Pagination** for large datasets
|
||||
- **Search and filtering** functionality
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
- CSRF protection (automatic with forms)
|
||||
- User authentication and authorization
|
||||
- SQL injection prevention (ORM)
|
||||
- XSS protection with template escaping
|
||||
- Proper error handling
|
||||
|
||||
## URL Configuration
|
||||
|
||||
```python
|
||||
# urls.py
|
||||
from django.urls import path
|
||||
from . import views
|
||||
|
||||
app_name = 'blog'
|
||||
|
||||
urlpatterns = [
|
||||
# Function-based views
|
||||
path('', views.post_list, name='post_list'),
|
||||
path('post/<slug:slug>/', views.post_detail, name='post_detail'),
|
||||
path('create/', views.post_create, name='post_create'),
|
||||
path('edit/<slug:slug>/', views.post_edit, name='post_edit'),
|
||||
|
||||
# Class-based views
|
||||
path('posts/', views.PostListView.as_view(), name='post_list_cbv'),
|
||||
path('posts/<slug:slug>/', views.PostDetailView.as_view(), name='post_detail_cbv'),
|
||||
path('posts/create/', views.PostCreateView.as_view(), name='post_create_cbv'),
|
||||
path('posts/<slug:slug>/edit/', views.PostUpdateView.as_view(), name='post_edit_cbv'),
|
||||
path('posts/<slug:slug>/delete/', views.PostDeleteView.as_view(), name='post_delete_cbv'),
|
||||
|
||||
# API endpoints
|
||||
path('api/posts/', views.api_post_list, name='api_post_list'),
|
||||
]
|
||||
```
|
||||
@@ -0,0 +1,313 @@
|
||||
# Django Project Configuration
|
||||
|
||||
This file provides specific guidance for Django web application development using Claude Code.
|
||||
|
||||
## Project Overview
|
||||
|
||||
This is a Django web application project optimized for scalable web development with the Django framework. The project follows Django best practices and conventions.
|
||||
|
||||
## Django-Specific Development Commands
|
||||
|
||||
### Project Management
|
||||
- `django-admin startproject myproject` - Create new Django project
|
||||
- `python manage.py startapp myapp` - Create new Django app
|
||||
- `python manage.py runserver` - Start development server
|
||||
- `python manage.py runserver 0.0.0.0:8000` - Start server accessible from network
|
||||
|
||||
### Database Management
|
||||
- `python manage.py makemigrations` - Create database migrations
|
||||
- `python manage.py migrate` - Apply database migrations
|
||||
- `python manage.py showmigrations` - Show migration status
|
||||
- `python manage.py sqlmigrate app_name migration_name` - Show SQL for migration
|
||||
- `python manage.py dbshell` - Open database shell
|
||||
|
||||
### User Management
|
||||
- `python manage.py createsuperuser` - Create admin superuser
|
||||
- `python manage.py changepassword username` - Change user password
|
||||
- `python manage.py shell` - Open Django shell
|
||||
|
||||
### Static Files & Media
|
||||
- `python manage.py collectstatic` - Collect static files for production
|
||||
- `python manage.py findstatic filename` - Find static file location
|
||||
|
||||
### Testing & Quality
|
||||
- `python manage.py test` - Run Django tests
|
||||
- `python manage.py test app_name` - Run tests for specific app
|
||||
- `python manage.py test --keepdb` - Run tests keeping test database
|
||||
- `coverage run --source='.' manage.py test` - Run tests with coverage
|
||||
|
||||
### Development Tools
|
||||
- `python manage.py check` - Check for Django issues
|
||||
- `python manage.py validate` - Validate models
|
||||
- `python manage.py inspectdb` - Generate models from existing database
|
||||
- `python manage.py dumpdata app_name` - Export data
|
||||
- `python manage.py loaddata fixture.json` - Import data
|
||||
|
||||
## Django Project Structure
|
||||
|
||||
```
|
||||
myproject/
|
||||
├── manage.py # Django management script
|
||||
├── myproject/ # Project configuration
|
||||
│ ├── __init__.py
|
||||
│ ├── settings/ # Settings modules
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── base.py # Base settings
|
||||
│ │ ├── development.py # Development settings
|
||||
│ │ ├── production.py # Production settings
|
||||
│ │ └── testing.py # Testing settings
|
||||
│ ├── urls.py # URL configuration
|
||||
│ ├── wsgi.py # WSGI configuration
|
||||
│ └── asgi.py # ASGI configuration
|
||||
├── apps/ # Django applications
|
||||
│ ├── users/ # User management app
|
||||
│ ├── blog/ # Blog app example
|
||||
│ └── api/ # API app
|
||||
├── static/ # Static files
|
||||
├── media/ # User uploaded files
|
||||
├── templates/ # Django templates
|
||||
├── requirements/ # Requirements files
|
||||
│ ├── base.txt
|
||||
│ ├── development.txt
|
||||
│ └── production.txt
|
||||
└── tests/ # Test files
|
||||
```
|
||||
|
||||
## Django Settings Configuration
|
||||
|
||||
### Base Settings (settings/base.py)
|
||||
```python
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent.parent
|
||||
|
||||
# Security
|
||||
SECRET_KEY = os.environ.get('SECRET_KEY')
|
||||
DEBUG = False
|
||||
ALLOWED_HOSTS = []
|
||||
|
||||
# Application definition
|
||||
DJANGO_APPS = [
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
]
|
||||
|
||||
THIRD_PARTY_APPS = [
|
||||
'rest_framework',
|
||||
'django_extensions',
|
||||
]
|
||||
|
||||
LOCAL_APPS = [
|
||||
'apps.users',
|
||||
'apps.blog',
|
||||
]
|
||||
|
||||
INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS
|
||||
|
||||
# Database
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.postgresql',
|
||||
'NAME': os.environ.get('DB_NAME'),
|
||||
'USER': os.environ.get('DB_USER'),
|
||||
'PASSWORD': os.environ.get('DB_PASSWORD'),
|
||||
'HOST': os.environ.get('DB_HOST', 'localhost'),
|
||||
'PORT': os.environ.get('DB_PORT', '5432'),
|
||||
}
|
||||
}
|
||||
|
||||
# Internationalization
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
TIME_ZONE = 'UTC'
|
||||
USE_I18N = True
|
||||
USE_TZ = True
|
||||
|
||||
# Static files
|
||||
STATIC_URL = '/static/'
|
||||
STATIC_ROOT = BASE_DIR / 'staticfiles'
|
||||
STATICFILES_DIRS = [BASE_DIR / 'static']
|
||||
|
||||
# Media files
|
||||
MEDIA_URL = '/media/'
|
||||
MEDIA_ROOT = BASE_DIR / 'media'
|
||||
```
|
||||
|
||||
## Django Best Practices
|
||||
|
||||
### Models
|
||||
- Use descriptive model names (singular)
|
||||
- Add `__str__` methods for better admin interface
|
||||
- Use `related_name` for foreign keys
|
||||
- Implement `get_absolute_url` method
|
||||
- Add proper Meta class with ordering
|
||||
|
||||
### Views
|
||||
- Use class-based views for complex logic
|
||||
- Implement proper error handling
|
||||
- Add pagination for list views
|
||||
- Use `select_related` and `prefetch_related` for optimization
|
||||
- Implement proper permission checks
|
||||
|
||||
### URLs
|
||||
- Use app namespaces
|
||||
- Use descriptive URL names
|
||||
- Group related URLs in separate files
|
||||
- Use slug fields for SEO-friendly URLs
|
||||
|
||||
### Templates
|
||||
- Extend base templates
|
||||
- Use template inheritance effectively
|
||||
- Create reusable template tags
|
||||
- Implement proper CSRF protection
|
||||
- Use Django's built-in template filters
|
||||
|
||||
### Forms
|
||||
- Use Django forms for validation
|
||||
- Implement custom form validation
|
||||
- Use ModelForms when appropriate
|
||||
- Add proper error handling
|
||||
- Implement CSRF protection
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Django Security Settings
|
||||
```python
|
||||
# Security settings for production
|
||||
SECURE_BROWSER_XSS_FILTER = True
|
||||
SECURE_CONTENT_TYPE_NOSNIFF = True
|
||||
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
|
||||
SECURE_HSTS_PRELOAD = True
|
||||
SECURE_HSTS_SECONDS = 31536000
|
||||
SECURE_REDIRECT_EXEMPT = []
|
||||
SECURE_SSL_REDIRECT = True
|
||||
SESSION_COOKIE_SECURE = True
|
||||
CSRF_COOKIE_SECURE = True
|
||||
```
|
||||
|
||||
### User Authentication
|
||||
- Use Django's built-in authentication
|
||||
- Implement proper password policies
|
||||
- Add two-factor authentication if needed
|
||||
- Use Django's permission system
|
||||
- Implement proper session management
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
### Test Organization
|
||||
```python
|
||||
# tests/test_models.py
|
||||
from django.test import TestCase
|
||||
from django.contrib.auth import get_user_model
|
||||
from apps.blog.models import Post
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
class PostModelTest(TestCase):
|
||||
def setUp(self):
|
||||
self.user = User.objects.create_user(
|
||||
username='testuser',
|
||||
email='test@example.com',
|
||||
password='testpass123'
|
||||
)
|
||||
|
||||
def test_post_creation(self):
|
||||
post = Post.objects.create(
|
||||
title='Test Post',
|
||||
content='Test content',
|
||||
author=self.user
|
||||
)
|
||||
self.assertEqual(post.title, 'Test Post')
|
||||
self.assertEqual(str(post), 'Test Post')
|
||||
```
|
||||
|
||||
### Test Types
|
||||
- **Unit tests** for models and utilities
|
||||
- **Integration tests** for views and forms
|
||||
- **Functional tests** for user workflows
|
||||
- **API tests** for REST endpoints
|
||||
|
||||
## Deployment Considerations
|
||||
|
||||
### Production Settings
|
||||
- Use environment variables for sensitive data
|
||||
- Configure proper logging
|
||||
- Set up static file serving
|
||||
- Configure database connection pooling
|
||||
- Implement proper caching strategy
|
||||
|
||||
### Docker Configuration
|
||||
```dockerfile
|
||||
FROM python:3.11-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
COPY . .
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "myproject.wsgi:application"]
|
||||
```
|
||||
|
||||
## Performance Optimization
|
||||
|
||||
### Database Optimization
|
||||
- Use `select_related()` for foreign keys
|
||||
- Use `prefetch_related()` for many-to-many
|
||||
- Add database indexes for frequent queries
|
||||
- Implement database connection pooling
|
||||
- Use database query optimization tools
|
||||
|
||||
### Caching Strategy
|
||||
- Implement Redis/Memcached for session storage
|
||||
- Use template fragment caching
|
||||
- Implement view-level caching
|
||||
- Add database query caching
|
||||
- Use CDN for static files
|
||||
|
||||
## Common Django Patterns
|
||||
|
||||
### Custom User Model
|
||||
```python
|
||||
from django.contrib.auth.models import AbstractUser
|
||||
from django.db import models
|
||||
|
||||
class User(AbstractUser):
|
||||
email = models.EmailField(unique=True)
|
||||
first_name = models.CharField(max_length=30)
|
||||
last_name = models.CharField(max_length=30)
|
||||
|
||||
USERNAME_FIELD = 'email'
|
||||
REQUIRED_FIELDS = ['username', 'first_name', 'last_name']
|
||||
```
|
||||
|
||||
### Custom Managers
|
||||
```python
|
||||
class PublishedManager(models.Manager):
|
||||
def get_queryset(self):
|
||||
return super().get_queryset().filter(status='published')
|
||||
|
||||
class Post(models.Model):
|
||||
title = models.CharField(max_length=200)
|
||||
status = models.CharField(max_length=20, default='draft')
|
||||
|
||||
objects = models.Manager() # Default manager
|
||||
published = PublishedManager() # Custom manager
|
||||
```
|
||||
|
||||
## Django Extensions & Tools
|
||||
|
||||
### Useful Third-Party Packages
|
||||
- **Django REST Framework** - API development
|
||||
- **Celery** - Asynchronous task processing
|
||||
- **Django Debug Toolbar** - Development debugging
|
||||
- **Django Extensions** - Additional management commands
|
||||
- **Pillow** - Image processing
|
||||
- **psycopg2-binary** - PostgreSQL adapter
|
||||
Reference in New Issue
Block a user