Do tohoto článku si s dovolením odložím několik drobných ale užitečných funkcí Djanga.
defaults
parametr metody get_or_create
Metoda get_or_create
na manageru modelů je známá a používaná — pokud get(**params)
query vyhodí DoesNotExist
, Django uloží do databáze nový objekt. Až doposud jsem však neznal a nepoužíval volitelný argument defaults
. Pokud jej předáte, Django nepoužije tato data pro dotaz do databáze (SELECT
), ale jen pro vytvoření nové instance (INSERT
, tj. pokud nebyl záznam v databázi nalezen).
Typický use case může být například: u nějakého objektu chcete ukládat informaci o jeho vytvoření. V následující ukázce se Django nejprve pokusí získat existující objekt podle dvou atributů user
a foo
, a pokud se mu to nepodaří, založí nový objekt s vyplněným atributem datetime_created
.
Tip: timezone.now
(bez ()
) není chyba. get_or_create
přijímá i callable
, které zavolá v ten správný okamžik.
from django.utils import timezone
my_model_obj, created = MyModel.objects.get_or_create(
user=request.user,
foo=bar,
defaults={'datetime_created': timezone.now}
)
Redirect na detail objektu
Nepsaným (volitelným) pravidlem je definovat metodu get_absolute_url
na modelu.
from django.core.urlresolvers import reverse
from django.db import models
class MyModel(models.Model):
# ...
def get_absolute_url(self) -> str:
return reverse('my_app:my_model_detail', args=(self.id,))
Django tuto metodu zná a například funkce redirect
ji umí sama zavolat a přesměrovat požadavek na detail patřičného objektu.
Ukázka v praxi:
from django.views.generic import View
from django.http import HttpRequest, HttpResponseRedirect
from django.http import HttpRequest
from django.shortcuts import redirect
class MyView(View):
# ...
def post(self, request: HttpRequest, *args, **kwargs) -> HttpResponseRedirect:
obj = MyModel.objects.get(pk=42)
# ...
# ...
return redirect(obj) # No need to use reverse(view_name:...)
get_object_or_404
a vlastní queryset
Další běžně známá je funkce get_object_or_404
. Užitečné na ní je, že kromě třídy modelu přijímá i queryset. Můžete tak snadno omezit množinu dat, ve kterých Django hledá daný objekt před vyhozením 404
.
# Get only PUBLISHED objects
my_obj = get_object_or_404(MyModel.objects.filter(is_published=True), pk=42)
Context v šabloně
Vyrenderovaná Django šablona pomocí CBV (Class Based Views) dostává defaultně proměnnou view
ve svém kontextu. Tato proměnná — jak napovídá název — obsahuje instanci view. Tuto funkcionalitu má na starost django.views.generic.base.ContextMixin
, od kterého dědí většina tříd z CBV.
Tuto vlastnost je možné využít k volání metod z šablony — avšak jen takových, které nepřijímají žádné parametry.
view.py
:
from django.views.generic import TemplateView
class IndexTemplateView(TemplateView):
template_name = "foo/some_page.html"
def get_world(self):
return "world"
foo/some_page.html
:
<h1>Hello {{ view.get_world }}</h1>
Obecně však takovýto přístup nemohu doporučit. Volat view metodu z šablony není dobrá praxe — Django šablony by měly zůstat ideálně velmi hloupé. Více o tomto tématu na Reinout van Rees: No need to use get_context_data, use {{ view.some_method }}
.