|
15 | 15 | - [Why not?](#why-not)
|
16 | 16 | - [Cookie Cutter](#cookie-cutter)
|
17 | 17 | - [Models](#models)
|
18 |
| - * [Base model](#base-model) |
19 |
| - * [Validation - `clean` and `full_clean`](#validation---clean-and-full_clean) |
20 |
| - * [Validation - constraints](#validation---constraints) |
21 |
| - * [Properties](#properties) |
22 |
| - * [Methods](#methods) |
23 |
| - * [Testing](#testing) |
| 18 | + - [Base model](#base-model) |
| 19 | + - [Validation - `clean` and `full_clean`](#validation---clean-and-full_clean) |
| 20 | + - [Validation - constraints](#validation---constraints) |
| 21 | + - [Properties](#properties) |
| 22 | + - [Methods](#methods) |
| 23 | + - [Testing](#testing) |
24 | 24 | - [Services](#services)
|
25 |
| - * [Example - function-based service](#example---function-based-service) |
26 |
| - * [Example - class-based service](#example---class-based-service) |
27 |
| - * [Naming convention](#naming-convention) |
28 |
| - * [Modules](#modules) |
29 |
| - * [Selectors](#selectors) |
30 |
| - * [Testing](#testing-1) |
| 25 | + - [Example - function-based service](#example---function-based-service) |
| 26 | + - [Example - class-based service](#example---class-based-service) |
| 27 | + - [Naming convention](#naming-convention) |
| 28 | + - [Modules](#modules) |
| 29 | + - [Selectors](#selectors) |
| 30 | + - [Testing](#testing-1) |
31 | 31 | - [APIs & Serializers](#apis--serializers)
|
32 |
| - * [Naming convention](#naming-convention-1) |
33 |
| - * [Class-based vs. Function-based](#class-based-vs-function-based) |
34 |
| - * [List APIs](#list-apis) |
35 |
| - + [Plain](#plain) |
36 |
| - + [Filters + Pagination](#filters--pagination) |
37 |
| - * [Detail API](#detail-api) |
38 |
| - * [Create API](#create-api) |
39 |
| - * [Update API](#update-api) |
40 |
| - * [Fetching objects](#fetching-objects) |
41 |
| - * [Nested serializers](#nested-serializers) |
42 |
| - * [Advanced serialization](#advanced-serialization) |
| 32 | + - [Naming convention](#naming-convention-1) |
| 33 | + - [Class-based vs. Function-based](#class-based-vs-function-based) |
| 34 | + - [List APIs](#list-apis) |
| 35 | + - [Plain](#plain) |
| 36 | + - [Filters + Pagination](#filters--pagination) |
| 37 | + - [Detail API](#detail-api) |
| 38 | + - [Create API](#create-api) |
| 39 | + - [Update API](#update-api) |
| 40 | + - [Fetching objects](#fetching-objects) |
| 41 | + - [Nested serializers](#nested-serializers) |
| 42 | + - [Advanced serialization](#advanced-serialization) |
43 | 43 | - [Urls](#urls)
|
44 | 44 | - [Settings](#settings)
|
45 |
| - * [Prefixing environment variables with `DJANGO_`](#prefixing-environment-variables-with-django_) |
46 |
| - * [Integrations](#integrations) |
47 |
| - * [Reading from `.env`](#reading-from-env) |
| 45 | + - [Prefixing environment variables with `DJANGO_`](#prefixing-environment-variables-with-django_) |
| 46 | + - [Integrations](#integrations) |
| 47 | + - [Reading from `.env`](#reading-from-env) |
48 | 48 | - [Errors & Exception Handling](#errors--exception-handling)
|
49 |
| - * [How exception handling works (in the context of DRF)](#how-exception-handling-works-in-the-context-of-drf) |
50 |
| - + [DRF's `ValidationError`](#drfs-validationerror) |
51 |
| - + [Django's `ValidationError`](#djangos-validationerror) |
52 |
| - * [Describe how your API errors are going to look like.](#describe-how-your-api-errors-are-going-to-look-like) |
53 |
| - * [Know how to change the default exception handling behavior.](#know-how-to-change-the-default-exception-handling-behavior) |
54 |
| - * [Approach 1 - Use DRF's default exceptions, with very little modifications.](#approach-1---use-drfs-default-exceptions-with-very-little-modifications) |
55 |
| - * [Approach 2 - HackSoft's proposed way](#approach-2---hacksofts-proposed-way) |
56 |
| - * [More ideas](#more-ideas) |
| 49 | + - [How exception handling works (in the context of DRF)](#how-exception-handling-works-in-the-context-of-drf) |
| 50 | + - [DRF's `ValidationError`](#drfs-validationerror) |
| 51 | + - [Django's `ValidationError`](#djangos-validationerror) |
| 52 | + - [Describe how your API errors are going to look like.](#describe-how-your-api-errors-are-going-to-look-like) |
| 53 | + - [Know how to change the default exception handling behavior.](#know-how-to-change-the-default-exception-handling-behavior) |
| 54 | + - [Approach 1 - Use DRF's default exceptions, with very little modifications.](#approach-1---use-drfs-default-exceptions-with-very-little-modifications) |
| 55 | + - [Approach 2 - HackSoft's proposed way](#approach-2---hacksofts-proposed-way) |
| 56 | + - [More ideas](#more-ideas) |
57 | 57 | - [Testing](#testing-2)
|
58 |
| - * [Overview](#overview-1) |
59 |
| - * [Naming conventions](#naming-conventions) |
60 |
| - * [Factories](#factories) |
| 58 | + - [Overview](#overview-1) |
| 59 | + - [Naming conventions](#naming-conventions) |
| 60 | + - [Factories](#factories) |
61 | 61 | - [Celery](#celery)
|
62 |
| - * [The basics](#the-basics) |
63 |
| - * [Error handling](#error-handling) |
64 |
| - * [Configuration](#configuration) |
65 |
| - * [Structure](#structure) |
66 |
| - * [Periodic Tasks](#periodic-tasks) |
67 |
| - * [Beyond](#beyond) |
| 62 | + - [The basics](#the-basics) |
| 63 | + - [Error handling](#error-handling) |
| 64 | + - [Configuration](#configuration) |
| 65 | + - [Structure](#structure) |
| 66 | + - [Periodic Tasks](#periodic-tasks) |
| 67 | + - [Beyond](#beyond) |
68 | 68 | - [Cookbook](#cookbook)
|
69 |
| - * [Handling updates with a service](#handling-updates-with-a-service) |
| 69 | + - [Handling updates with a service](#handling-updates-with-a-service) |
70 | 70 | - [DX (Developer Experience)](#dx-developer-experience)
|
71 |
| - * [`mypy` / type annotations](#mypy--type-annotations) |
| 71 | + - [`mypy` / type annotations](#mypy--type-annotations) |
72 | 72 | - [Django Styleguide in the Wild](#django-styleguide-in-the-wild)
|
73 | 73 | - [Additional resources / Alternatives](#additional-resources--alternatives)
|
74 | 74 | - [Inspiration](#inspiration)
|
@@ -317,7 +317,7 @@ Now, if we try to create new object via `course.save()` or via `Course.objects.c
|
317 | 317 |
|
318 | 318 | This can actually be a downside (_this is not the case, starting from Django 4.1. Check the extra section below._) to the approach, because now, we have to deal with the `IntegrityError`, which does not always have the best error message.
|
319 | 319 |
|
320 |
| -> 👀 ⚠️ 👀 Since Django 4.1, calling `.full_clean` will also check model constraints! |
| 320 | +> 👀 ⚠️ 👀 Since Django 4.1, calling `.full_clean` will also check model constraints! |
321 | 321 | >
|
322 | 322 | > This actually removes the downside, mentioned above, since you'll get a nice `ValidationError`, if your model constraints fail the check (if you go thru `Model.objects.create(...)` the downside still holds)
|
323 | 323 | >
|
@@ -449,7 +449,7 @@ Now, we can safely call `set_new_secret`, that'll produce correct values for bot
|
449 | 449 | 1. If the calculation of the derived value is simple enough.
|
450 | 450 | 1. If setting one attribute always requires setting values to other attributes, use a method for that.
|
451 | 451 |
|
452 |
| -**Models should be something else (service, selector, utility) in the following cases:** |
| 452 | +**Methods should be something else (service, selector, utility) in the following cases:** |
453 | 453 |
|
454 | 454 | 1. If we need to span multiple relations or fetch additional data.
|
455 | 455 | 1. If the calculation is more complex.
|
|
0 commit comments