@umacloud/knowledge 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (418) hide show
  1. package/00-governance/governance-capabilities.md +557 -0
  2. package/00-governance/knowledge-map.md +39 -0
  3. package/00-governance/maintenance-policy.md +76 -0
  4. package/00-governance/review-checklist.md +81 -0
  5. package/README.md +13 -0
  6. package/ai/01-standards/agent-development-complete.md +691 -0
  7. package/ai/01-standards/llm-application-complete.md +488 -0
  8. package/ai/01-standards/mlops-complete.md +798 -0
  9. package/ai/01-standards/prompt-engineering-complete.md +646 -0
  10. package/ai/01-standards/rag-architecture-complete.md +649 -0
  11. package/ai/02-playbooks/llm-evaluation-playbook.md +847 -0
  12. package/ai/03-checklists/ai-project-checklist.md +215 -0
  13. package/ai/04-antipatterns/ai-antipatterns.md +661 -0
  14. package/ai/05-cases/case-rag-production.md +147 -0
  15. package/ai/06-glossary/ai-glossary.md +162 -0
  16. package/ai/agent-evaluation-benchmark.md +53 -0
  17. package/ai/ai-agent-memory-context-management.md +41 -0
  18. package/ai/ai-cost-capacity-optimization-playbook.md +42 -0
  19. package/ai/ai-data-security-and-compliance-playbook.md +37 -0
  20. package/ai/ai-domain-index-and-checklist.md +40 -0
  21. package/ai/ai-governance-maturity-model.md +50 -0
  22. package/ai/ai-model-selection-and-routing-strategy.md +47 -0
  23. package/ai/ai-observability-and-oncall-runbook.md +52 -0
  24. package/ai/ai-rag-engineering-playbook.md +42 -0
  25. package/ai/ai-red-team-and-safety-evaluation.md +42 -0
  26. package/ai/ai-release-readiness-and-rollback-gate.md +42 -0
  27. package/ai/llm-agent-engineering-deep-dive.md +57 -0
  28. package/ai/prompt-and-tool-guardrails.md +52 -0
  29. package/api/01-standards/enterprise-api-standards.md +198 -0
  30. package/api/01-standards/rest-api-design-guide.md +63 -0
  31. package/api/02-playbooks/api-pagination-playbook.md +93 -0
  32. package/api/02-playbooks/graphql-production-playbook.md +176 -0
  33. package/api/03-checklists/api-review-checklist.md +55 -0
  34. package/api/04-antipatterns/api-antipatterns.md +112 -0
  35. package/architecture/01-standards/api-gateway-patterns.md +496 -0
  36. package/architecture/01-standards/cloud-native-patterns.md +644 -0
  37. package/architecture/01-standards/distributed-systems-patterns.md +591 -0
  38. package/architecture/01-standards/event-driven-architecture.md +595 -0
  39. package/architecture/01-standards/microservices-patterns-complete.md +968 -0
  40. package/architecture/01-standards/microservices-patterns.md +495 -0
  41. package/architecture/01-standards/system-design-interview.md +664 -0
  42. package/architecture/02-playbooks/microservices-patterns-playbook.md +137 -0
  43. package/architecture/02-playbooks/migration-playbook.md +780 -0
  44. package/architecture/02-playbooks/system-design-playbook.md +779 -0
  45. package/architecture/03-checklists/architecture-decision-checklist.md +297 -0
  46. package/architecture/04-antipatterns/architecture-antipatterns.md +417 -0
  47. package/architecture/05-cases/case-netflix-microservices.md +413 -0
  48. package/architecture/06-glossary/architecture-glossary.md +164 -0
  49. package/architecture/adr-template-and-examples.md +38 -0
  50. package/architecture/api-gateway-deep-dive.md +1291 -0
  51. package/architecture/configuration-management.md +1162 -0
  52. package/architecture/distributed-transactions.md +1220 -0
  53. package/architecture/microservices-complete.md +735 -0
  54. package/architecture/resilience-and-disaster-patterns.md +37 -0
  55. package/architecture/service-governance.md +1198 -0
  56. package/architecture/system-architecture-deep-dive.md +37 -0
  57. package/backend/01-standards/analytics-and-growth.md +65 -0
  58. package/backend/01-standards/api-and-error-conventions.md +120 -0
  59. package/backend/01-standards/application-layering-and-packaging.md +160 -0
  60. package/backend/01-standards/auth-implementation.md +104 -0
  61. package/backend/01-standards/backend-framework-idioms.md +74 -0
  62. package/backend/01-standards/background-jobs-and-async.md +66 -0
  63. package/backend/01-standards/caching-strategies-complete.md +390 -0
  64. package/backend/01-standards/config-and-observability.md +77 -0
  65. package/backend/01-standards/data-modeling-and-persistence.md +94 -0
  66. package/backend/01-standards/django-complete.md +1765 -0
  67. package/backend/01-standards/email-and-notifications.md +64 -0
  68. package/backend/01-standards/fastapi-complete.md +925 -0
  69. package/backend/01-standards/file-upload-and-storage.md +66 -0
  70. package/backend/01-standards/graphql-api-complete.md +416 -0
  71. package/backend/01-standards/llm-application-standard.md +78 -0
  72. package/backend/01-standards/message-queue-patterns.md +379 -0
  73. package/backend/01-standards/microservices-and-distributed.md +78 -0
  74. package/backend/01-standards/nestjs-complete.md +2167 -0
  75. package/backend/01-standards/payment-integration.md +80 -0
  76. package/backend/01-standards/rate-limiting-complete.md +451 -0
  77. package/backend/01-standards/realtime-and-websocket.md +65 -0
  78. package/backend/01-standards/search-and-filtering.md +64 -0
  79. package/backend/01-standards/spring-boot-complete.md +445 -0
  80. package/backend/02-playbooks/api-design-playbook.md +718 -0
  81. package/backend/02-playbooks/email-send-playbook.md +130 -0
  82. package/backend/02-playbooks/file-upload-s3-playbook.md +153 -0
  83. package/backend/02-playbooks/typescript-enterprise-playbook.md +133 -0
  84. package/backend/02-playbooks/websocket-realtime-playbook.md +154 -0
  85. package/backend/03-checklists/api-launch-checklist.md +189 -0
  86. package/backend/04-antipatterns/backend-antipatterns.md +1051 -0
  87. package/blockchain/01-standards/blockchain-basics.md +557 -0
  88. package/blockchain/01-standards/smart-contract-development.md +1315 -0
  89. package/cicd/01-standards/deployment-and-delivery-standard.md +96 -0
  90. package/cicd/01-standards/github-actions-complete.md +473 -0
  91. package/cicd/01-standards/release-and-store-submission.md +75 -0
  92. package/cicd/02-playbooks/cicd-pipeline-playbook.md +144 -0
  93. package/cicd/02-playbooks/release-management-playbook.md +605 -0
  94. package/cicd/03-checklists/pipeline-security-checklist.md +168 -0
  95. package/cicd/04-antipatterns/cicd-antipatterns.md +589 -0
  96. package/cicd/05-cases/case-deployment-automation.md +221 -0
  97. package/cicd/05-cases/case-gitops-transformation.md +212 -0
  98. package/cicd/06-glossary/cicd-glossary.md +114 -0
  99. package/cicd/cicd-blueprint-deep-dive.md +38 -0
  100. package/cicd/release-readiness-gate.md +37 -0
  101. package/cloud-native/01-standards/container-security.md +741 -0
  102. package/cloud-native/01-standards/kubernetes-complete.md +812 -0
  103. package/cloud-native/02-playbooks/api-gateway-playbook.md +155 -0
  104. package/cloud-native/02-playbooks/gitops-with-argocd.md +760 -0
  105. package/cloud-native/02-playbooks/k8s-troubleshooting-playbook.md +1942 -0
  106. package/cloud-native/02-playbooks/message-queue-playbook.md +129 -0
  107. package/cloud-native/02-playbooks/multicloud-governance.md +726 -0
  108. package/cloud-native/02-playbooks/serverless-patterns.md +788 -0
  109. package/cloud-native/02-playbooks/service-mesh-playbook.md +612 -0
  110. package/cloud-native/02-playbooks/terraform-iac-playbook.md +143 -0
  111. package/cloud-native/03-checklists/container-security-checklist.md +431 -0
  112. package/cloud-native/03-checklists/k8s-production-readiness-checklist.md +460 -0
  113. package/cloud-native/04-antipatterns/container-antipatterns.md +660 -0
  114. package/cloud-native/04-antipatterns/k8s-antipatterns.md +743 -0
  115. package/cloud-native/05-cases/case-k8s-migration.md +478 -0
  116. package/cloud-native/05-cases/case-k8s-scaling.md +642 -0
  117. package/cloud-native/05-cases/case-k8s-security-incident.md +397 -0
  118. package/cloud-native/06-glossary/cloud-native-glossary.md +337 -0
  119. package/cross-platform/01-standards/cross-platform-frameworks.md +83 -0
  120. package/cross-platform/01-standards/platform-selection-and-architecture.md +77 -0
  121. package/data/01-standards/elasticsearch-complete.md +2098 -0
  122. package/data/01-standards/postgresql-complete.md +1613 -0
  123. package/data/01-standards/redis-complete.md +1527 -0
  124. package/data/02-playbooks/database-optimization-playbook.md +403 -0
  125. package/data/02-playbooks/elasticsearch-production-playbook.md +132 -0
  126. package/data/03-checklists/database-launch-checklist.md +187 -0
  127. package/data/04-antipatterns/database-antipatterns.md +873 -0
  128. package/data/05-cases/case-database-migration.md +310 -0
  129. package/data/06-glossary/database-glossary.md +440 -0
  130. package/data/data-governance-and-modeling-deep-dive.md +39 -0
  131. package/data-engineering/01-standards/airflow-complete.md +523 -0
  132. package/data-engineering/01-standards/kafka-complete.md +1521 -0
  133. package/data-engineering/02-playbooks/spark-etl-playbook.md +496 -0
  134. package/data-engineering/03-checklists/pipeline-launch-checklist.md +194 -0
  135. package/data-engineering/04-antipatterns/data-pipeline-antipatterns.md +684 -0
  136. package/data-engineering/05-cases/case-real-time-pipeline.md +355 -0
  137. package/data-engineering/06-glossary/data-engineering-glossary.md +429 -0
  138. package/database/01-standards/database-schema-standards.md +147 -0
  139. package/database/02-playbooks/postgresql-optimization-quick.md +52 -0
  140. package/database/02-playbooks/postgresql-performance-optimization.md +58 -0
  141. package/database/02-playbooks/postgresql-production-playbook.md +146 -0
  142. package/database/02-playbooks/redis-caching-playbook.md +117 -0
  143. package/database/03-checklists/database-review-checklist.md +50 -0
  144. package/database/04-antipatterns/database-antipatterns.md +112 -0
  145. package/design/01-standards/ui-design-system-complete.md +423 -0
  146. package/design/02-playbooks/design-handoff-playbook.md +254 -0
  147. package/design/02-playbooks/design-review-playbook.md +388 -0
  148. package/design/03-checklists/design-review-checklist.md +246 -0
  149. package/design/04-antipatterns/design-antipatterns.md +378 -0
  150. package/design/05-cases/case-design-system-adoption.md +328 -0
  151. package/design/06-glossary/design-glossary.md +329 -0
  152. package/design/ui-full-lifecycle-cross-platform-playbook.md +571 -0
  153. package/design/ux-system-deep-dive.md +38 -0
  154. package/design-systems/00-craft-rules.md +71 -0
  155. package/design-systems/aesthetic-families.md +43 -0
  156. package/design-systems/anti-ai-slop.md +162 -0
  157. package/design-systems/bold-geometric.md +120 -0
  158. package/design-systems/brutalist-bold.md +103 -0
  159. package/design-systems/editorial-clean.md +109 -0
  160. package/design-systems/glass-aurora.md +108 -0
  161. package/design-systems/modern-minimal.md +145 -0
  162. package/design-systems/premium-luxury.md +106 -0
  163. package/design-systems/product-type-design-map.md +48 -0
  164. package/design-systems/soft-warm.md +123 -0
  165. package/design-systems/tech-utility.md +113 -0
  166. package/desktop/01-standards/desktop-app-standard.md +72 -0
  167. package/desktop/01-standards/desktop-design.md +71 -0
  168. package/development/00-governance/document-template.md +41 -0
  169. package/development/01-standards/api-versioning-strategies.md +432 -0
  170. package/development/01-standards/authentication-patterns-complete.md +479 -0
  171. package/development/01-standards/css-architecture-complete.md +550 -0
  172. package/development/01-standards/database-migration-strategies.md +484 -0
  173. package/development/01-standards/elasticsearch-complete.md +347 -0
  174. package/development/01-standards/git-complete.md +371 -0
  175. package/development/01-standards/golang-complete.md +1565 -0
  176. package/development/01-standards/graphql-complete.md +298 -0
  177. package/development/01-standards/javascript-bundlers-complete.md +469 -0
  178. package/development/01-standards/javascript-typescript-complete.md +528 -0
  179. package/development/01-standards/jest-complete.md +275 -0
  180. package/development/01-standards/linux-complete.md +234 -0
  181. package/development/01-standards/logging-observability-complete.md +526 -0
  182. package/development/01-standards/microservices-communication.md +502 -0
  183. package/development/01-standards/mongodb-complete.md +406 -0
  184. package/development/01-standards/oauth2-complete.md +285 -0
  185. package/development/01-standards/performance-optimization-complete.md +289 -0
  186. package/development/01-standards/playwright-complete.md +247 -0
  187. package/development/01-standards/postgresql-complete.md +456 -0
  188. package/development/01-standards/pytest-complete.md +340 -0
  189. package/development/01-standards/python-async-programming.md +902 -0
  190. package/development/01-standards/python-complete.md +956 -0
  191. package/development/01-standards/python-decorators-complete.md +799 -0
  192. package/development/01-standards/python-design-patterns.md +2854 -0
  193. package/development/01-standards/python-packaging-distribution.md +420 -0
  194. package/development/01-standards/python-testing-strategies.md +607 -0
  195. package/development/01-standards/python-web-frameworks-comparison.md +471 -0
  196. package/development/01-standards/redis-complete.md +317 -0
  197. package/development/01-standards/rest-api-complete.md +316 -0
  198. package/development/01-standards/rust-complete.md +578 -0
  199. package/development/01-standards/typescript-advanced-types.md +1513 -0
  200. package/development/01-standards/web-security-complete.md +292 -0
  201. package/development/02-playbooks/api-design-playbook.md +810 -0
  202. package/development/02-playbooks/database-migration-playbook.md +580 -0
  203. package/development/02-playbooks/debugging-playbook.md +692 -0
  204. package/development/02-playbooks/feature-delivery-playbook.md +430 -0
  205. package/development/02-playbooks/incident-hotfix-playbook.md +387 -0
  206. package/development/02-playbooks/performance-optimization-playbook.md +531 -0
  207. package/development/02-playbooks/performance-tuning-playbook.md +652 -0
  208. package/development/02-playbooks/refactor-playbook.md +403 -0
  209. package/development/02-playbooks/release-playbook.md +469 -0
  210. package/development/03-checklists/architecture-review-checklist.md +168 -0
  211. package/development/03-checklists/data-migration-checklist.md +157 -0
  212. package/development/03-checklists/oncall-handover-checklist.md +173 -0
  213. package/development/03-checklists/pr-checklist.md +158 -0
  214. package/development/03-checklists/production-readiness-checklist.md +190 -0
  215. package/development/03-checklists/release-readiness-checklist.md +154 -0
  216. package/development/03-checklists/security-review-checklist.md +182 -0
  217. package/development/04-antipatterns/api-antipatterns.md +657 -0
  218. package/development/04-antipatterns/architecture-antipatterns.md +686 -0
  219. package/development/04-antipatterns/backend-antipatterns.md +648 -0
  220. package/development/04-antipatterns/cicd-antipatterns.md +540 -0
  221. package/development/04-antipatterns/code-smell-antipatterns.md +571 -0
  222. package/development/04-antipatterns/data-antipatterns.md +658 -0
  223. package/development/04-antipatterns/database-antipatterns.md +578 -0
  224. package/development/04-antipatterns/frontend-antipatterns.md +635 -0
  225. package/development/04-antipatterns/reliability-antipatterns.md +700 -0
  226. package/development/04-antipatterns/security-antipatterns.md +747 -0
  227. package/development/05-cases/case-api-version-migration.md +428 -0
  228. package/development/05-cases/case-authorization-hardening.md +383 -0
  229. package/development/05-cases/case-bluegreen-rollback.md +466 -0
  230. package/development/05-cases/case-cache-snowball-protection.md +485 -0
  231. package/development/05-cases/case-ci-cd-pipeline.md +544 -0
  232. package/development/05-cases/case-database-scaling.md +500 -0
  233. package/development/05-cases/case-db-hotspot-optimization.md +487 -0
  234. package/development/05-cases/case-incident-mttr-reduction.md +563 -0
  235. package/development/05-cases/case-microservice-migration.md +375 -0
  236. package/development/05-cases/case-performance-optimization.md +406 -0
  237. package/development/05-cases/case-security-incident-response.md +345 -0
  238. package/development/06-glossary/full-stack-glossary.md +166 -0
  239. package/development/09-maturity/quarterly-audit-template.md +35 -0
  240. package/development/11-ui-excellence/ui-aesthetic-system.md +41 -0
  241. package/development/11-ui-excellence/ui-engineering-excellence.md +435 -0
  242. package/development/12-scenarios/development-scenarios-guide.md +565 -0
  243. package/development/13-implementation-assets/implementation-toolkit.md +282 -0
  244. package/development/13-implementation-assets/knowledge-gates-execution.md +43 -0
  245. package/development/14-full-lifecycle/software-lifecycle-gates.md +511 -0
  246. package/development/15-lifecycle-templates/project-templates-collection.md +791 -0
  247. package/development/api-contract-and-versioning-guide.md +36 -0
  248. package/development/api-governance-complete.md +43 -0
  249. package/development/backend-engineering-complete.md +43 -0
  250. package/development/code-review-quality-complete.md +43 -0
  251. package/development/concurrency-reliability-complete.md +43 -0
  252. package/development/database-engineering-complete.md +43 -0
  253. package/development/engineering-effectiveness-complete.md +43 -0
  254. package/development/engineering-standards-deep-dive.md +38 -0
  255. package/development/frontend-engineering-complete.md +43 -0
  256. package/development/performance-capacity-complete.md +43 -0
  257. package/development/refactor-migration-complete.md +42 -0
  258. package/development/refactoring-and-techdebt-playbook.md +37 -0
  259. package/development/security-in-development-complete.md +43 -0
  260. package/devops/01-standards/cicd-pipeline-complete.md +262 -0
  261. package/devops/01-standards/docker-complete.md +1490 -0
  262. package/devops/01-standards/github-actions-complete.md +337 -0
  263. package/devops/01-standards/kubernetes-complete.md +638 -0
  264. package/devops/01-standards/terraform-complete.md +2117 -0
  265. package/devops/02-playbooks/docker-compose-playbook.md +233 -0
  266. package/devops/02-playbooks/docker-k8s-production-playbook.md +186 -0
  267. package/devops/02-playbooks/docker-production-playbook.md +952 -0
  268. package/edge-iot/01-standards/edge-iot-complete.md +473 -0
  269. package/experts/architect/api-design.md +178 -0
  270. package/experts/architect/methodology.md +124 -0
  271. package/experts/architect/security.md +75 -0
  272. package/experts/backend-lead/methodology.md +216 -0
  273. package/experts/devops/methodology.md +160 -0
  274. package/experts/frontend-lead/methodology.md +178 -0
  275. package/experts/product-manager/industry/ecommerce.md +43 -0
  276. package/experts/product-manager/industry/saas.md +40 -0
  277. package/experts/product-manager/methodology.md +97 -0
  278. package/experts/qa-lead/methodology.md +123 -0
  279. package/experts/qa-lead/test-strategy.md +128 -0
  280. package/experts/uiux-designer/methodology.md +125 -0
  281. package/frontend/01-standards/accessibility-complete.md +532 -0
  282. package/frontend/01-standards/accessibility-standard.md +74 -0
  283. package/frontend/01-standards/admin-dashboard-and-crud.md +72 -0
  284. package/frontend/01-standards/design-tokens-complete.md +444 -0
  285. package/frontend/01-standards/forms-and-validation.md +77 -0
  286. package/frontend/01-standards/frontend-architecture-and-layering.md +119 -0
  287. package/frontend/01-standards/i18n-and-localization.md +65 -0
  288. package/frontend/01-standards/nextjs-complete.md +451 -0
  289. package/frontend/01-standards/react-complete.md +713 -0
  290. package/frontend/01-standards/react-hooks-complete-guide.md +1100 -0
  291. package/frontend/01-standards/react-hooks-complete.md +1171 -0
  292. package/frontend/01-standards/seo-and-web-vitals.md +77 -0
  293. package/frontend/01-standards/state-management-complete.md +444 -0
  294. package/frontend/01-standards/vue-complete.md +499 -0
  295. package/frontend/01-standards/vue3-complete.md +2002 -0
  296. package/frontend/01-standards/web-framework-best-practices.md +64 -0
  297. package/frontend/01-standards/web-performance-complete.md +495 -0
  298. package/frontend/02-playbooks/accessibility-a11y-playbook.md +161 -0
  299. package/frontend/02-playbooks/frontend-performance-playbook.md +707 -0
  300. package/frontend/02-playbooks/i18n-internationalization-playbook.md +120 -0
  301. package/frontend/02-playbooks/performance-optimization-playbook.md +163 -0
  302. package/frontend/02-playbooks/react-nextjs-production-playbook.md +167 -0
  303. package/frontend/02-playbooks/react-state-management-playbook.md +173 -0
  304. package/frontend/03-checklists/component-quality-checklist.md +166 -0
  305. package/frontend/03-checklists/frontend-launch-checklist.md +299 -0
  306. package/frontend/04-antipatterns/frontend-antipatterns.md +886 -0
  307. package/frontend/05-cases/case-performance-optimization.md +274 -0
  308. package/harmony/01-standards/harmonyos-arkts-standard.md +75 -0
  309. package/harmony/01-standards/harmonyos-design.md +65 -0
  310. package/high-quality-engineering-playbook.md +54 -0
  311. package/incident/01-standards/incident-response-complete.md +303 -0
  312. package/incident/02-playbooks/chaos-engineering-playbook.md +883 -0
  313. package/incident/02-playbooks/postmortem-playbook.md +398 -0
  314. package/incident/03-checklists/incident-readiness-checklist.md +181 -0
  315. package/incident/04-antipatterns/incident-antipatterns.md +490 -0
  316. package/incident/05-cases/case-cascade-failure.md +176 -0
  317. package/incident/06-glossary/incident-glossary.md +114 -0
  318. package/incident/postmortem-and-response-deep-dive.md +39 -0
  319. package/industries/ecommerce/ecommerce-complete.md +631 -0
  320. package/industries/education/education-complete.md +555 -0
  321. package/industries/fintech/fintech-complete.md +501 -0
  322. package/industries/gaming/gaming-complete.md +587 -0
  323. package/industries/healthcare/healthcare-complete.md +452 -0
  324. package/low-code/01-standards/low-code-complete.md +944 -0
  325. package/miniprogram/01-standards/ai-common-mistakes.md +61 -0
  326. package/miniprogram/01-standards/miniprogram-custom-navbar-capsule.md +77 -0
  327. package/miniprogram/01-standards/miniprogram-design.md +61 -0
  328. package/miniprogram/01-standards/miniprogram-standard.md +81 -0
  329. package/mobile/01-standards/android-material-design.md +70 -0
  330. package/mobile/01-standards/flutter-complete.md +384 -0
  331. package/mobile/01-standards/ios-design-hig.md +78 -0
  332. package/mobile/01-standards/mobile-app-standard.md +85 -0
  333. package/mobile/01-standards/react-native-complete.md +352 -0
  334. package/mobile/02-playbooks/mobile-cross-platform-playbook.md +175 -0
  335. package/mobile/02-playbooks/mobile-performance.md +473 -0
  336. package/mobile/03-checklists/mobile-release-checklist.md +234 -0
  337. package/mobile/04-antipatterns/mobile-antipatterns.md +798 -0
  338. package/mobile/05-cases/case-app-performance.md +500 -0
  339. package/mobile/05-cases/case-app-startup-optimization.md +218 -0
  340. package/mobile/06-glossary/mobile-glossary.md +484 -0
  341. package/observability/01-standards/observability-standards.md +103 -0
  342. package/observability/02-playbooks/prometheus-grafana-playbook.md +135 -0
  343. package/observability/02-playbooks/structured-logging-playbook.md +73 -0
  344. package/observability/03-checklists/observability-checklist.md +54 -0
  345. package/observability/04-antipatterns/observability-antipatterns.md +106 -0
  346. package/operations/01-standards/prometheus-monitoring-complete.md +1578 -0
  347. package/operations/02-playbooks/capacity-planning-playbook.md +620 -0
  348. package/operations/03-checklists/production-launch-checklist.md +365 -0
  349. package/operations/04-antipatterns/operations-antipatterns.md +664 -0
  350. package/operations/05-cases/case-sre-practices.md +581 -0
  351. package/operations/06-glossary/operations-glossary.md +120 -0
  352. package/operations/aiops-anomaly-detection.md +758 -0
  353. package/operations/capacity-planning.md +1061 -0
  354. package/operations/chaos-engineering.md +659 -0
  355. package/operations/incident-command-system.md +38 -0
  356. package/operations/observability-complete.md +442 -0
  357. package/operations/slo-sli-playbook.md +517 -0
  358. package/operations/sre-operations-deep-dive.md +39 -0
  359. package/package.json +8 -0
  360. package/performance/01-standards/performance-and-scalability.md +80 -0
  361. package/performance/01-standards/performance-standards.md +156 -0
  362. package/performance/02-playbooks/query-optimization-playbook.md +103 -0
  363. package/performance/03-checklists/performance-checklist.md +56 -0
  364. package/performance/04-antipatterns/performance-antipatterns.md +146 -0
  365. package/product/01-standards/product-management-complete.md +285 -0
  366. package/product/02-playbooks/feature-launch-playbook.md +207 -0
  367. package/product/02-playbooks/user-research-playbook.md +532 -0
  368. package/product/03-checklists/feature-launch-checklist.md +275 -0
  369. package/product/04-antipatterns/product-antipatterns.md +355 -0
  370. package/product/05-cases/case-mvp-to-scale.md +384 -0
  371. package/product/06-glossary/product-glossary.md +462 -0
  372. package/product/feature-prioritization-framework.md +40 -0
  373. package/product/kpi-and-metric-tree.md +37 -0
  374. package/product/product-discovery-and-prd-deep-dive.md +41 -0
  375. package/quantum/01-standards/quantum-complete.md +1186 -0
  376. package/security/01-standards/api-security-complete.md +511 -0
  377. package/security/01-standards/container-runtime-security.md +574 -0
  378. package/security/01-standards/data-protection-gdpr.md +543 -0
  379. package/security/01-standards/owasp-top10-complete.md +1890 -0
  380. package/security/01-standards/secure-coding-baseline.md +90 -0
  381. package/security/01-standards/supply-chain-security.md +441 -0
  382. package/security/01-standards/web-security-checklist.md +108 -0
  383. package/security/01-standards/zero-trust-architecture.md +521 -0
  384. package/security/02-playbooks/auth-sso-playbook.md +166 -0
  385. package/security/02-playbooks/incident-response-security-playbook.md +588 -0
  386. package/security/02-playbooks/owasp-api-security-playbook.md +129 -0
  387. package/security/02-playbooks/payment-integration-playbook.md +119 -0
  388. package/security/02-playbooks/penetration-testing-playbook.md +517 -0
  389. package/security/03-checklists/security-audit-checklist.md +356 -0
  390. package/security/04-antipatterns/security-coding-antipatterns.md +580 -0
  391. package/security/05-cases/case-log4shell-incident.md +537 -0
  392. package/security/05-cases/case-major-breaches.md +468 -0
  393. package/security/06-glossary/security-glossary.md +212 -0
  394. package/security/compliance-automation.md +993 -0
  395. package/security/container-security.md +680 -0
  396. package/security/devsecops-complete.md +426 -0
  397. package/security/sast-dast-sca.md +775 -0
  398. package/security/secrets-management.md +594 -0
  399. package/security/security-architecture-deep-dive.md +37 -0
  400. package/security/threat-modeling-stride-playbook.md +40 -0
  401. package/seed-templates/auth-system.md +59 -0
  402. package/seed-templates/blog-content.md +94 -0
  403. package/seed-templates/dashboard.md +89 -0
  404. package/seed-templates/docs-site.md +73 -0
  405. package/seed-templates/e-commerce.md +50 -0
  406. package/seed-templates/saas-landing.md +92 -0
  407. package/seed-templates/settings-page.md +51 -0
  408. package/testing/01-standards/test-strategy-and-layering.md +83 -0
  409. package/testing/01-standards/testing-strategy-complete.md +422 -0
  410. package/testing/01-standards/unit-testing-best-practices.md +118 -0
  411. package/testing/02-playbooks/e2e-testing-playbook.md +988 -0
  412. package/testing/02-playbooks/testing-strategy-playbook.md +126 -0
  413. package/testing/03-checklists/test-strategy-checklist.md +208 -0
  414. package/testing/04-antipatterns/testing-antipatterns.md +718 -0
  415. package/testing/05-cases/case-testing-transformation.md +300 -0
  416. package/testing/06-glossary/testing-glossary.md +110 -0
  417. package/testing/risk-based-test-matrix.md +36 -0
  418. package/testing/testing-strategy-deep-dive.md +37 -0
@@ -0,0 +1,1765 @@
1
+ ---
2
+ id: django-complete
3
+ title: Django 完整指南
4
+ domain: backend
5
+ category: 01-standards
6
+ difficulty: intermediate
7
+ tags: [backend, complete, django, framework, rest, 中间件, 数据库迁移, 概述]
8
+ quality_score: 70
9
+ last_updated: 2026-06-15
10
+ ---
11
+ # Django 完整指南
12
+
13
+ ## 概述
14
+
15
+ Django 是 Python 生态中最成熟的全栈 Web 框架,遵循 MTV(Model-Template-View)模式,内置 ORM、认证系统、后台管理、表单处理、国际化等企业级功能。Django 秉承"batteries included"哲学,适用于从原型到大规模生产的全生命周期开发。
16
+
17
+ ### 核心特性
18
+
19
+ - **ORM**: 强大的对象关系映射,支持多种数据库后端
20
+ - **Admin**: 自动生成的后台管理界面
21
+ - **认证系统**: 内置用户认证、权限、组管理
22
+ - **迁移系统**: 数据库 schema 版本控制
23
+ - **安全**: 内置 CSRF/XSS/SQL 注入/Clickjacking 防护
24
+ - **缓存框架**: 多级缓存策略,支持 Redis/Memcached
25
+ - **信号系统**: 松耦合的事件驱动扩展机制
26
+ - **中间件**: 请求/响应处理管线
27
+
28
+ ### 为什么选择 Django?
29
+
30
+ - 成熟稳定,社区活跃(GitHub 70k+ stars)
31
+ - 文档质量业界公认一流
32
+ - Instagram/Pinterest/Disqus/Mozilla 等大规模验证
33
+ - 丰富的第三方生态(DRF/Celery/Channels/django-allauth 等)
34
+
35
+ ---
36
+
37
+ ## 项目结构最佳实践
38
+
39
+ ### 标准项目布局
40
+
41
+ ```
42
+ project_root/
43
+ ├── manage.py
44
+ ├── requirements/
45
+ │ ├── base.txt
46
+ │ ├── dev.txt
47
+ │ └── prod.txt
48
+ ├── config/ # 项目配置包(推荐重命名)
49
+ │ ├── __init__.py
50
+ │ ├── settings/
51
+ │ │ ├── __init__.py
52
+ │ │ ├── base.py # 公共配置
53
+ │ │ ├── dev.py # 开发环境
54
+ │ │ ├── staging.py # 预发布环境
55
+ │ │ └── prod.py # 生产环境
56
+ │ ├── urls.py
57
+ │ ├── wsgi.py
58
+ │ └── asgi.py
59
+ ├── apps/
60
+ │ ├── users/
61
+ │ │ ├── __init__.py
62
+ │ │ ├── admin.py
63
+ │ │ ├── apps.py
64
+ │ │ ├── models.py
65
+ │ │ ├── managers.py # 自定义 Manager
66
+ │ │ ├── serializers.py
67
+ │ │ ├── views.py
68
+ │ │ ├── urls.py
69
+ │ │ ├── signals.py
70
+ │ │ ├── tasks.py # Celery 任务
71
+ │ │ ├── permissions.py
72
+ │ │ ├── tests/
73
+ │ │ │ ├── __init__.py
74
+ │ │ │ ├── test_models.py
75
+ │ │ │ ├── test_views.py
76
+ │ │ │ └── factories.py # Factory Boy
77
+ │ │ └── migrations/
78
+ │ └── orders/
79
+ │ └── ...
80
+ ├── templates/
81
+ ├── static/
82
+ ├── media/
83
+ ├── locale/
84
+ ├── docker/
85
+ │ ├── Dockerfile
86
+ │ └── docker-compose.yml
87
+ └── docs/
88
+ ```
89
+
90
+ ### 设置拆分最佳实践
91
+
92
+ ```python
93
+ # config/settings/base.py
94
+ import os
95
+ from pathlib import Path
96
+
97
+ BASE_DIR = Path(__file__).resolve().parent.parent.parent
98
+
99
+ SECRET_KEY = os.environ.get("DJANGO_SECRET_KEY")
100
+
101
+ INSTALLED_APPS = [
102
+ "django.contrib.admin",
103
+ "django.contrib.auth",
104
+ "django.contrib.contenttypes",
105
+ "django.contrib.sessions",
106
+ "django.contrib.messages",
107
+ "django.contrib.staticfiles",
108
+ # 第三方
109
+ "rest_framework",
110
+ "django_filters",
111
+ "corsheaders",
112
+ # 本地
113
+ "apps.users",
114
+ "apps.orders",
115
+ ]
116
+
117
+ AUTH_USER_MODEL = "users.User"
118
+
119
+ # config/settings/dev.py
120
+ from .base import * # noqa: F401,F403
121
+
122
+ DEBUG = True
123
+ ALLOWED_HOSTS = ["*"]
124
+ DATABASES = {
125
+ "default": {
126
+ "ENGINE": "django.db.backends.postgresql",
127
+ "NAME": "myproject_dev",
128
+ "HOST": "localhost",
129
+ "PORT": "5432",
130
+ }
131
+ }
132
+
133
+ # config/settings/prod.py
134
+ from .base import * # noqa: F401,F403
135
+
136
+ DEBUG = False
137
+ ALLOWED_HOSTS = os.environ.get("ALLOWED_HOSTS", "").split(",")
138
+ DATABASES = {
139
+ "default": {
140
+ "ENGINE": "django.db.backends.postgresql",
141
+ "NAME": os.environ["DB_NAME"],
142
+ "USER": os.environ["DB_USER"],
143
+ "PASSWORD": os.environ["DB_PASSWORD"],
144
+ "HOST": os.environ["DB_HOST"],
145
+ "PORT": os.environ.get("DB_PORT", "5432"),
146
+ "CONN_MAX_AGE": 600,
147
+ "OPTIONS": {
148
+ "connect_timeout": 10,
149
+ "options": "-c statement_timeout=30000",
150
+ },
151
+ }
152
+ }
153
+ ```
154
+
155
+ ---
156
+
157
+ ## ORM 高级用法
158
+
159
+ ### 模型定义
160
+
161
+ ```python
162
+ from django.db import models
163
+ from django.utils import timezone
164
+
165
+
166
+ class TimeStampedModel(models.Model):
167
+ """可复用的时间戳抽象基类"""
168
+ created_at = models.DateTimeField(auto_now_add=True, db_index=True)
169
+ updated_at = models.DateTimeField(auto_now=True)
170
+
171
+ class Meta:
172
+ abstract = True
173
+
174
+
175
+ class Category(models.Model):
176
+ name = models.CharField(max_length=100, unique=True)
177
+ slug = models.SlugField(unique=True)
178
+ parent = models.ForeignKey(
179
+ "self", null=True, blank=True,
180
+ on_delete=models.CASCADE,
181
+ related_name="children",
182
+ )
183
+
184
+ class Meta:
185
+ verbose_name_plural = "Categories"
186
+ ordering = ["name"]
187
+ indexes = [
188
+ models.Index(fields=["slug"]),
189
+ ]
190
+
191
+ def __str__(self):
192
+ return self.name
193
+
194
+
195
+ class Article(TimeStampedModel):
196
+ class Status(models.TextChoices):
197
+ DRAFT = "draft", "Draft"
198
+ PUBLISHED = "published", "Published"
199
+ ARCHIVED = "archived", "Archived"
200
+
201
+ title = models.CharField(max_length=200)
202
+ slug = models.SlugField(max_length=200, unique_for_date="publish_date")
203
+ author = models.ForeignKey(
204
+ "users.User",
205
+ on_delete=models.CASCADE,
206
+ related_name="articles",
207
+ )
208
+ category = models.ForeignKey(
209
+ Category, on_delete=models.SET_NULL,
210
+ null=True, related_name="articles",
211
+ )
212
+ body = models.TextField()
213
+ status = models.CharField(
214
+ max_length=10,
215
+ choices=Status.choices,
216
+ default=Status.DRAFT,
217
+ db_index=True,
218
+ )
219
+ publish_date = models.DateTimeField(default=timezone.now)
220
+ tags = models.ManyToManyField("Tag", blank=True, related_name="articles")
221
+ view_count = models.PositiveIntegerField(default=0)
222
+
223
+ class Meta:
224
+ ordering = ["-publish_date"]
225
+ indexes = [
226
+ models.Index(fields=["-publish_date", "status"]),
227
+ models.Index(fields=["author", "status"]),
228
+ ]
229
+ constraints = [
230
+ models.CheckConstraint(
231
+ check=models.Q(view_count__gte=0),
232
+ name="view_count_non_negative",
233
+ ),
234
+ ]
235
+ ```
236
+
237
+ ### QuerySet 高级查询
238
+
239
+ ```python
240
+ from django.db.models import Q, F, Count, Avg, Sum, Subquery, OuterRef, Exists
241
+
242
+ # F 表达式 —— 引用字段值进行数据库级操作
243
+ Article.objects.filter(updated_at__gt=F("created_at"))
244
+ Article.objects.update(view_count=F("view_count") + 1)
245
+
246
+ # Q 对象 —— 构建复杂查询条件
247
+ Article.objects.filter(
248
+ Q(status="published") & (Q(title__icontains="django") | Q(body__icontains="django"))
249
+ )
250
+
251
+ # 排除条件
252
+ Article.objects.exclude(
253
+ Q(status="draft") | Q(author__is_active=False)
254
+ )
255
+
256
+ # annotate —— 为每行附加聚合计算值
257
+ authors_with_stats = User.objects.annotate(
258
+ article_count=Count("articles"),
259
+ avg_views=Avg("articles__view_count"),
260
+ total_views=Sum("articles__view_count"),
261
+ ).filter(article_count__gt=0).order_by("-total_views")
262
+
263
+ # aggregate —— 全表聚合
264
+ from django.db.models import Max, Min
265
+ stats = Article.objects.filter(status="published").aggregate(
266
+ total=Count("id"),
267
+ avg_views=Avg("view_count"),
268
+ max_views=Max("view_count"),
269
+ min_views=Min("view_count"),
270
+ )
271
+
272
+ # Subquery —— 子查询
273
+ newest_article = Article.objects.filter(
274
+ author=OuterRef("pk")
275
+ ).order_by("-publish_date")
276
+
277
+ users_with_latest = User.objects.annotate(
278
+ latest_article_title=Subquery(newest_article.values("title")[:1]),
279
+ latest_article_date=Subquery(newest_article.values("publish_date")[:1]),
280
+ )
281
+
282
+ # Exists —— 高效存在性检查
283
+ active_authors = User.objects.filter(
284
+ Exists(Article.objects.filter(author=OuterRef("pk"), status="published"))
285
+ )
286
+ ```
287
+
288
+ ### Prefetch 与 select_related
289
+
290
+ ```python
291
+ from django.db.models import Prefetch
292
+
293
+ # select_related —— ForeignKey / OneToOne,单次 JOIN
294
+ articles = Article.objects.select_related("author", "category").all()
295
+
296
+ # prefetch_related —— ManyToMany / 反向 FK,独立查询后合并
297
+ articles = Article.objects.prefetch_related("tags").all()
298
+
299
+ # Prefetch 对象 —— 自定义预取 QuerySet
300
+ published_articles = Article.objects.filter(status="published")
301
+ users = User.objects.prefetch_related(
302
+ Prefetch(
303
+ "articles",
304
+ queryset=published_articles.select_related("category"),
305
+ to_attr="published_articles", # 结果存到属性而非 Manager
306
+ )
307
+ )
308
+
309
+ # 嵌套预取
310
+ categories = Category.objects.prefetch_related(
311
+ Prefetch(
312
+ "articles",
313
+ queryset=Article.objects.select_related("author").prefetch_related("tags"),
314
+ )
315
+ )
316
+ ```
317
+
318
+ ### 自定义 Manager 和 QuerySet
319
+
320
+ ```python
321
+ class PublishedQuerySet(models.QuerySet):
322
+ def published(self):
323
+ return self.filter(status="published", publish_date__lte=timezone.now())
324
+
325
+ def by_author(self, user):
326
+ return self.filter(author=user)
327
+
328
+ def popular(self, min_views=100):
329
+ return self.filter(view_count__gte=min_views)
330
+
331
+ def with_stats(self):
332
+ return self.annotate(
333
+ comment_count=Count("comments"),
334
+ avg_rating=Avg("ratings__score"),
335
+ )
336
+
337
+
338
+ class PublishedManager(models.Manager):
339
+ def get_queryset(self):
340
+ return PublishedQuerySet(self.model, using=self._db).published()
341
+
342
+
343
+ class Article(TimeStampedModel):
344
+ # ...字段定义...
345
+ objects = models.Manager() # 默认 Manager
346
+ published = PublishedManager() # 自定义 Manager
347
+
348
+ class Meta:
349
+ default_manager_name = "objects"
350
+
351
+ # 链式调用
352
+ Article.published.by_author(user).popular().with_stats()
353
+ ```
354
+
355
+ ---
356
+
357
+ ## 数据库迁移
358
+
359
+ ### 迁移管理
360
+
361
+ ```bash
362
+ # 生成迁移文件
363
+ python manage.py makemigrations
364
+
365
+ # 查看迁移 SQL(不执行)
366
+ python manage.py sqlmigrate myapp 0001
367
+
368
+ # 执行迁移
369
+ python manage.py migrate
370
+
371
+ # 查看迁移状态
372
+ python manage.py showmigrations
373
+
374
+ # 回滚到指定迁移
375
+ python manage.py migrate myapp 0003
376
+
377
+ # 生成空迁移(用于数据迁移)
378
+ python manage.py makemigrations myapp --empty -n populate_slugs
379
+ ```
380
+
381
+ ### 数据迁移
382
+
383
+ ```python
384
+ from django.db import migrations
385
+
386
+ def populate_slugs(apps, schema_editor):
387
+ from django.utils.text import slugify
388
+ Article = apps.get_model("myapp", "Article")
389
+ for article in Article.objects.filter(slug=""):
390
+ article.slug = slugify(article.title)
391
+ article.save(update_fields=["slug"])
392
+
393
+ def reverse_slugs(apps, schema_editor):
394
+ pass # 反向迁移通常不需要操作
395
+
396
+ class Migration(migrations.Migration):
397
+ dependencies = [("myapp", "0005_article_slug")]
398
+
399
+ operations = [
400
+ migrations.RunPython(populate_slugs, reverse_slugs),
401
+ ]
402
+ ```
403
+
404
+ ### 迁移最佳实践
405
+
406
+ - 每次 `makemigrations` 只修改一个 app
407
+ - 数据迁移和 schema 迁移分开写
408
+ - 大表添加列时使用 `db_default`(Django 5.0+)或分步迁移
409
+ - 避免在迁移中直接 import Model,使用 `apps.get_model()`
410
+ - 生产环境迁移前先在 staging 测试
411
+ - 使用 `--check` 在 CI 中验证迁移文件是否最新
412
+
413
+ ---
414
+
415
+ ## 认证与权限
416
+
417
+ ### 自定义 User 模型
418
+
419
+ ```python
420
+ from django.contrib.auth.models import AbstractUser, BaseUserManager
421
+
422
+
423
+ class UserManager(BaseUserManager):
424
+ def create_user(self, email, password=None, **extra_fields):
425
+ if not email:
426
+ raise ValueError("Email is required")
427
+ email = self.normalize_email(email)
428
+ user = self.model(email=email, **extra_fields)
429
+ user.set_password(password)
430
+ user.save(using=self._db)
431
+ return user
432
+
433
+ def create_superuser(self, email, password=None, **extra_fields):
434
+ extra_fields.setdefault("is_staff", True)
435
+ extra_fields.setdefault("is_superuser", True)
436
+ return self.create_user(email, password, **extra_fields)
437
+
438
+
439
+ class User(AbstractUser):
440
+ username = None # 移除 username 字段
441
+ email = models.EmailField(unique=True)
442
+ phone = models.CharField(max_length=20, blank=True)
443
+ avatar = models.ImageField(upload_to="avatars/", blank=True)
444
+
445
+ USERNAME_FIELD = "email"
446
+ REQUIRED_FIELDS = []
447
+
448
+ objects = UserManager()
449
+
450
+ def __str__(self):
451
+ return self.email
452
+ ```
453
+
454
+ ### Groups 和 Permissions
455
+
456
+ ```python
457
+ from django.contrib.auth.models import Group, Permission
458
+ from django.contrib.contenttypes.models import ContentType
459
+
460
+ # 创建自定义权限
461
+ class Article(models.Model):
462
+ class Meta:
463
+ permissions = [
464
+ ("publish_article", "Can publish article"),
465
+ ("feature_article", "Can feature article on homepage"),
466
+ ]
467
+
468
+ # 程序化管理权限
469
+ def setup_groups():
470
+ editors, _ = Group.objects.get_or_create(name="Editors")
471
+ content_type = ContentType.objects.get_for_model(Article)
472
+
473
+ publish_perm = Permission.objects.get(
474
+ codename="publish_article", content_type=content_type
475
+ )
476
+ editors.permissions.add(publish_perm)
477
+
478
+ # 检查权限
479
+ user.has_perm("myapp.publish_article")
480
+ user.has_perms(["myapp.publish_article", "myapp.change_article"])
481
+ ```
482
+
483
+ ### JWT 认证(djangorestframework-simplejwt)
484
+
485
+ ```python
486
+ # settings.py
487
+ from datetime import timedelta
488
+
489
+ INSTALLED_APPS += ["rest_framework_simplejwt"]
490
+
491
+ REST_FRAMEWORK = {
492
+ "DEFAULT_AUTHENTICATION_CLASSES": [
493
+ "rest_framework_simplejwt.authentication.JWTAuthentication",
494
+ ],
495
+ }
496
+
497
+ SIMPLE_JWT = {
498
+ "ACCESS_TOKEN_LIFETIME": timedelta(minutes=15),
499
+ "REFRESH_TOKEN_LIFETIME": timedelta(days=7),
500
+ "ROTATE_REFRESH_TOKENS": True,
501
+ "BLACKLIST_AFTER_ROTATION": True,
502
+ "AUTH_HEADER_TYPES": ("Bearer",),
503
+ "TOKEN_OBTAIN_SERIALIZER": "apps.users.serializers.CustomTokenObtainPairSerializer",
504
+ }
505
+
506
+ # urls.py
507
+ from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
508
+
509
+ urlpatterns = [
510
+ path("api/token/", TokenObtainPairView.as_view(), name="token_obtain_pair"),
511
+ path("api/token/refresh/", TokenRefreshView.as_view(), name="token_refresh"),
512
+ ]
513
+
514
+ # 自定义 Token 载荷
515
+ from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
516
+
517
+ class CustomTokenObtainPairSerializer(TokenObtainPairSerializer):
518
+ @classmethod
519
+ def get_token(cls, user):
520
+ token = super().get_token(user)
521
+ token["email"] = user.email
522
+ token["is_staff"] = user.is_staff
523
+ return token
524
+ ```
525
+
526
+ ---
527
+
528
+ ## Django REST Framework
529
+
530
+ ### Serializer
531
+
532
+ ```python
533
+ from rest_framework import serializers
534
+
535
+ class ArticleSerializer(serializers.ModelSerializer):
536
+ author_name = serializers.CharField(source="author.get_full_name", read_only=True)
537
+ category_name = serializers.CharField(source="category.name", read_only=True)
538
+ comment_count = serializers.IntegerField(read_only=True)
539
+
540
+ class Meta:
541
+ model = Article
542
+ fields = [
543
+ "id", "title", "slug", "body", "status",
544
+ "author", "author_name",
545
+ "category", "category_name",
546
+ "publish_date", "view_count", "comment_count",
547
+ "created_at", "updated_at",
548
+ ]
549
+ read_only_fields = ["author", "view_count"]
550
+ extra_kwargs = {
551
+ "body": {"min_length": 50},
552
+ }
553
+
554
+ def validate_title(self, value):
555
+ if Article.objects.filter(title=value).exclude(pk=self.instance and self.instance.pk).exists():
556
+ raise serializers.ValidationError("Title already exists.")
557
+ return value
558
+
559
+ def validate(self, data):
560
+ if data.get("status") == "published" and not data.get("category"):
561
+ raise serializers.ValidationError(
562
+ {"category": "Published articles must have a category."}
563
+ )
564
+ return data
565
+
566
+ def create(self, validated_data):
567
+ validated_data["author"] = self.context["request"].user
568
+ return super().create(validated_data)
569
+
570
+
571
+ class ArticleListSerializer(serializers.ModelSerializer):
572
+ """列表专用轻量 Serializer,减少数据传输"""
573
+ class Meta:
574
+ model = Article
575
+ fields = ["id", "title", "slug", "status", "publish_date", "view_count"]
576
+ ```
577
+
578
+ ### ViewSet
579
+
580
+ ```python
581
+ from rest_framework import viewsets, status
582
+ from rest_framework.decorators import action
583
+ from rest_framework.response import Response
584
+ from django_filters.rest_framework import DjangoFilterBackend
585
+ from rest_framework.filters import SearchFilter, OrderingFilter
586
+
587
+
588
+ class ArticleViewSet(viewsets.ModelViewSet):
589
+ queryset = Article.objects.select_related("author", "category")
590
+ filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
591
+ filterset_fields = ["status", "category", "author"]
592
+ search_fields = ["title", "body"]
593
+ ordering_fields = ["publish_date", "view_count"]
594
+ ordering = ["-publish_date"]
595
+
596
+ def get_serializer_class(self):
597
+ if self.action == "list":
598
+ return ArticleListSerializer
599
+ return ArticleSerializer
600
+
601
+ def get_queryset(self):
602
+ qs = super().get_queryset()
603
+ if self.action == "list":
604
+ qs = qs.annotate(comment_count=Count("comments"))
605
+ return qs
606
+
607
+ @action(detail=True, methods=["post"])
608
+ def publish(self, request, pk=None):
609
+ article = self.get_object()
610
+ article.status = "published"
611
+ article.publish_date = timezone.now()
612
+ article.save(update_fields=["status", "publish_date"])
613
+ return Response({"status": "published"})
614
+
615
+ @action(detail=False, methods=["get"])
616
+ def my_articles(self, request):
617
+ qs = self.get_queryset().filter(author=request.user)
618
+ page = self.paginate_queryset(qs)
619
+ if page is not None:
620
+ serializer = self.get_serializer(page, many=True)
621
+ return self.get_paginated_response(serializer.data)
622
+ serializer = self.get_serializer(qs, many=True)
623
+ return Response(serializer.data)
624
+ ```
625
+
626
+ ### Permission
627
+
628
+ ```python
629
+ from rest_framework.permissions import BasePermission, SAFE_METHODS
630
+
631
+
632
+ class IsAuthorOrReadOnly(BasePermission):
633
+ def has_object_permission(self, request, view, obj):
634
+ if request.method in SAFE_METHODS:
635
+ return True
636
+ return obj.author == request.user
637
+
638
+
639
+ class IsAdminOrEditor(BasePermission):
640
+ def has_permission(self, request, view):
641
+ return request.user.is_staff or request.user.groups.filter(name="Editors").exists()
642
+
643
+
644
+ # 在 ViewSet 中组合使用
645
+ class ArticleViewSet(viewsets.ModelViewSet):
646
+ permission_classes = [IsAuthenticated, IsAuthorOrReadOnly]
647
+
648
+ def get_permissions(self):
649
+ if self.action in ["publish", "destroy"]:
650
+ return [IsAuthenticated(), IsAdminOrEditor()]
651
+ return super().get_permissions()
652
+ ```
653
+
654
+ ### Pagination
655
+
656
+ ```python
657
+ # settings.py
658
+ REST_FRAMEWORK = {
659
+ "DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
660
+ "PAGE_SIZE": 20,
661
+ }
662
+
663
+ # 自定义分页
664
+ from rest_framework.pagination import CursorPagination
665
+
666
+ class ArticleCursorPagination(CursorPagination):
667
+ page_size = 20
668
+ ordering = "-publish_date"
669
+ cursor_query_param = "cursor"
670
+
671
+ class ArticleViewSet(viewsets.ModelViewSet):
672
+ pagination_class = ArticleCursorPagination
673
+ ```
674
+
675
+ ### Throttling
676
+
677
+ ```python
678
+ # settings.py
679
+ REST_FRAMEWORK = {
680
+ "DEFAULT_THROTTLE_CLASSES": [
681
+ "rest_framework.throttling.AnonRateThrottle",
682
+ "rest_framework.throttling.UserRateThrottle",
683
+ ],
684
+ "DEFAULT_THROTTLE_RATES": {
685
+ "anon": "100/hour",
686
+ "user": "1000/hour",
687
+ "burst": "60/minute",
688
+ },
689
+ }
690
+
691
+ from rest_framework.throttling import UserRateThrottle
692
+
693
+ class BurstRateThrottle(UserRateThrottle):
694
+ scope = "burst"
695
+
696
+ class ArticleViewSet(viewsets.ModelViewSet):
697
+ throttle_classes = [BurstRateThrottle]
698
+ ```
699
+
700
+ ---
701
+
702
+ ## 中间件
703
+
704
+ ### 自定义中间件
705
+
706
+ ```python
707
+ import time
708
+ import logging
709
+
710
+ logger = logging.getLogger(__name__)
711
+
712
+
713
+ class RequestTimingMiddleware:
714
+ """记录每次请求的耗时"""
715
+ def __init__(self, get_response):
716
+ self.get_response = get_response
717
+
718
+ def __call__(self, request):
719
+ start = time.monotonic()
720
+ response = self.get_response(request)
721
+ duration = time.monotonic() - start
722
+ response["X-Request-Duration"] = f"{duration:.4f}s"
723
+ if duration > 1.0:
724
+ logger.warning(
725
+ "Slow request: %s %s took %.2fs",
726
+ request.method, request.path, duration,
727
+ )
728
+ return response
729
+
730
+
731
+ class RequestIDMiddleware:
732
+ """为每次请求添加唯一 ID,方便日志追踪"""
733
+ def __init__(self, get_response):
734
+ self.get_response = get_response
735
+
736
+ def __call__(self, request):
737
+ import uuid
738
+ request_id = request.headers.get("X-Request-ID", str(uuid.uuid4()))
739
+ request.request_id = request_id
740
+ response = self.get_response(request)
741
+ response["X-Request-ID"] = request_id
742
+ return response
743
+
744
+
745
+ # settings.py
746
+ MIDDLEWARE = [
747
+ "django.middleware.security.SecurityMiddleware",
748
+ "corsheaders.middleware.CorsMiddleware",
749
+ "apps.core.middleware.RequestIDMiddleware",
750
+ "apps.core.middleware.RequestTimingMiddleware",
751
+ "django.contrib.sessions.middleware.SessionMiddleware",
752
+ "django.middleware.common.CommonMiddleware",
753
+ "django.middleware.csrf.CsrfViewMiddleware",
754
+ "django.contrib.auth.middleware.AuthenticationMiddleware",
755
+ "django.contrib.messages.middleware.MessageMiddleware",
756
+ "django.middleware.clickjacking.XFrameOptionsMiddleware",
757
+ ]
758
+ ```
759
+
760
+ ---
761
+
762
+ ## 信号系统
763
+
764
+ ### 信号定义与使用
765
+
766
+ ```python
767
+ # apps/users/signals.py
768
+ from django.db.models.signals import post_save, pre_save
769
+ from django.dispatch import receiver
770
+ from django.conf import settings
771
+
772
+
773
+ @receiver(post_save, sender=settings.AUTH_USER_MODEL)
774
+ def create_user_profile(sender, instance, created, **kwargs):
775
+ if created:
776
+ Profile.objects.create(user=instance)
777
+
778
+
779
+ @receiver(pre_save, sender="articles.Article")
780
+ def auto_slug(sender, instance, **kwargs):
781
+ if not instance.slug:
782
+ from django.utils.text import slugify
783
+ instance.slug = slugify(instance.title)
784
+ ```
785
+
786
+ ### 信号注册
787
+
788
+ ```python
789
+ # apps/users/apps.py
790
+ from django.apps import AppConfig
791
+
792
+ class UsersConfig(AppConfig):
793
+ default_auto_field = "django.db.models.BigAutoField"
794
+ name = "apps.users"
795
+
796
+ def ready(self):
797
+ import apps.users.signals # noqa: F401
798
+ ```
799
+
800
+ ### 信号使用原则
801
+
802
+ - 信号适合跨 app 通知(如用户注册后发邮件)
803
+ - 不要用信号做本 app 内的业务逻辑,应放在 Model 方法或 Service 层
804
+ - 信号中避免耗时操作,长任务交给 Celery
805
+ - 测试时可用 `signal.disconnect()` 临时解除
806
+
807
+ ---
808
+
809
+ ## 缓存策略
810
+
811
+ ### Redis 缓存配置
812
+
813
+ ```python
814
+ # settings.py
815
+ CACHES = {
816
+ "default": {
817
+ "BACKEND": "django_redis.cache.RedisCache",
818
+ "LOCATION": os.environ.get("REDIS_URL", "redis://127.0.0.1:6379/1"),
819
+ "OPTIONS": {
820
+ "CLIENT_CLASS": "django_redis.client.DefaultClient",
821
+ "SERIALIZER": "django_redis.serializers.json.JSONSerializer",
822
+ "CONNECTION_POOL_KWARGS": {"max_connections": 50},
823
+ "SOCKET_CONNECT_TIMEOUT": 5,
824
+ "SOCKET_TIMEOUT": 5,
825
+ },
826
+ "KEY_PREFIX": "myproject",
827
+ "TIMEOUT": 300, # 默认 5 分钟
828
+ }
829
+ }
830
+
831
+ # 使用 Redis 做 Session 后端
832
+ SESSION_ENGINE = "django.contrib.sessions.backends.cache"
833
+ SESSION_CACHE_ALIAS = "default"
834
+ ```
835
+
836
+ ### Per-View 缓存
837
+
838
+ ```python
839
+ from django.views.decorators.cache import cache_page
840
+ from django.utils.decorators import method_decorator
841
+
842
+ # 函数视图
843
+ @cache_page(60 * 15) # 缓存 15 分钟
844
+ def article_list(request):
845
+ ...
846
+
847
+ # 类视图
848
+ @method_decorator(cache_page(60 * 15), name="dispatch")
849
+ class ArticleListView(ListView):
850
+ ...
851
+
852
+ # DRF ViewSet —— 使用 vary_on_headers 区分用户
853
+ from django.views.decorators.vary import vary_on_headers
854
+
855
+ @method_decorator(cache_page(60 * 5), name="list")
856
+ @method_decorator(vary_on_headers("Authorization"), name="list")
857
+ class ArticleViewSet(viewsets.ModelViewSet):
858
+ ...
859
+ ```
860
+
861
+ ### Per-Site 缓存
862
+
863
+ ```python
864
+ MIDDLEWARE = [
865
+ "django.middleware.cache.UpdateCacheMiddleware", # 放在最前
866
+ # ... 其他中间件 ...
867
+ "django.middleware.cache.FetchFromCacheMiddleware", # 放在最后
868
+ ]
869
+
870
+ CACHE_MIDDLEWARE_ALIAS = "default"
871
+ CACHE_MIDDLEWARE_SECONDS = 600
872
+ CACHE_MIDDLEWARE_KEY_PREFIX = "site"
873
+ ```
874
+
875
+ ### 低级缓存 API
876
+
877
+ ```python
878
+ from django.core.cache import cache
879
+
880
+ # 基本操作
881
+ cache.set("article:123", article_data, timeout=300)
882
+ data = cache.get("article:123")
883
+ cache.delete("article:123")
884
+
885
+ # get_or_set 模式
886
+ def get_article_stats():
887
+ return Article.objects.aggregate(
888
+ total=Count("id"),
889
+ published=Count("id", filter=Q(status="published")),
890
+ )
891
+
892
+ stats = cache.get_or_set("article_stats", get_article_stats, timeout=600)
893
+
894
+ # 批量操作
895
+ cache.set_many({"key1": "val1", "key2": "val2"}, timeout=300)
896
+ data = cache.get_many(["key1", "key2"])
897
+
898
+ # 原子递增
899
+ cache.set("page_views:123", 0)
900
+ cache.incr("page_views:123")
901
+
902
+ # 缓存版本控制
903
+ cache.set("data", value, version=2)
904
+ cache.incr_version("data")
905
+
906
+ # 缓存失效策略
907
+ def invalidate_article_cache(article_id):
908
+ keys = [
909
+ f"article:{article_id}",
910
+ "article_list",
911
+ "article_stats",
912
+ ]
913
+ cache.delete_many(keys)
914
+ ```
915
+
916
+ ---
917
+
918
+ ## Celery 异步任务
919
+
920
+ ### 基础配置
921
+
922
+ ```python
923
+ # config/celery.py
924
+ import os
925
+ from celery import Celery
926
+
927
+ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.prod")
928
+
929
+ app = Celery("myproject")
930
+ app.config_from_object("django.conf:settings", namespace="CELERY")
931
+ app.autodiscover_tasks()
932
+
933
+ # settings.py
934
+ CELERY_BROKER_URL = os.environ.get("CELERY_BROKER_URL", "redis://127.0.0.1:6379/0")
935
+ CELERY_RESULT_BACKEND = "django-db" # django-celery-results
936
+ CELERY_ACCEPT_CONTENT = ["json"]
937
+ CELERY_TASK_SERIALIZER = "json"
938
+ CELERY_RESULT_SERIALIZER = "json"
939
+ CELERY_TIMEZONE = "Asia/Shanghai"
940
+ CELERY_TASK_TRACK_STARTED = True
941
+ CELERY_TASK_TIME_LIMIT = 600
942
+ CELERY_TASK_SOFT_TIME_LIMIT = 300
943
+ CELERY_WORKER_MAX_TASKS_PER_CHILD = 1000
944
+ CELERY_WORKER_PREFETCH_MULTIPLIER = 1
945
+ ```
946
+
947
+ ### 任务定义与重试
948
+
949
+ ```python
950
+ # apps/notifications/tasks.py
951
+ from celery import shared_task
952
+ from celery.utils.log import get_task_logger
953
+
954
+ logger = get_task_logger(__name__)
955
+
956
+
957
+ @shared_task(
958
+ bind=True,
959
+ max_retries=3,
960
+ default_retry_delay=60,
961
+ autoretry_for=(ConnectionError, TimeoutError),
962
+ retry_backoff=True,
963
+ retry_backoff_max=600,
964
+ retry_jitter=True,
965
+ )
966
+ def send_notification_email(self, user_id, template_name, context):
967
+ try:
968
+ user = User.objects.get(id=user_id)
969
+ send_mail(
970
+ subject=context["subject"],
971
+ message="",
972
+ html_message=render_to_string(template_name, context),
973
+ from_email=settings.DEFAULT_FROM_EMAIL,
974
+ recipient_list=[user.email],
975
+ )
976
+ logger.info("Email sent to user %s", user_id)
977
+ except User.DoesNotExist:
978
+ logger.error("User %s not found, not retrying", user_id)
979
+ except Exception as exc:
980
+ logger.warning("Email failed for user %s: %s", user_id, exc)
981
+ raise self.retry(exc=exc)
982
+ ```
983
+
984
+ ### 任务编排
985
+
986
+ ```python
987
+ from celery import chain, group, chord
988
+
989
+ # chain —— 串行执行
990
+ result = chain(
991
+ fetch_data.s(url),
992
+ process_data.s(),
993
+ store_results.s(),
994
+ )()
995
+
996
+ # group —— 并行执行
997
+ result = group(
998
+ process_image.s(image_id) for image_id in image_ids
999
+ )()
1000
+
1001
+ # chord —— 并行执行 + 汇总回调
1002
+ result = chord(
1003
+ [analyze_article.s(aid) for aid in article_ids],
1004
+ aggregate_results.s(),
1005
+ )()
1006
+ ```
1007
+
1008
+ ### 任务优先级
1009
+
1010
+ ```python
1011
+ # 定义队列
1012
+ CELERY_TASK_ROUTES = {
1013
+ "apps.notifications.tasks.*": {"queue": "notifications"},
1014
+ "apps.analytics.tasks.*": {"queue": "analytics", "priority": 3},
1015
+ "apps.orders.tasks.*": {"queue": "critical", "priority": 9},
1016
+ }
1017
+
1018
+ # 手动指定队列
1019
+ send_notification_email.apply_async(
1020
+ args=[user_id, "welcome.html", ctx],
1021
+ queue="notifications",
1022
+ priority=5,
1023
+ countdown=10, # 延迟 10 秒执行
1024
+ )
1025
+ ```
1026
+
1027
+ ### Celery Beat 定时任务
1028
+
1029
+ ```python
1030
+ from celery.schedules import crontab
1031
+
1032
+ CELERY_BEAT_SCHEDULE = {
1033
+ "cleanup-expired-sessions": {
1034
+ "task": "apps.core.tasks.cleanup_expired_sessions",
1035
+ "schedule": crontab(hour=3, minute=0), # 每天凌晨 3 点
1036
+ },
1037
+ "generate-daily-report": {
1038
+ "task": "apps.analytics.tasks.generate_daily_report",
1039
+ "schedule": crontab(hour=6, minute=30),
1040
+ },
1041
+ "sync-external-data": {
1042
+ "task": "apps.integrations.tasks.sync_external_data",
1043
+ "schedule": 300.0, # 每 5 分钟
1044
+ },
1045
+ }
1046
+ ```
1047
+
1048
+ ---
1049
+
1050
+ ## 安全
1051
+
1052
+ ### CSRF 防护
1053
+
1054
+ ```python
1055
+ # settings.py
1056
+ CSRF_COOKIE_SECURE = True # 仅 HTTPS 传输 CSRF cookie
1057
+ CSRF_COOKIE_HTTPONLY = True # JS 不可读取
1058
+ CSRF_TRUSTED_ORIGINS = [
1059
+ "https://mysite.com",
1060
+ "https://*.mysite.com",
1061
+ ]
1062
+
1063
+ # DRF API 中排除 CSRF(JWT 场景)
1064
+ REST_FRAMEWORK = {
1065
+ "DEFAULT_AUTHENTICATION_CLASSES": [
1066
+ "rest_framework_simplejwt.authentication.JWTAuthentication",
1067
+ ],
1068
+ # SessionAuthentication 会强制 CSRF,纯 JWT 时不要包含
1069
+ }
1070
+ ```
1071
+
1072
+ ### XSS 防护
1073
+
1074
+ ```python
1075
+ # Django 模板默认自动转义,确保不要滥用 |safe 过滤器
1076
+ # 在 DRF 中 JSON 响应天然不存在模板 XSS
1077
+
1078
+ # 清理用户输入的 HTML
1079
+ import bleach
1080
+
1081
+ ALLOWED_TAGS = ["p", "b", "i", "u", "a", "ul", "ol", "li", "br", "strong", "em"]
1082
+ ALLOWED_ATTRS = {"a": ["href", "title"]}
1083
+
1084
+ def sanitize_html(raw_html):
1085
+ return bleach.clean(raw_html, tags=ALLOWED_TAGS, attributes=ALLOWED_ATTRS, strip=True)
1086
+ ```
1087
+
1088
+ ### SQL 注入防护
1089
+
1090
+ ```python
1091
+ # Django ORM 自动参数化,以下是安全的
1092
+ Article.objects.filter(title=user_input)
1093
+ Article.objects.extra(where=["title=%s"], params=[user_input]) # 参数化
1094
+
1095
+ # 危险 —— 永远不要这样做
1096
+ Article.objects.raw(f"SELECT * FROM article WHERE title='{user_input}'")
1097
+
1098
+ # 安全的 raw SQL
1099
+ Article.objects.raw("SELECT * FROM article WHERE title=%s", [user_input])
1100
+
1101
+ # 安全使用 connection.cursor
1102
+ from django.db import connection
1103
+ with connection.cursor() as cursor:
1104
+ cursor.execute("SELECT * FROM article WHERE status=%s", ["published"])
1105
+ ```
1106
+
1107
+ ### Content Security Policy
1108
+
1109
+ ```python
1110
+ # 使用 django-csp
1111
+ # pip install django-csp
1112
+ MIDDLEWARE += ["csp.middleware.CSPMiddleware"]
1113
+
1114
+ CSP_DEFAULT_SRC = ("'self'",)
1115
+ CSP_SCRIPT_SRC = ("'self'", "cdn.jsdelivr.net")
1116
+ CSP_STYLE_SRC = ("'self'", "'unsafe-inline'", "fonts.googleapis.com")
1117
+ CSP_FONT_SRC = ("'self'", "fonts.gstatic.com")
1118
+ CSP_IMG_SRC = ("'self'", "data:", "cdn.mysite.com")
1119
+ CSP_CONNECT_SRC = ("'self'", "api.mysite.com")
1120
+ ```
1121
+
1122
+ ### 综合安全设置
1123
+
1124
+ ```python
1125
+ # settings/prod.py
1126
+ SECURE_HSTS_SECONDS = 31536000
1127
+ SECURE_HSTS_INCLUDE_SUBDOMAINS = True
1128
+ SECURE_HSTS_PRELOAD = True
1129
+ SECURE_SSL_REDIRECT = True
1130
+ SECURE_BROWSER_XSS_FILTER = True
1131
+ SECURE_CONTENT_TYPE_NOSNIFF = True
1132
+ SESSION_COOKIE_SECURE = True
1133
+ SESSION_COOKIE_HTTPONLY = True
1134
+ SESSION_COOKIE_AGE = 3600 # 1 小时
1135
+ X_FRAME_OPTIONS = "DENY"
1136
+ ```
1137
+
1138
+ ---
1139
+
1140
+ ## 测试
1141
+
1142
+ ### TestCase 与 APITestCase
1143
+
1144
+ ```python
1145
+ from django.test import TestCase, TransactionTestCase
1146
+ from rest_framework.test import APITestCase, APIClient
1147
+ from django.urls import reverse
1148
+
1149
+
1150
+ class ArticleModelTest(TestCase):
1151
+ @classmethod
1152
+ def setUpTestData(cls):
1153
+ """类级别数据准备,整个 TestCase 共享,速度更快"""
1154
+ cls.user = User.objects.create_user(
1155
+ email="test@example.com", password="testpass123"
1156
+ )
1157
+ cls.category = Category.objects.create(name="Tech", slug="tech")
1158
+
1159
+ def test_article_creation(self):
1160
+ article = Article.objects.create(
1161
+ title="Test Article",
1162
+ body="x" * 100,
1163
+ author=self.user,
1164
+ category=self.category,
1165
+ )
1166
+ self.assertEqual(str(article), "Test Article")
1167
+ self.assertEqual(article.status, Article.Status.DRAFT)
1168
+
1169
+ def test_published_manager(self):
1170
+ Article.objects.create(
1171
+ title="Draft", body="x" * 100,
1172
+ author=self.user, status="draft",
1173
+ )
1174
+ Article.objects.create(
1175
+ title="Published", body="x" * 100,
1176
+ author=self.user, status="published",
1177
+ )
1178
+ self.assertEqual(Article.published.count(), 1)
1179
+
1180
+
1181
+ class ArticleAPITest(APITestCase):
1182
+ def setUp(self):
1183
+ self.user = User.objects.create_user(
1184
+ email="api@example.com", password="testpass123"
1185
+ )
1186
+ self.client = APIClient()
1187
+ self.client.force_authenticate(user=self.user)
1188
+
1189
+ def test_create_article(self):
1190
+ url = reverse("article-list")
1191
+ data = {
1192
+ "title": "API Article",
1193
+ "body": "x" * 100,
1194
+ "status": "draft",
1195
+ }
1196
+ response = self.client.post(url, data, format="json")
1197
+ self.assertEqual(response.status_code, 201)
1198
+ self.assertEqual(Article.objects.count(), 1)
1199
+ self.assertEqual(Article.objects.first().author, self.user)
1200
+
1201
+ def test_list_articles_pagination(self):
1202
+ for i in range(25):
1203
+ Article.objects.create(
1204
+ title=f"Article {i}", body="x" * 100, author=self.user
1205
+ )
1206
+ response = self.client.get(reverse("article-list"))
1207
+ self.assertEqual(response.status_code, 200)
1208
+ self.assertEqual(len(response.data["results"]), 20)
1209
+
1210
+ def test_unauthorized_delete(self):
1211
+ other_user = User.objects.create_user(email="other@example.com", password="pass")
1212
+ article = Article.objects.create(
1213
+ title="Other", body="x" * 100, author=other_user
1214
+ )
1215
+ url = reverse("article-detail", kwargs={"pk": article.pk})
1216
+ response = self.client.delete(url)
1217
+ self.assertEqual(response.status_code, 403)
1218
+ ```
1219
+
1220
+ ### Factory Boy
1221
+
1222
+ ```python
1223
+ # apps/articles/tests/factories.py
1224
+ import factory
1225
+ from factory.django import DjangoModelFactory
1226
+ from apps.users.models import User
1227
+ from apps.articles.models import Article, Category
1228
+
1229
+
1230
+ class UserFactory(DjangoModelFactory):
1231
+ class Meta:
1232
+ model = User
1233
+
1234
+ email = factory.Sequence(lambda n: f"user{n}@example.com")
1235
+ password = factory.PostGenerationMethodCall("set_password", "testpass123")
1236
+ is_active = True
1237
+
1238
+
1239
+ class CategoryFactory(DjangoModelFactory):
1240
+ class Meta:
1241
+ model = Category
1242
+
1243
+ name = factory.Sequence(lambda n: f"Category {n}")
1244
+ slug = factory.LazyAttribute(lambda o: o.name.lower().replace(" ", "-"))
1245
+
1246
+
1247
+ class ArticleFactory(DjangoModelFactory):
1248
+ class Meta:
1249
+ model = Article
1250
+
1251
+ title = factory.Sequence(lambda n: f"Article {n}")
1252
+ slug = factory.LazyAttribute(lambda o: o.title.lower().replace(" ", "-"))
1253
+ body = factory.Faker("paragraph", nb_sentences=10)
1254
+ author = factory.SubFactory(UserFactory)
1255
+ category = factory.SubFactory(CategoryFactory)
1256
+ status = "draft"
1257
+
1258
+ class Params:
1259
+ published = factory.Trait(
1260
+ status="published",
1261
+ publish_date=factory.LazyFunction(timezone.now),
1262
+ )
1263
+
1264
+ # 在测试中使用
1265
+ class ArticleTest(TestCase):
1266
+ def test_with_factory(self):
1267
+ article = ArticleFactory(published=True)
1268
+ self.assertEqual(article.status, "published")
1269
+
1270
+ def test_batch_create(self):
1271
+ ArticleFactory.create_batch(10, published=True)
1272
+ self.assertEqual(Article.published.count(), 10)
1273
+ ```
1274
+
1275
+ ### 覆盖率配置
1276
+
1277
+ ```ini
1278
+ # .coveragerc 或 pyproject.toml
1279
+ [tool.coverage.run]
1280
+ source = ["apps"]
1281
+ omit = ["*/migrations/*", "*/tests/*", "*/admin.py"]
1282
+ branch = true
1283
+
1284
+ [tool.coverage.report]
1285
+ fail_under = 85
1286
+ show_missing = true
1287
+ exclude_lines = [
1288
+ "pragma: no cover",
1289
+ "def __repr__",
1290
+ "raise NotImplementedError",
1291
+ "if TYPE_CHECKING:",
1292
+ ]
1293
+ ```
1294
+
1295
+ ```bash
1296
+ pytest --cov=apps --cov-report=term-missing --cov-report=html
1297
+ ```
1298
+
1299
+ ---
1300
+
1301
+ ## 部署
1302
+
1303
+ ### Gunicorn 配置
1304
+
1305
+ ```python
1306
+ # gunicorn.conf.py
1307
+ import multiprocessing
1308
+
1309
+ bind = "0.0.0.0:8000"
1310
+ workers = multiprocessing.cpu_count() * 2 + 1
1311
+ worker_class = "gthread"
1312
+ threads = 2
1313
+ worker_tmp_dir = "/dev/shm"
1314
+ timeout = 30
1315
+ graceful_timeout = 30
1316
+ keepalive = 5
1317
+ max_requests = 1000
1318
+ max_requests_jitter = 50
1319
+ accesslog = "-"
1320
+ errorlog = "-"
1321
+ loglevel = "info"
1322
+ preload_app = True
1323
+ ```
1324
+
1325
+ ### Nginx 配置
1326
+
1327
+ ```nginx
1328
+ upstream django {
1329
+ server 127.0.0.1:8000;
1330
+ }
1331
+
1332
+ server {
1333
+ listen 80;
1334
+ server_name mysite.com;
1335
+ return 301 https://$host$request_uri;
1336
+ }
1337
+
1338
+ server {
1339
+ listen 443 ssl http2;
1340
+ server_name mysite.com;
1341
+
1342
+ ssl_certificate /etc/nginx/ssl/cert.pem;
1343
+ ssl_certificate_key /etc/nginx/ssl/key.pem;
1344
+
1345
+ client_max_body_size 10M;
1346
+
1347
+ location /static/ {
1348
+ alias /app/staticfiles/;
1349
+ expires 30d;
1350
+ add_header Cache-Control "public, immutable";
1351
+ }
1352
+
1353
+ location /media/ {
1354
+ alias /app/media/;
1355
+ expires 7d;
1356
+ }
1357
+
1358
+ location / {
1359
+ proxy_pass http://django;
1360
+ proxy_set_header Host $host;
1361
+ proxy_set_header X-Real-IP $remote_addr;
1362
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
1363
+ proxy_set_header X-Forwarded-Proto $scheme;
1364
+ proxy_read_timeout 30s;
1365
+ proxy_connect_timeout 10s;
1366
+ }
1367
+ }
1368
+ ```
1369
+
1370
+ ### Docker 部署
1371
+
1372
+ ```dockerfile
1373
+ # Dockerfile
1374
+ FROM python:3.12-slim AS base
1375
+
1376
+ ENV PYTHONDONTWRITEBYTECODE=1 \
1377
+ PYTHONUNBUFFERED=1
1378
+
1379
+ WORKDIR /app
1380
+
1381
+ RUN apt-get update && apt-get install -y --no-install-recommends \
1382
+ libpq-dev gcc && \
1383
+ rm -rf /var/lib/apt/lists/*
1384
+
1385
+ COPY requirements/prod.txt requirements.txt
1386
+ RUN pip install --no-cache-dir -r requirements.txt
1387
+
1388
+ COPY . .
1389
+ RUN python manage.py collectstatic --noinput
1390
+
1391
+ FROM base AS production
1392
+ RUN addgroup --system django && adduser --system --group django
1393
+ USER django
1394
+
1395
+ CMD ["gunicorn", "config.wsgi:application", "-c", "gunicorn.conf.py"]
1396
+ ```
1397
+
1398
+ ```yaml
1399
+ # docker-compose.yml
1400
+ services:
1401
+ web:
1402
+ build: .
1403
+ command: gunicorn config.wsgi:application -c gunicorn.conf.py
1404
+ volumes:
1405
+ - static_volume:/app/staticfiles
1406
+ - media_volume:/app/media
1407
+ env_file: .env
1408
+ depends_on:
1409
+ db:
1410
+ condition: service_healthy
1411
+ redis:
1412
+ condition: service_started
1413
+
1414
+ db:
1415
+ image: postgres:16-alpine
1416
+ volumes:
1417
+ - postgres_data:/var/lib/postgresql/data
1418
+ environment:
1419
+ POSTGRES_DB: ${DB_NAME}
1420
+ POSTGRES_USER: ${DB_USER}
1421
+ POSTGRES_PASSWORD: ${DB_PASSWORD}
1422
+ healthcheck:
1423
+ test: ["CMD-SHELL", "pg_isready -U ${DB_USER}"]
1424
+ interval: 5s
1425
+ timeout: 5s
1426
+ retries: 5
1427
+
1428
+ redis:
1429
+ image: redis:7-alpine
1430
+ command: redis-server --maxmemory 256mb --maxmemory-policy allkeys-lru
1431
+
1432
+ celery:
1433
+ build: .
1434
+ command: celery -A config worker -l info --concurrency=4
1435
+ env_file: .env
1436
+ depends_on: [web, redis]
1437
+
1438
+ celery-beat:
1439
+ build: .
1440
+ command: celery -A config beat -l info --scheduler django_celery_beat.schedulers:DatabaseScheduler
1441
+ env_file: .env
1442
+ depends_on: [web, redis]
1443
+
1444
+ nginx:
1445
+ image: nginx:alpine
1446
+ ports:
1447
+ - "80:80"
1448
+ - "443:443"
1449
+ volumes:
1450
+ - ./nginx.conf:/etc/nginx/conf.d/default.conf
1451
+ - static_volume:/app/staticfiles
1452
+ - media_volume:/app/media
1453
+
1454
+ volumes:
1455
+ postgres_data:
1456
+ static_volume:
1457
+ media_volume:
1458
+ ```
1459
+
1460
+ ### Kubernetes 部署
1461
+
1462
+ ```yaml
1463
+ # k8s/deployment.yaml
1464
+ apiVersion: apps/v1
1465
+ kind: Deployment
1466
+ metadata:
1467
+ name: django-web
1468
+ spec:
1469
+ replicas: 3
1470
+ selector:
1471
+ matchLabels:
1472
+ app: django-web
1473
+ template:
1474
+ metadata:
1475
+ labels:
1476
+ app: django-web
1477
+ spec:
1478
+ containers:
1479
+ - name: web
1480
+ image: myregistry/django-app:latest
1481
+ ports:
1482
+ - containerPort: 8000
1483
+ envFrom:
1484
+ - secretRef:
1485
+ name: django-secrets
1486
+ - configMapRef:
1487
+ name: django-config
1488
+ resources:
1489
+ requests:
1490
+ cpu: "250m"
1491
+ memory: "256Mi"
1492
+ limits:
1493
+ cpu: "1000m"
1494
+ memory: "512Mi"
1495
+ readinessProbe:
1496
+ httpGet:
1497
+ path: /health/
1498
+ port: 8000
1499
+ initialDelaySeconds: 10
1500
+ periodSeconds: 5
1501
+ livenessProbe:
1502
+ httpGet:
1503
+ path: /health/
1504
+ port: 8000
1505
+ initialDelaySeconds: 30
1506
+ periodSeconds: 15
1507
+ ```
1508
+
1509
+ ---
1510
+
1511
+ ## 性能优化
1512
+
1513
+ ### 数据库查询优化
1514
+
1515
+ ```python
1516
+ # 1. 使用 select_related 减少 ForeignKey 查询
1517
+ # 差: 每篇文章额外查询 author 和 category
1518
+ articles = Article.objects.all()
1519
+ for a in articles:
1520
+ print(a.author.email) # N+1 查询!
1521
+
1522
+ # 好: 单次 JOIN 查询
1523
+ articles = Article.objects.select_related("author", "category").all()
1524
+
1525
+ # 2. 使用 prefetch_related 处理 ManyToMany
1526
+ articles = Article.objects.prefetch_related("tags").all()
1527
+
1528
+ # 3. 只查需要的字段
1529
+ Article.objects.values_list("id", "title", flat=False)
1530
+ Article.objects.only("id", "title", "status")
1531
+ Article.objects.defer("body") # 延迟加载大字段
1532
+
1533
+ # 4. 使用 iterator() 处理大结果集
1534
+ for article in Article.objects.all().iterator(chunk_size=2000):
1535
+ process(article)
1536
+
1537
+ # 5. 批量操作
1538
+ Article.objects.bulk_create([
1539
+ Article(title=f"Article {i}", body="...", author=user)
1540
+ for i in range(1000)
1541
+ ], batch_size=500)
1542
+
1543
+ Article.objects.filter(status="draft").update(status="archived")
1544
+
1545
+ Article.objects.bulk_update(articles, ["status", "updated_at"], batch_size=500)
1546
+ ```
1547
+
1548
+ ### 索引策略
1549
+
1550
+ ```python
1551
+ class Article(models.Model):
1552
+ class Meta:
1553
+ indexes = [
1554
+ # 单字段索引
1555
+ models.Index(fields=["status"]),
1556
+ # 复合索引 —— 查询条件的列顺序要与索引一致
1557
+ models.Index(fields=["status", "-publish_date"]),
1558
+ # 部分索引(PostgreSQL)
1559
+ models.Index(
1560
+ fields=["publish_date"],
1561
+ condition=Q(status="published"),
1562
+ name="idx_published_date",
1563
+ ),
1564
+ # 覆盖索引(PostgreSQL,Django 5.0+)
1565
+ models.Index(
1566
+ fields=["status"],
1567
+ include=["title", "publish_date"],
1568
+ name="idx_status_covering",
1569
+ ),
1570
+ ]
1571
+ ```
1572
+
1573
+ ### 查询调试
1574
+
1575
+ ```python
1576
+ # 在开发环境中追踪查询
1577
+ from django.db import connection, reset_queries
1578
+
1579
+ reset_queries()
1580
+ # ... 执行查询 ...
1581
+ print(f"Total queries: {len(connection.queries)}")
1582
+ for q in connection.queries:
1583
+ print(f"[{q['time']}s] {q['sql'][:200]}")
1584
+
1585
+ # 使用 django-debug-toolbar
1586
+ INSTALLED_APPS += ["debug_toolbar"]
1587
+ MIDDLEWARE += ["debug_toolbar.middleware.DebugToolbarMiddleware"]
1588
+ INTERNAL_IPS = ["127.0.0.1"]
1589
+
1590
+ # QuerySet.explain() 查看执行计划
1591
+ qs = Article.objects.filter(status="published").order_by("-publish_date")
1592
+ print(qs.explain(analyze=True))
1593
+ ```
1594
+
1595
+ ---
1596
+
1597
+ ## 常见陷阱
1598
+
1599
+ ### N+1 查询
1600
+
1601
+ ```python
1602
+ # 陷阱: 模板或序列化器中触发隐式查询
1603
+ # 检测方法: django-debug-toolbar / django-silk / nplusone
1604
+
1605
+ # 解决方案: 在 QuerySet 层提前 JOIN 或预取
1606
+ # View 层负责定义 QuerySet,Serializer 不应触发额外查询
1607
+
1608
+ class ArticleViewSet(viewsets.ModelViewSet):
1609
+ def get_queryset(self):
1610
+ return (
1611
+ Article.objects
1612
+ .select_related("author", "category")
1613
+ .prefetch_related("tags", "comments__author")
1614
+ .annotate(comment_count=Count("comments"))
1615
+ )
1616
+ ```
1617
+
1618
+ ### 信号滥用
1619
+
1620
+ ```python
1621
+ # 陷阱: 把业务逻辑放在信号中
1622
+ # - 隐式执行,难以调试和追踪
1623
+ # - 多个信号之间可能存在顺序依赖
1624
+ # - 信号异常可能被吞掉
1625
+
1626
+ # 解决方案: 使用 Service 层替代
1627
+ class ArticleService:
1628
+ @staticmethod
1629
+ def publish(article):
1630
+ article.status = "published"
1631
+ article.publish_date = timezone.now()
1632
+ article.save(update_fields=["status", "publish_date"])
1633
+ # 明确的后续操作
1634
+ send_notification_email.delay(article.author_id, "article_published.html", {...})
1635
+ cache.delete(f"article:{article.id}")
1636
+ return article
1637
+ ```
1638
+
1639
+ ### Fat Models 反模式
1640
+
1641
+ ```python
1642
+ # 陷阱: Model 中包含大量业务逻辑、外部调用、邮件发送
1643
+ class Article(models.Model):
1644
+ def publish(self):
1645
+ self.status = "published"
1646
+ self.save()
1647
+ send_mail(...) # 模型不应直接发邮件
1648
+ requests.post(...) # 模型不应调用外部服务
1649
+ cache.delete(...) # 模型不应管理缓存
1650
+
1651
+ # 解决方案: 将业务逻辑抽到 Service 层
1652
+ # Model 只负责: 字段定义、Meta、__str__、简单计算属性、自定义 Manager
1653
+ # Service 层负责: 业务流程、外部调用、缓存、通知
1654
+ ```
1655
+
1656
+ ### 其他常见陷阱
1657
+
1658
+ ```python
1659
+ # 1. 在循环中 save() —— 应使用 bulk_update
1660
+ for article in articles:
1661
+ article.view_count += 1
1662
+ article.save() # 每次都是一条 UPDATE!
1663
+
1664
+ # 修正
1665
+ Article.objects.filter(id__in=ids).update(view_count=F("view_count") + 1)
1666
+
1667
+ # 2. 未正确使用事务
1668
+ from django.db import transaction
1669
+
1670
+ # 差: 部分成功部分失败
1671
+ def transfer_funds(from_account, to_account, amount):
1672
+ from_account.balance -= amount
1673
+ from_account.save()
1674
+ # 如果这里崩溃,钱就消失了!
1675
+ to_account.balance += amount
1676
+ to_account.save()
1677
+
1678
+ # 好: 原子事务
1679
+ @transaction.atomic
1680
+ def transfer_funds(from_account, to_account, amount):
1681
+ from_account.balance = F("balance") - amount
1682
+ from_account.save(update_fields=["balance"])
1683
+ to_account.balance = F("balance") + amount
1684
+ to_account.save(update_fields=["balance"])
1685
+
1686
+ # 3. settings.py 中硬编码秘密信息
1687
+ SECRET_KEY = "hardcoded-secret" # 永远不要这样做!
1688
+ SECRET_KEY = os.environ["DJANGO_SECRET_KEY"] # 从环境变量读取
1689
+
1690
+ # 4. 迁移中使用当前模型代码
1691
+ # 差: 迁移运行时模型可能已变
1692
+ from apps.users.models import User
1693
+
1694
+ # 好: 使用历史模型
1695
+ def forward(apps, schema_editor):
1696
+ User = apps.get_model("users", "User")
1697
+ ```
1698
+
1699
+ ---
1700
+
1701
+ ## Agent Checklist
1702
+
1703
+ 以下是 UmaDev Agent 在 Django 项目中执行审查和交付时必须验证的检查清单:
1704
+
1705
+ ### 项目结构
1706
+ - [ ] 使用 settings 拆分(base/dev/staging/prod)
1707
+ - [ ] `AUTH_USER_MODEL` 在第一次迁移前已定义
1708
+ - [ ] 每个 app 有独立的 `tests/` 目录和 `factories.py`
1709
+ - [ ] requirements 按环境拆分(base/dev/prod)
1710
+
1711
+ ### ORM 与数据库
1712
+ - [ ] 所有 ForeignKey 查询使用 `select_related`
1713
+ - [ ] 所有 ManyToMany / 反向查询使用 `prefetch_related`
1714
+ - [ ] 列表接口使用 `only()` / `defer()` 排除大字段
1715
+ - [ ] 批量操作使用 `bulk_create` / `bulk_update` 而非循环 save
1716
+ - [ ] 高频查询字段有 `db_index=True` 或 Meta.indexes
1717
+ - [ ] 关键写操作包裹在 `transaction.atomic` 中
1718
+ - [ ] 迁移中使用 `apps.get_model()` 而非直接 import
1719
+
1720
+ ### 认证与权限
1721
+ - [ ] 自定义 User 模型继承 `AbstractUser` 或 `AbstractBaseUser`
1722
+ - [ ] JWT 配置了 token 过期时间和刷新轮换
1723
+ - [ ] API ViewSet 显式声明 `permission_classes`
1724
+ - [ ] 对象级权限已实现(如 IsAuthorOrReadOnly)
1725
+
1726
+ ### REST API
1727
+ - [ ] 列表和详情使用不同 Serializer(轻量 vs 完整)
1728
+ - [ ] 分页已配置(推荐 CursorPagination 用于大数据集)
1729
+ - [ ] 限流已配置(区分匿名和认证用户)
1730
+ - [ ] 输入验证在 Serializer 层完成(validate_field / validate)
1731
+
1732
+ ### 缓存
1733
+ - [ ] Redis 连接池大小和超时已配置
1734
+ - [ ] 缓存 key 有命名规范和前缀
1735
+ - [ ] 数据变更时有缓存失效策略
1736
+ - [ ] 不缓存包含用户敏感信息的响应
1737
+
1738
+ ### 异步任务
1739
+ - [ ] Celery 任务配置了 `max_retries` 和 `time_limit`
1740
+ - [ ] 使用 `retry_backoff=True` 避免重试风暴
1741
+ - [ ] 任务参数可 JSON 序列化(不传 Model 实例,传 ID)
1742
+ - [ ] 定时任务通过 Beat 管理,不使用 cron 直调
1743
+
1744
+ ### 安全
1745
+ - [ ] 生产环境 `DEBUG=False`
1746
+ - [ ] `SECRET_KEY` 从环境变量读取
1747
+ - [ ] HSTS/SSL/Secure Cookie 已启用
1748
+ - [ ] CSRF 保护正确配置(Session 认证开启,纯 JWT 可排除)
1749
+ - [ ] 用户输入 HTML 经过 `bleach` 清理
1750
+ - [ ] Raw SQL 使用参数化查询
1751
+ - [ ] CSP 头已配置
1752
+
1753
+ ### 测试
1754
+ - [ ] 单元测试覆盖率 >= 85%
1755
+ - [ ] 使用 Factory Boy 而非手动创建测试数据
1756
+ - [ ] API 测试覆盖认证、权限、分页、错误场景
1757
+ - [ ] 使用 `setUpTestData` 替代 `setUp` 提升速度
1758
+
1759
+ ### 部署
1760
+ - [ ] Gunicorn workers 数量 = CPU * 2 + 1
1761
+ - [ ] Nginx 配置静态文件直接服务和缓存头
1762
+ - [ ] Docker 镜像使用非 root 用户运行
1763
+ - [ ] 健康检查端点 `/health/` 已实现
1764
+ - [ ] 数据库连接配置 `CONN_MAX_AGE` 和超时
1765
+ - [ ] Celery worker 配置了 `max_tasks_per_child` 防止内存泄漏