Spec-to-Django Template
A PM-to-engineering handoff template that translates product requirements directly into Django model, API, and permission specifications. Reduce back-and-forth between PM and backend engineers. Free to copy, download, and use. No signup required.
# Spec-to-Django Template
**Feature:** [Feature Name]
**PM:** [Name]
**Backend Engineer:** [Name]
**Date:** [Date]
**Target Sprint:** [Sprint]
---
## 1. Feature Summary (1 paragraph)
> What is this feature? Who uses it? What problem does it solve?
[Write here]
---
## 2. Data Model
### New Models
```python
# models.py
class [ModelName](models.Model):
# Fields — define type, null/blank, default, help_text
name = models.CharField(max_length=255)
status = models.CharField(
max_length=20,
choices=[("active", "Active"), ("archived", "Archived")],
default="active",
)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
db_table = "[table_name]"
ordering = ["-created_at"]
def __str__(self):
return self.name
```
### Changes to Existing Models
| Model | Field | Change | Migration Notes |
|---|---|---|---|
| | | Add / Rename / Remove / Type change | Nullable migration? |
---
## 3. API Endpoints
| Method | Endpoint | Auth | Request Body | Response | Status Codes |
|---|---|---|---|---|---|
| GET | /api/v1/[resource]/ | JWT | — | List[ResourceSchema] | 200 |
| POST | /api/v1/[resource]/ | JWT | ResourceCreateSchema | ResourceSchema | 201, 400 |
| GET | /api/v1/[resource]/{id}/ | JWT | — | ResourceSchema | 200, 404 |
| PATCH | /api/v1/[resource]/{id}/ | JWT | ResourceUpdateSchema | ResourceSchema | 200, 400, 404 |
| DELETE | /api/v1/[resource]/{id}/ | JWT | — | — | 204, 404 |
### Request / Response Schemas
```python
# serializers.py or schemas.py
class ResourceCreateSchema(serializers.Serializer):
name = serializers.CharField(max_length=255)
status = serializers.ChoiceField(choices=["active", "archived"], default="active")
class ResourceSchema(serializers.ModelSerializer):
class Meta:
model = [ModelName]
fields = ["id", "name", "status", "created_at", "updated_at"]
read_only_fields = ["id", "created_at", "updated_at"]
```
---
## 4. Business Logic
> Describe non-obvious rules that must be enforced in the view or service layer.
| Rule | Where Enforced | Notes |
|---|---|---|
| Users can only see their own resources | Queryset filter in view | Use request.user.id |
| Status can only go Active → Archived, not back | Validator or save() | Raise ValidationError |
| | | |
---
## 5. Permissions
| Role | Can Create | Can Read | Can Update | Can Delete |
|---|---|---|---|---|
| Owner | ✅ | ✅ | ✅ | ✅ |
| Member | ✅ | ✅ | Own only | Own only |
| Viewer | ❌ | ✅ | ❌ | ❌ |
| Admin | ✅ | ✅ | ✅ | ✅ |
---
## 6. Background Jobs / Celery Tasks
| Task Name | Trigger | Frequency | Notes |
|---|---|---|---|
| | On save signal | — | |
| | Cron | Daily at 00:00 UTC | |
---
## 7. Edge Cases
> List the non-obvious cases engineering should handle:
- [ ] What happens when a user is deleted — do their resources cascade or preserve?
- [ ] What if the POST body is empty?
- [ ] What if two users create the same resource simultaneously?
- [ ] What if the foreign key references a deleted object?
---
## 8. Migration Plan
| Step | Who | Notes |
|---|---|---|
| Write migration | Engineering | Run `makemigrations` |
| Review migration | PM + Engineering | Check for destructive changes |
| Test on staging | QA | Confirm existing data untouched |
| Deploy to production | DevOps | Run during low-traffic window |
---
## 9. Open Questions
| Question | Owner | Due |
|---|---|---|
| | | |How to use this Spec-to-Django template
Write the feature summary before touching the technical sections
The summary forces you to articulate what the feature does in plain English. If you can't write it in one paragraph, you don't know the feature well enough to spec it for engineering.
Draft the data model fields collaboratively with engineering
PMs define what data needs to exist and why. Engineers define how it's stored. Fill in the field names together — ambiguity in field names (is it 'type' or 'category'?) causes bugs that live for years.
Define permissions before writing business logic
Permission tables are the most-forgotten part of any spec. Write the full matrix (owner / member / viewer × create / read / update / delete) before any code is written. Retrofitting permissions onto existing endpoints is expensive.
List edge cases explicitly
Cascade deletes, concurrent writes, and empty payloads are the three most common sources of production bugs. Walk through each one and write it down — even 'not handled in v1, returns 500' is better than silence.
Want a Spec-to-Django grounded in your actual customer data?
PMRead ingests your customer interviews, feedback, and Slack threads — and generates PRDs backed by real evidence, not guesses.
Frequently asked questions
Should PMs write the actual Django code in this template?
No. The code blocks are scaffolds that help engineers understand the spec in their own language — not production code. PMs fill in field names, types, and constraints; engineers write the actual implementation. The template eliminates a round of clarification questions, not the engineering work.
How detailed should the API endpoint table be?
Enough detail that a frontend developer could write the API client without asking questions. That means: method, path, auth requirement, request body fields, response shape, and all meaningful status codes (not just 200 and 500).
What if the feature has no new models — it only modifies existing ones?
Use the 'Changes to Existing Models' table and skip the 'New Models' section. Document every field change with its migration strategy — especially nullable vs non-nullable additions to tables with production data.
When should I use this template vs a regular PRD?
Use the Spec-to-Django template for any backend feature that creates new data models or modifies existing ones. Use a standard PRD for higher-level features where the implementation details are up to engineering. These two documents should coexist — the PRD explains 'what and why', this spec explains 'how it maps to the backend'.
Other free templates