Applikationer¶
Django innehåller ett register över installerade applikationer som lagrar konfiguration och ger introspektion. Det upprätthåller också en lista över tillgängliga modeller.
Det här registret kallas apps
och finns i django.apps
:
>>> from django.apps import apps
>>> apps.get_app_config("admin").verbose_name
'Administration'
Projekt och tillämpningar¶
Termen projekt beskriver en Django webbapplikation. Projektets Python-paket definieras främst av en inställningsmodul, men det innehåller vanligtvis andra saker. Till exempel:, när du kör django-admin startproject mysite
får du en mysite
projektkatalog som innehåller ett mysite
Python-paket med settings.py
, urls.py
, asgi.py
och wsgi.py
. Projektpaketet utökas ofta för att inkludera saker som fixturer, CSS och mallar som inte är knutna till en viss applikation.
Ett projekts rotkatalog (den som innehåller manage.py
) är vanligtvis behållaren för alla ett projekts applikationer som inte installeras separat.
Termen applikation beskriver ett Python-paket som tillhandahåller en viss uppsättning funktioner. Applikationer kan återanvändas i olika projekt.
Applikationer innehåller en kombination av modeller, vyer, mallar, malltaggar, statiska filer, webbadresser, mellanprogram osv. De är i allmänhet kopplade till projekt med inställningen INSTALLED_APPS
och eventuellt med andra mekanismer som URLconfs, inställningen MIDDLEWARE
eller mallarv.
Det är viktigt att förstå att en Django-applikation är en uppsättning kod som interagerar med olika delar av ramverket. Det finns inget sådant som ett Application
-objekt. Det finns dock några ställen där Django behöver interagera med installerade applikationer, främst för konfiguration och även för introspektion. Det är därför som applikationsregistret upprätthåller metadata i en AppConfig
-instans för varje installerad applikation.
Det finns inga begränsningar för att ett projektpaket inte också kan betraktas som en applikation och ha modeller etc. (vilket skulle kräva att det läggs till i INSTALLED_APPS
).
Konfigurera applikationer¶
För att konfigurera en applikation skapar du en apps.py
-modul i applikationen och definierar sedan en subklass av AppConfig
där.
När INSTALLED_APPS
innehåller den prickade sökvägen till en applikationsmodul, som standard, om Django hittar exakt en AppConfig
subklass i apps.py
submodulen, använder den den konfigurationen för applikationen. Detta beteende kan inaktiveras genom att ställa in AppConfig.default
till False
.
Om modulen apps.py
innehåller mer än en AppConfig
-underklass, kommer Django att leta efter en enda där AppConfig.default
är True
.
Om ingen underklass till AppConfig
hittas, kommer basklassen AppConfig
att användas.
Alternativt kan INSTALLED_APPS
innehålla den prickade sökvägen till en konfigurationsklass för att ange den explicit:
INSTALLED_APPS = [
...,
"polls.apps.PollsAppConfig",
...,
]
För applikationsanvändare¶
Om du använder ”Rock ’n’ roll” i ett projekt som heter anthology
, men du vill att det ska visas som ”Jazz Manouche” istället, kan du ange din egen konfiguration:
# anthology/apps.py
from rock_n_roll.apps import RockNRollConfig
class JazzManoucheConfig(RockNRollConfig):
verbose_name = "Jazz Manouche"
# anthology/settings.py
INSTALLED_APPS = [
"anthology.apps.JazzManoucheConfig",
# ...
]
Detta exempel visar projektspecifika konfigurationsklasser som finns i en undermodul som heter apps.py
. Detta är en konvention, inte ett krav. AppConfig
-subklasser kan definieras var som helst.
I den här situationen måste INSTALLED_APPS
innehålla den prickade sökvägen till konfigurationsklassen eftersom den ligger utanför ett program och därför inte kan upptäckas automatiskt.
Konfiguration av applikation¶
- class AppConfig[source]¶
Applikationskonfigurationsobjekt lagrar metadata för en applikation. Vissa attribut kan konfigureras i
AppConfig
subklasser. Andra ställs in av Django och är skrivskyddade.
Konfigurerbara attribut¶
- AppConfig.name¶
Fullständig Python-sökväg till applikationen, t.ex.
'django.contrib.admin'
.Detta attribut definierar vilken applikation som konfigurationen gäller för. Det måste anges i alla
AppConfig
-subklasser.Den måste vara unik för hela Django-projektet.
- AppConfig.label¶
Kortnamn för applikationen, t.ex.
'admin'
Detta attribut möjliggör ommärkning av en applikation när två applikationer har motstridiga etiketter. Standardvärdet är den sista komponenten i
name
. Det bör vara en giltig Python-identifierare.Den måste vara unik för hela Django-projektet.
Varning
Om du ändrar det här attributet efter att migreringar har tillämpats för en applikation kommer det att leda till att ändringar i ett projekt eller, när det gäller en återanvändbar app, alla befintliga installationer av den appen bryts. Detta beror på att
AppConfig.label
används i databastabeller och migreringsfiler när en app refereras till i beroendelistan.
- AppConfig.verbose_name¶
Ett mänskligt läsbart namn för applikationen, t.ex. ”Administration”.
Standardvärdet för detta attribut är
label.title()
.
- AppConfig.path¶
Filsystemets sökväg till applikationskatalogen, t.ex.
'/usr/lib/pythonX.Y/dist-packages/django/contrib/admin'
.I de flesta fall kan Django automatiskt upptäcka och ställa in detta, men du kan också tillhandahålla en explicit åsidosättning som ett klassattribut på din
AppConfig
-underklass. I några få situationer krävs detta; till exempel om app-paketet är ett namespace package med flera sökvägar.
- AppConfig.default¶
Sätt detta attribut till
False
för att förhindra Django från att välja en konfigurationsklass automatiskt. Detta är användbart närapps.py
bara definierar enAppConfig
-underklass men du inte vill att Django ska använda den som standard.Sätt detta attribut till
True
för att säga till Django att välja en konfigurationsklass automatiskt. Detta är användbart närapps.py
definierar mer än enAppConfig
-underklass och du vill att Django ska använda en av dem som standard.Som standard är detta attribut inte inställt.
- AppConfig.default_auto_field[source]¶
Den implicita primära nyckeltypen som ska läggas till i modeller i den här appen. Du kan använda detta för att behålla
AutoField
som primärnyckeltyp för tredjepartsapplikationer.Som standard är detta värdet för
DEFAULT_AUTO_FIELD
.
Skrivskyddade attribut¶
- AppConfig.module¶
Rotmodul för applikationen, t.ex.
<module 'django.contrib.admin' from 'django/contrib/admin/__init__.py'>
.
- AppConfig.models_module¶
Modul som innehåller modellerna, t.ex.
<module 'django.contrib.admin.models' from 'django/contrib/admin/models.py'>
.Den kan vara
None
om applikationen inte innehåller enmodels
modul. Observera att de databasrelaterade signalerna sompre_migrate
ochpost_migrate
endast sänds ut för applikationer som har enmodels
-modul.
Metoder¶
- AppConfig.get_models(include_auto_created=False, include_swapped=False)[source]¶
Returnerar en iterabel av
Model
-klasser för denna applikation.Kräver att appregistret är helt fyllt.
- AppConfig.get_model(model_name, require_ready=True)[source]¶
Returnerar
Model
med det angivnamodel_name
.model_name
är skiftlägesokänsligt.Utlöser
LookupError
om ingen sådan modell finns i denna applikation.Kräver att appregistret är helt fyllt om inte argumentet
require_ready
är satt tillFalse
.require_ready
beter sig exakt som iapps.get_model()
.
- AppConfig.ready()[source]¶
Underklasser kan åsidosätta denna metod för att utföra initialiseringsuppgifter som t.ex. registrering av signaler. Den anropas så snart registret är helt fyllt.
Även om du inte kan importera modeller på modulnivå där
AppConfig
-klasserna definieras, kan du importera dem iready()
, antingen med hjälp av enimport
-sats ellerget_model()
.Om du registrerar
modellsignaler
kan du hänvisa till avsändaren med dess strängetikett istället för att använda själva modellklassen.Exempel:
from django.apps import AppConfig from django.db.models.signals import pre_save class RockNRollConfig(AppConfig): # ... def ready(self): # importing model classes from .models import MyModel # or... MyModel = self.get_model("MyModel") # registering signals with the model's string label pre_save.connect(receiver, sender="app_label.MyModel")
Varning
Även om du kan komma åt modellklasser enligt beskrivningen ovan bör du undvika att interagera med databasen i din
ready()
-implementering. Detta inkluderar modellmetoder som utför frågor (save()
,delete()
, managermetoder etc.), och även råa SQL-frågor viadjango.db.connection
. Dinready()
-metod kommer att köras under uppstarten av varje hanteringskommando. Till exempel:, även om testdatabasens konfiguration är separat från produktionsinställningarna, kommermanage.py test
fortfarande att köra några frågor mot din produktions databas!Observera
I den vanliga initialiseringsprocessen anropas metoden
ready
bara en gång av Django. Men i vissa hörnfall, särskilt i tester som manipulerar installerade applikationer, kanready
anropas mer än en gång. I så fall ska du antingen skriva idempotenta metoder eller sätta en flagga på dinaAppConfig
-klasser för att förhindra att kod som ska köras exakt en gång körs om.
Namnrymdspaket som appar¶
Python-paket utan filen __init__.py
kallas ”namespace-paket” och kan vara spridda över flera kataloger på olika platser i sys.path
(se PEP 420).
Django-applikationer kräver en enda basfilsystemssökväg där Django (beroende på konfiguration) kommer att söka efter mallar, statiska tillgångar etc. Namnrymdspaket kan således endast vara Django-applikationer om något av följande är sant:
Namnrymdspaketet har faktiskt bara en enda plats (dvs. det är inte utspritt över mer än en katalog)
Klassen
AppConfig
som används för att konfigurera applikationen har ett klassattributpath
, som är den absoluta katalogsökvägen som Django kommer att använda som den enda basvägen för applikationen.
Om inget av dessa villkor uppfylls kommer Django att ge upphov till ImproperlyConfigured
.
Applikationsregister¶
- apps¶
Applikationsregistret tillhandahåller följande offentliga API. Metoder som inte listas nedan betraktas som privata och kan ändras utan föregående meddelande.
- apps.ready¶
Booleskt attribut som sätts till
True
när registret är helt fyllt och allaAppConfig.ready()
-metoder har anropats.
- apps.get_app_config(app_label)¶
Returnerar en
AppConfig
för applikationen med den angivnaapp_label
. UtlöserLookupError
om ingen sådan applikation finns.
- apps.is_installed(app_name)¶
Kontrollerar om en applikation med det angivna namnet finns i registret.
app_name
är det fullständiga namnet på appen, t.ex.'django.contrib.admin'
.
- apps.get_model(app_label, model_name, require_ready=True)¶
Returnerar
Model
med de givnaapp_label
ochmodel_name
. Som en genväg accepterar denna metod också ett enda argument i form avapp_label.model_name
.model_name
är skiftlägesokänsligt.Ger upphov till
LookupError
om ingen sådan applikation eller modell finns. Ger upphov tillValueError
när den anropas med ett enda argument som inte innehåller exakt en punkt.Kräver att appregistret är helt fyllt om inte argumentet
require_ready
är satt tillFalse
.Om du ställer in
require_ready
tillFalse
kan du leta upp modeller :ref:medan appregistret fylls på <app-loading-process>`, särskilt under den andra fasen där den importerar modeller. Då har ``get_model()
samma effekt som att importera modellen. Det huvudsakliga användningsfallet är att konfigurera modellklasser med inställningar, till exempelAUTH_USER_MODEL
.När
require_ready
ärFalse
returnerarget_model()
en modellklass som kanske inte är helt funktionell (omvända accessorer kan till exempel saknas) förrän appregistret är helt fyllt. Av denna anledning är det bäst att lämnarequire_ready
till standardvärdetTrue
när det är möjligt.
Initialiseringsprocess¶
Hur applikationer laddas¶
När Django startar ansvarar django.setup()
för att fylla på applikationsregistret.
- setup(set_prefix=True)[source]¶
Konfigurerar Django genom att:
Ladda inställningarna.
Sätta upp loggning.
Om
set_prefix
är True, ställs URL-resolverns skriptprefix in påFORCE_SCRIPT_NAME
om det är definierat, eller/
annars.Initialisering av programregistret.
Denna funktion anropas automatiskt:
När du kör en HTTP-server via Djangos ASGI- eller WSGI-stöd.
När du anropar ett managementkommando.
Den måste anropas explicit i andra fall, t.ex. i vanliga Python-skript.
Applikationsregistret initieras i tre steg. Vid varje steg bearbetar Django alla applikationer i ordningen INSTALLED_APPS
.
Först importerar Django varje objekt i
INSTALLED_APPS
.Om det är en applikationskonfigurationsklass importerar Django applikationens rotpaket, definierat av dess
name
-attribut. Om det är ett Python-paket letar Django efter en applikationskonfiguration i enapps.py
-undermodul, eller skapar en standardapplikationskonfiguration.I det här skedet ska din kod inte importera några modeller!
Med andra ord bör dina programs rotpaket och de moduler som definierar dina programkonfigurationsklasser inte importera några modeller, inte ens indirekt.
Strängt taget tillåter Django import av modeller när deras applikationskonfiguration har laddats. Men för att undvika onödiga begränsningar av ordningen på
INSTALLED_APPS
rekommenderas det starkt att inte importera några modeller i det här skedet.När detta steg har slutförts blir API:er som arbetar med applikationskonfigurationer, t.ex.
get_app_config()
, användbara.Sedan försöker Django importera undermodulen
models
för varje applikation, om det finns en sådan.Du måste definiera eller importera alla modeller i din applikations
models.py
ellermodels/__init__.py
. Annars kan det hända att programregistret inte är helt fyllt vid denna tidpunkt, vilket kan leda till att ORM inte fungerar som det ska.När detta steg har slutförts blir API:er som arbetar med modeller, t.ex.
get_model()
, användbara.Slutligen kör Django
ready()
-metoden för varje applikationskonfiguration.
Felsökning¶
Här följer några vanliga problem som du kan stöta på under initialiseringen:
AppRegistryNotReady
: Detta händer när import av en applikationskonfiguration eller en modellmodul utlöser kod som är beroende av appregistret.Till exempel: använder
gettext()
appregistret för att leta upp översättningskataloger i program. För att översätta vid importtillfället behöver du iställetgettext_lazy()
. (Att användagettext()
skulle vara en bugg, eftersom översättningen skulle ske vid importtillfället, snarare än vid varje förfrågan beroende på det aktiva språket)Om du kör databasfrågor med ORM vid importtillfället i modellmoduler kommer detta undantag också att utlösas. ORM kan inte fungera korrekt förrän alla modeller är tillgängliga.
Detta undantag inträffar också om du glömmer att anropa
django.setup()
i ett fristående Python-skript.ImportError: cannot import name ...
Detta händer om importsekvensen hamnar i en slinga.För att eliminera sådana problem bör du minimera beroendet mellan dina modellmoduler och göra så lite arbete som möjligt vid importtillfället. För att undvika att exekvera kod vid importtillfället kan du flytta den till en funktion och cacha dess resultat. Koden kommer att exekveras när du först behöver dess resultat. Det här konceptet kallas ”lazy evaluation”.
django.contrib.admin
utför automatiskt autodiscovery avadmin
-moduler i installerade applikationer. För att förhindra det, ändra dinINSTALLED_APPS
så att den innehåller'django.contrib.admin.apps.SimpleAdminConfig'
istället för'django.contrib.admin'
.RuntimeWarning: Accessing the database during app initialization is discouraged.
Denna varning utlöses för databasfrågor som körs innan appar är klara, t.ex. under modulimport eller i metodenAppConfig.ready()
. Sådana för tidiga databasfrågor avråds eftersom de kommer att köras under uppstarten av varje hanteringskommando, vilket kommer att sakta ner projektstarten, potentiellt cacha inaktuella data och kan till och med misslyckas om migreringar väntar.Ett vanligt misstag är t.ex. att göra en databasfråga för att fylla i formulärfältens val:
class LocationForm(forms.Form): country = forms.ChoiceField(choices=[c.name for c in Country.objects.all()])
I exemplet ovan körs frågan från
Country.objects.all()
under modulimporten, eftersomQuerySet
itereras över. För att undvika varningen kan formuläret använda enModelChoiceField
istället:class LocationForm(forms.Form): country = forms.ModelChoiceField(queryset=Country.objects.all())
För att göra det lättare att hitta koden som utlöste varningen kan du få Python behandla varningar som fel att visa stackspårningen, till exempel med
python -Werror manage.py shell
.