Day 5 of 5
⏱ ~60 minutes
Django in 5 Days — Day 5

Deploy to Production

Configure Django for production: DEBUG off, static files, PostgreSQL, and deploy to Railway with environment variables.

Production Settings

mysite/settings.py changes
import os

DEBUG = os.environ.get('DEBUG', 'False') == 'True'
SECRET_KEY = os.environ.get('SECRET_KEY', 'fallback-dev-key')
ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', 'localhost').split(',')

# Database: switch to PostgreSQL in production
import dj_database_url
DATABASES = {
    'default': dj_database_url.config(default=os.environ.get('DATABASE_URL'))
}
Static Files with WhiteNoise
pip install whitenoise dj-database-url gunicorn

# settings.py
MIDDLEWARE = [
    'whitenoise.middleware.WhiteNoiseMiddleware',
    # ... existing middleware
]
STATIC_ROOT = BASE_DIR / 'staticfiles'
STATICSFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
Procfile
web: gunicorn mysite.wsgi --log-file -
Deploy to Railway
# railway.app → New Project → Deploy from GitHub
# Add environment variables:
# SECRET_KEY, DATABASE_URL (Railway provisions Postgres),
# ALLOWED_HOSTS=your-app.railway.app,DEBUG=False

# Post-deploy: run migrations
railway run python manage.py migrate
railway run python manage.py collectstatic --noinput
⚠️
Never set DEBUG=True in production. It exposes your full stack trace and settings to anyone who triggers an error. Set it to False and configure ALLOWED_HOSTS properly.
📝 Day 5 Exercise
Deploy Your Django App
  1. I
  2. n
  3. s
  4. t
  5. a
  6. l
  7. l
  8. g
  9. u
  10. n
  11. i
  12. c
  13. o
  14. r
  15. n
  16. ,
  17. w
  18. h
  19. i
  20. t
  21. e
  22. n
  23. o
  24. i
  25. s
  26. e
  27. ,
  28. d
  29. j
  30. -
  31. d
  32. a
  33. t
  34. a
  35. b
  36. a
  37. s
  38. e
  39. -
  40. u
  41. r
  42. l
  43. .
  44. S
  45. e
  46. t
  47. D
  48. E
  49. B
  50. U
  51. G
  52. a
  53. n
  54. d
  55. S
  56. E
  57. C
  58. R
  59. E
  60. T
  61. _
  62. K
  63. E
  64. Y
  65. f
  66. r
  67. o
  68. m
  69. e
  70. n
  71. v
  72. i
  73. r
  74. o
  75. n
  76. m
  77. e
  78. n
  79. t
  80. v
  81. a
  82. r
  83. i
  84. a
  85. b
  86. l
  87. e
  88. s
  89. .
  90. R
  91. u
  92. n
  93. c
  94. o
  95. l
  96. l
  97. e
  98. c
  99. t
  100. s
  101. t
  102. a
  103. t
  104. i
  105. c
  106. .
  107. P
  108. u
  109. s
  110. h
  111. t
  112. o
  113. G
  114. i
  115. t
  116. H
  117. u
  118. b
  119. a
  120. n
  121. d
  122. d
  123. e
  124. p
  125. l
  126. o
  127. y
  128. t
  129. o
  130. R
  131. a
  132. i
  133. l
  134. w
  135. a
  136. y
  137. .
  138. V
  139. e
  140. r
  141. i
  142. f
  143. y
  144. t
  145. h
  146. e
  147. a
  148. p
  149. p
  150. w
  151. o
  152. r
  153. k
  154. s
  155. w
  156. i
  157. t
  158. h
  159. D
  160. E
  161. B
  162. U
  163. G
  164. =
  165. F
  166. a
  167. l
  168. s
  169. e
  170. .

Day 5 Summary

  • DEBUG=False in production — no exceptions. Use env vars for secrets and settings.
  • WhiteNoise serves static files efficiently without a separate file server.
  • dj_database_url.config() parses a DATABASE_URL env var into Django's database dict.
  • gunicorn is the production WSGI server. Replace manage.py runserver which is dev-only.
Finished this lesson?