django-models

📁 kjnez/claude-code-django 📅 Jan 23, 2026
4
总安装量
2
周安装量
#50997
全站排名
安装命令
npx skills add https://github.com/kjnez/claude-code-django --skill django-models

Agent 安装分布

claude-code 2
opencode 1
cursor 1
codex 1
antigravity 1
gemini-cli 1

Skill 文档

Django Model Patterns

Core Philosophy: Fat Models, Thin Views

Business logic belongs in models and managers, not views. Views orchestrate workflows; models implement domain behavior. This principle creates testable, reusable code that stays maintainable as complexity grows.

Good: Model methods handle business rules, state transitions, validation Bad: Views contain if/else logic for domain rules, calculate derived values

Model Design

Structure Your Models Around Domain Concepts

  • Use TextChoices/IntegerChoices for status fields and enums
  • Add get_absolute_url() for canonical object URLs
  • Include __str__() for readable representations
  • Set proper ordering in Meta for consistent default sorting
  • Add database indexes for frequently filtered/sorted fields
  • Use abstract base models for shared fields (timestamps, soft deletes, etc.)

Field Selection Guidelines

  • Use blank=True, default="" for optional text fields (avoid null)
  • Use null=True, blank=True for optional foreign keys
  • For unique optional fields, use null=True to avoid collision issues
  • Leverage JSONField for flexible metadata (avoid creating many optional fields)
  • Set appropriate max_length based on actual data needs

Encapsulate Business Logic in Model Methods

  • State transitions: post.publish(), order.cancel()
  • Permission checks: post.is_editable_by(user)
  • Complex calculations: invoice.calculate_total()
  • Use properties for computed read-only values
  • Specify update_fields when saving partial changes

QuerySet Patterns: The Power of Composition

Custom QuerySet classes are your secret weapon. They make queries reusable, chainable, and testable.

Pattern: QuerySet as Manager

Define a QuerySet subclass with domain-specific filter methods
Attach it to your model: objects = YourQuerySet.as_manager()
Chain methods for composable queries

Benefits

  • Reusable query logic across views, tasks, management commands
  • Chainable methods enable expressive, readable queries
  • Easy to test in isolation
  • Encapsulates query complexity away from views

Common QuerySet Methods

  • Filtering by status/state
  • Date range queries (recent, upcoming, expired)
  • User-scoped queries (owned_by, visible_to)
  • Combined lookups (published_and_recent)

Query Optimization: Avoid N+1 Queries

The Golden Rules

  1. select_related(): Use for ForeignKey and OneToOneField (creates SQL JOIN)
  2. prefetch_related(): Use for ManyToManyField and reverse ForeignKeys (separate query + Python join)
  3. only(): Load specific fields when you don’t need the whole object
  4. defer(): Exclude heavy fields (TextField, JSONField) you won’t use
  5. Prefetch() object: Customize prefetch with filters and select_related

Efficient Counting and Existence Checks

  • Use .exists() instead of if queryset: or if len(queryset):
  • Use .count() instead of len(queryset.all())
  • Both perform database-level operations without loading objects

Aggregation and Annotation

  • annotate(): Add computed fields to each object (Count, Sum, Avg, etc.)
  • aggregate(): Compute values across entire queryset
  • Use F() expressions for database-level updates (views=F('views') + 1)
  • Combine annotate with filter for “objects with at least N related items”

Managers vs QuerySets

Use QuerySets for chainable query logic. Use Managers for model-level operations that don’t return querysets.

Manager: Think “factory methods” – User.objects.create_user() QuerySet: Think “filters and transformations” – Post.objects.published().recent()

Most of the time, you want a custom QuerySet, not a custom Manager.

Signals: Use Sparingly

Signals create implicit coupling and make code harder to follow. Prefer explicit method calls.

When Signals Make Sense

  • Audit logging (track all changes to a model)
  • Cache invalidation (clear cache when model changes)
  • Decoupling apps (third-party app needs to react to your models)

When to Avoid Signals

  • Business logic that should be in model methods
  • Logic tightly coupled to the calling code (just call the function directly)
  • Complex workflows (use explicit service layer instead)

Rule of thumb: If you control both the trigger and the reaction, don’t use a signal.

Migrations

Workflow

  • Run makemigrations after model changes
  • Review generated migration files before applying
  • Run migrate to apply migrations
  • Migrations should be reversible when possible

Data Migrations

Create with makemigrations --empty app_name. Use apps.get_model() to access models (not direct imports). Write both forward and reverse operations.

Use data migrations for: Populating new fields, transforming data, migrating between fields.

Anti-Patterns to Avoid

Query Anti-Patterns

  • Iterating over objects and accessing relations without select_related()/prefetch_related()
  • Using if queryset: instead of .exists()
  • Using len() to count instead of .count()
  • Loading entire objects when you only need specific fields

Design Anti-Patterns

  • Business logic in views instead of models
  • Views performing calculations that belong in model methods
  • Overusing signals for synchronous operations
  • Creating new models when JSONField would suffice
  • Forgetting to add indexes for filtered/sorted fields

Integration

Works with:

  • pytest-django-patterns: Factory-based model testing
  • celery-patterns: Async operations on models (pass IDs, not instances)
  • django-forms: ModelForm validation and saving