Kodningsstil¶
Följ dessa kodningsstandarder när du skriver kod som ska inkluderas i Django.
Kontroller före åtagandet¶
pre-commit är ett ramverk för att hantera pre-commit hooks. Dessa krokar hjälper till att identifiera enkla problem innan koden skickas för granskning. Genom att kontrollera dessa problem före kodgranskningen kan granskaren fokusera på själva ändringen, och det kan också bidra till att minska antalet CI-körningar.
För att använda verktyget måste du först installera pre-commit
och sedan git-krokarna:
$ python -m pip install pre-commit
$ pre-commit install
...\> py -m pip install pre-commit
...\> pre-commit install
Vid det första åtagandet kommer pre-commit
att installera krokarna, dessa installeras i sina egna miljöer och tar en kort stund att installera vid första körningen. Efterföljande kontroller kommer att vara betydligt snabbare. Om ett fel hittas kommer ett lämpligt felmeddelande att visas. Om felet gällde black
eller isort
kommer verktyget att gå vidare och åtgärda dem åt dig. Granska ändringarna och lägg upp dem på nytt för commit om du är nöjd med dem.
Python-stil¶
Alla filer bör formateras med hjälp av den automatiska formateraren black. Detta kommer att köras av
pre-commit
om det är konfigurerat.Projektarkivet innehåller en fil med namnet
.editorconfig
. Vi rekommenderar att du använder en textredigerare med stöd för EditorConfig för att undvika problem med indragning och blanksteg. Python-filerna använder 4 mellanslag för indragning och HTML-filerna använder 2 mellanslag.Om inte annat anges, följ PEP 8.
Use flake8 to check for problems in this area. Note that our
.flake8
file excludes some errors that we don’t consider as gross violations. Remember that PEP 8 is only a guide, so respect the style of the surrounding code as a primary goal.Ett undantag från PEP 8 är våra regler om radlängder. Begränsa inte kodrader till 79 tecken om det innebär att koden ser betydligt fulare ut eller är svårare att läsa. Vi tillåter upp till 88 tecken eftersom detta är den radlängd som används av
black
. Denna kontroll ingår när du körflake8
. Dokumentation, kommentarer och docstrings bör vara omslutna av 79 tecken, även om PEP 8 föreslår 72.Interpolering av strängvariabler kan använda %-formatting, f-strings, eller
str.format()
på lämpligt sätt, med målet att maximera kodens läsbarhet.Slutliga bedömningar av läsbarheten lämnas till Merger’s diskretion. Som en vägledning bör f-strängar endast använda vanlig variabel- och egenskapsåtkomst, med föregående lokal variabeltilldelning för mer komplexa fall:
# Allowed f"hello {user}" f"hello {user.name}" f"hello {self.user.name}" # Disallowed f"hello {get_user()}" f"you are {user.age * 365.25} days old" # Allowed with local variable assignment user = get_user() f"hello {user}" user_days_old = user.age * 365.25 f"you are {user_days_old} days old"
f-strings bör inte användas för strängar som kan behöva översättas, t.ex. fel- och loggmeddelanden. I allmänhet är
format()
mer omständlig, så de andra formateringsmetoderna är att föredra.Slösa inte tid på att göra en orelaterad refaktorisering av befintlig kod för att justera formateringsmetoden.
Undvik att använda ”vi” i kommentarer, t.ex. ”Loop over” i stället för ”We loop over”.
Använd understrykningstecken, inte camelCase, för variabel-, funktions- och metodnamn (t.ex.
poll.get_unique_voters()
, intepoll.getUniqueVoters()
).Använd
InitialCaps
för klassnamn (eller för fabriksfunktioner som returnerar klasser).I dokumentationer, följ stilen för befintliga dokumentationer och PEP 257.
I tester, använd
assertRaisesMessage()
ochassertWarnsMessage()
istället förassertRaises()
ochassertWarns()
så att du kan kontrollera undantaget eller varningsmeddelandet. AnvändassertRaisesRegex()
ochassertWarnsRegex()
endast om du behöver matchning med reguljära uttryck.Använd
assertIs(..., True/False)
för att testa booleska värden, snarare änassertTrue()
ochassertFalse()
, så att du kan kontrollera det faktiska booleska värdet, inte sanningshalten i uttrycket.I testdokumentationer ska du ange det förväntade beteende som varje test demonstrerar. Inkludera inte ingresser som ”Testar att” eller ”Säkerställer att”.
Reservera ärendehänvisningar för obskyra frågor där ärendet innehåller ytterligare detaljer som inte enkelt kan beskrivas i dokument eller kommentarer. Inkludera ärendenumret i slutet av en mening så här:
def test_foo(): """ A test docstring looks like this (#123456). """ ...
Där det är tillämpligt, använd uppackningsgeneraliseringar som överensstämmer med PEP 448, till exempel sammanslagning av mappningar (
{**x, **y}
) eller sekvenser ([*a, *b]
). Detta förbättrar prestanda, läsbarhet och underhållsmässighet samtidigt som det minskar antalet fel.
Importera¶
Använd isort för att automatisera importsorteringen enligt riktlinjerna nedan.
Snabb start:
$ python -m pip install "isort >= 5.1.0" $ isort .
...\> py -m pip install "isort >= 5.1.0" ...\> isort .
Detta kör
isort
rekursivt från din aktuella katalog och ändrar alla filer som inte överensstämmer med riktlinjerna. Om du behöver ha import i fel ordning (för att undvika cirkulär import, till exempel), använd en kommentar som denna:import module # isort:skip
Lägg import i dessa grupper: future, standardbibliotek, tredjepartsbibliotek, andra Django-komponenter, lokal Django-komponent, try/excepts. Sortera raderna i varje grupp alfabetiskt efter det fullständiga modulnamnet. Placera alla
import module
-satser förefrom module import objects
i varje avsnitt. Använd absolut import för andra Django-komponenter och relativ import för lokala komponenter.Alfabetisera artiklarna på varje rad med de versala artiklarna grupperade före de gemena artiklarna.
Bryt långa rader med parenteser och dra in fortsättningsraderna med 4 mellanslag. Sätt ett efterföljande kommatecken efter den sista importen och sätt den avslutande parentesen på en egen rad.
Använd en blankrad mellan den sista importen och all kod på modulnivå, och använd två blankrader ovanför den första funktionen eller klassen.
Till exempel (kommentarerna är endast i förklarande syfte):
django/contrib/admin/example.py
¶# future from __future__ import unicode_literals # standard library import json from itertools import chain # third-party import bcrypt # Django from django.http import Http404 from django.http.response import ( Http404, HttpResponse, HttpResponseNotAllowed, StreamingHttpResponse, cookie, ) # local Django from .models import LogEntry # try/except try: import yaml except ImportError: yaml = None CONSTANT = "foo" class Example: ...
Använd bekvämlighetsimport när det är möjligt. Gör till exempel så här
from django.views import View
istället för:
from django.views.generic.base import View
Mallens stil¶
Följ nedanstående regler i Django mallkod.
{% extends %}
bör vara den första raden utan kommentar.Gör så här:
{% extends "base.html" %} {% block content %} <h1 class="font-semibold text-xl"> {{ pages.title }} </h1> {% endblock content %}
Eller det här:
{# This is a comment #} {% extends "base.html" %} {% block content %} <h1 class="font-semibold text-xl"> {{ pages.title }} </h1> {% endblock content %}
Gör inte så här:
{% load i18n %} {% extends "base.html" %} {% block content %} <h1 class="font-semibold text-xl"> {{ pages.title }} </h1> {% endblock content %}
Lägg till exakt ett mellanslag mellan
{{
, variabelinnehåll och}}
.Gör så här:
{{ user }}
Gör inte så här:
{{user}}
I
{% load ... %}
, lista bibliotek i alfabetisk ordning.Gör så här:
{% load i18n l10 tz %}
Gör inte så här:
{% load l10 i18n tz %}
Lägg till exakt ett mellanslag mellan
{%
, taggens innehåll och%}
.Gör så här:
{% load humanize %}
Gör inte så här:
{%load humanize%}
Lägg till taggnamnet
{% block %}
i taggen{% endblock %}
om den inte står på samma rad.Gör så här:
{% block header %} Code goes here {% endblock header %}
Gör inte så här:
{% block header %} Code goes here {% endblock %}
Inom hakparenteser separeras tokens med enkla mellanslag, utom runt
.
för attributåtkomst och|
för ett filter.Gör så här:
{% if user.name|lower == "admin" %}
Gör inte så här:
{% if user . name | lower == "admin" %} {{ user.name | upper }}
Inom en mall som använder
{% extends %}
, undvik indragning av toppnivå{% block %}
taggar.Gör så här:
{% extends "base.html" %} {% block content %}
Gör inte så här:
{% extends "base.html" %} {% block content %} ...
Visa stil¶
I Django-vyer ska den första parametern i en vyfunktion heta
request
.Gör så här:
def my_view(request, foo): ...
Gör inte så här:
def my_view(req, foo): ...
Modell stil¶
Fältnamn ska vara gemener och underscores ska användas i stället för camelCase.
Gör så här:
class Person(models.Model): first_name = models.CharField(max_length=20) last_name = models.CharField(max_length=40)
Gör inte så här:
class Person(models.Model): FirstName = models.CharField(max_length=20) Last_Name = models.CharField(max_length=40)
Klass Meta bör visas efter att fälten har definierats, med en enda blankrad som skiljer fälten och klassdefinitionen åt.
Gör så här:
class Person(models.Model): first_name = models.CharField(max_length=20) last_name = models.CharField(max_length=40) class Meta: verbose_name_plural = "people"
Gör inte så här:
class Person(models.Model): class Meta: verbose_name_plural = "people" first_name = models.CharField(max_length=20) last_name = models.CharField(max_length=40)
Ordningsföljden för modellens inre klasser och standardmetoder bör vara enligt följande (observera att alla inte är obligatoriska):
Alla databasfält
Anpassade chefsattribut
klass Meta
def __str__()
och andra magiska Python-metoderdef save()`
def get_absolute_url()`
Eventuella anpassade metoder
Om
val
definieras för ett visst modellfält, definieras varje val som en mappning, med ett namn i versaler som ett klassattribut på modellen. Exempel:class MyModel(models.Model): DIRECTION_UP = "U" DIRECTION_DOWN = "D" DIRECTION_CHOICES = { DIRECTION_UP: "Up", DIRECTION_DOWN: "Down", }
Alternativt kan du överväga att använda Uppräkningstyper:
class MyModel(models.Model): class Direction(models.TextChoices): UP = "U", "Up" DOWN = "D", "Down"
Användning av django.conf.settings
¶
Moduler bör i allmänhet inte använda inställningar som lagras i django.conf.settings
på toppnivå (dvs. utvärderas när modulen importeras). Förklaringen till detta är som följer:
Manuell konfiguration av inställningar (dvs. utan att förlita sig på miljövariabeln DJANGO_SETTINGS_MODULE
) är tillåten och möjlig enligt följande:
from django.conf import settings
settings.configure({}, SOME_SETTING="foo")
Men om någon inställning används före raden settings.configure
fungerar inte detta. (Internt är settings
ett LazyObject
som konfigurerar sig själv automatiskt när inställningarna öppnas om det inte redan har konfigurerats).
Så om det finns en modul som innehåller kod enligt följande:
from django.conf import settings
from django.urls import get_callable
default_foo_view = get_callable(settings.FOO_VIEW)
…så kommer import av denna modul att leda till att inställningsobjektet konfigureras. Det innebär att möjligheten för tredje part att importera modulen på högsta nivå är oförenlig med möjligheten att konfigurera inställningsobjektet manuellt, eller gör det mycket svårt under vissa omständigheter.
Istället för ovanstående kod måste en nivå av lathet eller indirektion användas, till exempel django.utils.functional.LazyObject
, django.utils.functional.lazy()
eller lambda
.
Diverse¶
Markera alla strängar för internationalisering; se i18n-dokumentation för mer information.
Ta bort
import
-satser som inte längre används när du ändrar kod. flake8 kommer att identifiera dessa importer åt dig. Om en oanvänd import måste finnas kvar för bakåtkompatibilitet, markera slutet av med# NOQA
för att tysta flake8-varningen.Ta systematiskt bort alla efterföljande blanksteg från din kod eftersom de lägger till onödiga byte, lägger till visuell röra i patcherna och ibland också kan orsaka onödiga sammanfogningskonflikter. Vissa IDE:er kan konfigureras så att de automatiskt tar bort dem och de flesta VCS-verktyg kan ställas in så att de markerar dem i diff-utdata.
Skriv inte ditt namn i den kod du bidrar med. Vår policy är att hålla bidragsgivarnas namn i filen
AUTHORS
som distribueras med Django - inte utspridda i själva kodbasen. Inkludera gärna en ändring av filenAUTHORS
i din patch om du gör mer än en enda trivial ändring.
JavaScript-stil¶
För detaljer om den JavaScript-kodstil som används av Django, se JavaScript-kod.