Some notes on starting to use Django
Julia Evans' personal first impressions learning Django after avoiding web frameworks for years. High-value practical notes from a developer who normally writes single-file Go binaries or static sites.
Core Insights
1. Less Magic Than Rails — Explicit Over Convention
After trying Rails in 2020 and finding it hard to return to projects after months away (conventions like resources :topics hide the actual configuration), Julia finds Django more "explicit." Five main files in a small project: urls.py, models.py, views.py, admin.py, tests.py — everything else is explicitly referenced. This makes long-term project maintenance much easier.
2. Built-in Admin Interface
Django's admin is surprisingly powerful with minimal code. Example customization:
@admin.register(Zine)
class ZineAdmin(admin.ModelAdmin):
list_display = ["name", "publication_date", "free", "slug", "image_preview"]
search_fields = ["name", "slug"]
readonly_fields = ["image_preview"]
ordering = ["-publication_date"]
3. ORM: Rethinking the "I Can Write My Own SQL" Attitude
Julia moved from "ORMs? Who needs them?" to genuine appreciation. Django's join syntax using __ is elegant:
Zine.objects
.exclude(product__order__email_hash=email_hash)
This query spans 5 tables. The tradeoff: zero performance concern for small sites, much less typing, much easier to read.
4. Automatic Migrations Feel Like Magic
Changing models.py → Django generates migration scripts like migrations/0006_delete_imageblob.py. Critical for projects where the data model evolves frequently. "It really feels like magic."
5. SQLite in Production: A Practical Choice
After bad experiences with Postgres complexity, Julia runs all small sites on SQLite. Backup is trivial: VACUUM INTO → copy single file. Used on Mess with DNS which has significantly more writes. References these instructions for production SQLite.
6. Batteries-Included: Email, CSRF, CSP All Built In
Configuration to save emails to file in dev mode:
# settings/dev.py
EMAIL_BACKEND = "django.core.mail.backends.filebased.EmailBackend"
EMAIL_FILE_PATH = BASE_DIR / "emails"
Production SMTP config with environment variables is similarly minimal.
7. The Settings File Anxiety
One remaining friction: settings.py uses global variables. No IDE autocomplete/lint. A typo like WSGI_APPLICATOIN vs WSGI_APPLICATION would be silent. Python language server support can't help here — unlike typed code.
Key Takeaways
- Django's explicitness > Rails' convention-over-configuration for long-term maintainability
- ORMs are worth embracing for small-to-medium projects (SQLite + Django handles surprising scale)
- Automatic migrations are transformative for evolving data models
- "Batteries included" isn't marketing — CSRF, CSP, email, admin are first-class
- Settings.py global variables are the one rough edge in an otherwise pleasant DX