diff --git a/README.md b/README.md index 6b772db..d5aa88c 100644 --- a/README.md +++ b/README.md @@ -15,60 +15,60 @@ - [Why not?](#why-not) - [Cookie Cutter](#cookie-cutter) - [Models](#models) - * [Base model](#base-model) - * [Validation - `clean` and `full_clean`](#validation---clean-and-full_clean) - * [Validation - constraints](#validation---constraints) - * [Properties](#properties) - * [Methods](#methods) - * [Testing](#testing) + - [Base model](#base-model) + - [Validation - `clean` and `full_clean`](#validation---clean-and-full_clean) + - [Validation - constraints](#validation---constraints) + - [Properties](#properties) + - [Methods](#methods) + - [Testing](#testing) - [Services](#services) - * [Example - function-based service](#example---function-based-service) - * [Example - class-based service](#example---class-based-service) - * [Naming convention](#naming-convention) - * [Modules](#modules) - * [Selectors](#selectors) - * [Testing](#testing-1) + - [Example - function-based service](#example---function-based-service) + - [Example - class-based service](#example---class-based-service) + - [Naming convention](#naming-convention) + - [Modules](#modules) + - [Selectors](#selectors) + - [Testing](#testing-1) - [APIs & Serializers](#apis--serializers) - * [Naming convention](#naming-convention-1) - * [Class-based vs. Function-based](#class-based-vs-function-based) - * [List APIs](#list-apis) - + [Plain](#plain) - + [Filters + Pagination](#filters--pagination) - * [Detail API](#detail-api) - * [Create API](#create-api) - * [Update API](#update-api) - * [Fetching objects](#fetching-objects) - * [Nested serializers](#nested-serializers) - * [Advanced serialization](#advanced-serialization) + - [Naming convention](#naming-convention-1) + - [Class-based vs. Function-based](#class-based-vs-function-based) + - [List APIs](#list-apis) + - [Plain](#plain) + - [Filters + Pagination](#filters--pagination) + - [Detail API](#detail-api) + - [Create API](#create-api) + - [Update API](#update-api) + - [Fetching objects](#fetching-objects) + - [Nested serializers](#nested-serializers) + - [Advanced serialization](#advanced-serialization) - [Urls](#urls) - [Settings](#settings) - * [Prefixing environment variables with `DJANGO_`](#prefixing-environment-variables-with-django_) - * [Integrations](#integrations) - * [Reading from `.env`](#reading-from-env) + - [Prefixing environment variables with `DJANGO_`](#prefixing-environment-variables-with-django_) + - [Integrations](#integrations) + - [Reading from `.env`](#reading-from-env) - [Errors & Exception Handling](#errors--exception-handling) - * [How exception handling works (in the context of DRF)](#how-exception-handling-works-in-the-context-of-drf) - + [DRF's `ValidationError`](#drfs-validationerror) - + [Django's `ValidationError`](#djangos-validationerror) - * [Describe how your API errors are going to look like.](#describe-how-your-api-errors-are-going-to-look-like) - * [Know how to change the default exception handling behavior.](#know-how-to-change-the-default-exception-handling-behavior) - * [Approach 1 - Use DRF's default exceptions, with very little modifications.](#approach-1---use-drfs-default-exceptions-with-very-little-modifications) - * [Approach 2 - HackSoft's proposed way](#approach-2---hacksofts-proposed-way) - * [More ideas](#more-ideas) + - [How exception handling works (in the context of DRF)](#how-exception-handling-works-in-the-context-of-drf) + - [DRF's `ValidationError`](#drfs-validationerror) + - [Django's `ValidationError`](#djangos-validationerror) + - [Describe how your API errors are going to look like.](#describe-how-your-api-errors-are-going-to-look-like) + - [Know how to change the default exception handling behavior.](#know-how-to-change-the-default-exception-handling-behavior) + - [Approach 1 - Use DRF's default exceptions, with very little modifications.](#approach-1---use-drfs-default-exceptions-with-very-little-modifications) + - [Approach 2 - HackSoft's proposed way](#approach-2---hacksofts-proposed-way) + - [More ideas](#more-ideas) - [Testing](#testing-2) - * [Overview](#overview-1) - * [Naming conventions](#naming-conventions) - * [Factories](#factories) + - [Overview](#overview-1) + - [Naming conventions](#naming-conventions) + - [Factories](#factories) - [Celery](#celery) - * [The basics](#the-basics) - * [Error handling](#error-handling) - * [Configuration](#configuration) - * [Structure](#structure) - * [Periodic Tasks](#periodic-tasks) - * [Beyond](#beyond) + - [The basics](#the-basics) + - [Error handling](#error-handling) + - [Configuration](#configuration) + - [Structure](#structure) + - [Periodic Tasks](#periodic-tasks) + - [Beyond](#beyond) - [Cookbook](#cookbook) - * [Handling updates with a service](#handling-updates-with-a-service) + - [Handling updates with a service](#handling-updates-with-a-service) - [DX (Developer Experience)](#dx-developer-experience) - * [`mypy` / type annotations](#mypy--type-annotations) + - [`mypy` / type annotations](#mypy--type-annotations) - [Django Styleguide in the Wild](#django-styleguide-in-the-wild) - [Additional resources / Alternatives](#additional-resources--alternatives) - [Inspiration](#inspiration) @@ -317,7 +317,7 @@ Now, if we try to create new object via `course.save()` or via `Course.objects.c 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. -> 👀 ⚠️ 👀 Since Django 4.1, calling `.full_clean` will also check model constraints! +> 👀 ⚠️ 👀 Since Django 4.1, calling `.full_clean` will also check model constraints! > > 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) > @@ -449,7 +449,7 @@ Now, we can safely call `set_new_secret`, that'll produce correct values for bot 1. If the calculation of the derived value is simple enough. 1. If setting one attribute always requires setting values to other attributes, use a method for that. -**Models should be something else (service, selector, utility) in the following cases:** +**Methods should be something else (service, selector, utility) in the following cases:** 1. If we need to span multiple relations or fetch additional data. 1. If the calculation is more complex.