Python >> Python opplæring >  >> Python

Få malnavn i maltag (Django)

Ser på kilden, mens Template objektet vil ha tilgang til malnavnet (via .name ) denne verdien sendes aldri videre til Parser-objektet og derfor ikke tilgjengelig for mal-tagger.

Det er forskjellige måter å gjøre malnavnet tilgjengelig for selve malen (ved å legge det til konteksten), men ikke innenfor malkodene.

Som Daniel Roseman nevnte i kommentarene, hvis du kan utdype hva du faktisk prøver å oppnå, kan det være en bedre måte å oppnå det du ønsker. Ingen fornærmelse, men dette høres ut som det kan være et XY-problem.

Av akademisk interesse hadde jeg en kjapp fele for å se om det var mulig. Så vidt jeg kan se, er det mulig, men ikke uten å endre eller ape lappe django-kilden.

Merk:følgende er ikke en anbefalt løsning og bare hint om hva som kan kreves for å faktisk få dette til å fungere. Skal ikke brukes til produksjonskode.

Ved å endre django.template.base.py med følgende endringer legger vi til .template_name attributt til parserobjektet som gjør det tilgjengelig for malkoder.

  1. Lagt til valgfri arg til compile_string
  2. Lagt til malnavn som ekstra attributt til parser
  3. Satt inn malnavnet når du ringte compile_string()

For å teste dette, definerte jeg følgende tag som ganske enkelt returnerer malnavnet med store bokstaver:

from django.template.base import Node, Library
register = Library()

class TemplateNameNode(Node):
    def __init__(self, template_name):
        self.name = template_name

    def render(self, context):
        return self.name.upper()

@register.tag
def caps_template_name(parser, token):
     return TemplateNameNode(parser.template_name)

og følgende mal:

{% load mytags %}
Template name in caps: {% caps_template_name %}

Dette ser ut til å fungere når det er testet i ./manage.py shell :

>>> from django.template import loader, Context
>>> t = loader.get_template("test.html")
>>> t.render(Context({}))
u'\nTemplate name in caps: TEST.HTML\n'

Selv om dette ser ut til å fungere, bør jeg gjenta at manuelt oppdatering av django-kilden aldri en god løsning og er utsatt for all slags elendighet når man migrerer til forskjellige versjoner.


Du kan kanskje gjøre dette med en kontekstprosessor, men jeg er ikke sikker på om disse har tilgang til navnet på malen.

Det som vil fungere er å lage en innpakning for gjengivelsesanropene du gjør. Si at du for øyeblikket gjør følgende:

from django.shortcuts import render
def index(request):
    return render(request, 'app/index.html', { 'foo': 'bar', })

Hvis du lager din egen wrapper for dette, kan du legge til malnavnet i ordboken før selve gjengivelsen finner sted:

from django.shortcuts import render
def myrender(request, template, dictionary):
    dictionary.update({'template_name': template})
    return render(request, template, dictionary)

Deretter endrer du det som følger i visningene dine (forutsatt at du lagret funksjonen ovenfor i myutils.py , og den er tilgjengelig på banen din):

#from django.shortcuts import render <- delete this line
from myutils import myrender as render
def index(request):
    return render(request, 'app/index.html', { 'foo': 'bar', })

Nå alle dine render samtaler vil oppdatere ordboken med malnavnet. I hvilken som helst mal bruker du bare {{ template_name }} for å få navnet. Du kan selvfølgelig også oppdatere andre gjengivelsesfunksjoner som render_to_response og slikt på lignende måte.

Også import myrender as render kanskje eller kanskje ikke forvirre deg senere fordi den heter som Django-funksjonen ... hvis ja, bare importer den uten "as render ", og erstatte alle render anrop med myrender . Personlig foretrekker jeg dette siden dette gjør det til en drop-in-erstatning for de eksisterende gjengivelsesfunksjonene.