Přejít k navigační liště

Zdroják » Různé » Django: Rozšiřování možností Djanga

Django: Rozšiřování možností Djanga

Články Různé

Holá instalace Djanga má mnoho různých funkcí. Určitě však časem zjistíme, že nám nějaká maličkost chybí. Proto se v tomto díle podíváme na několik ukázek možného rozšíření.

Přidání vlastního filtru do šablony

Určitě si vzpomínáte na šestý díl seriálu, kde jsme se učili prezentovat data pomocí generických pohledů. V příkladu jsme si vypsali mimo jiné e-mailovou adresu provozovny. Tyto adresy nejsou nijak chráněné, takže je může zaznamenat i ten nejhloupější spambot, což představuje problém. Proto si napíšeme jednoduchý filtr, pomocí kterého e-mailovou adresu transformujeme do zakódovaného řetězce v JavaScriptu.

Filtr je vlastně obyčejná funkce, které předáme nějaký vstup a ona vrátí odpovídající výstup. Každá aplikace, která je uvedená v konstantě INSTALLED_APPS v souboru settings.py, může mít svou sadu filtrů a značek. Stačí v adresáři aplikace (v našem případě video_store) vytvořit podadresář templatetags a umístit do něj dva soubory. První je potřeba pojmenovat __init__.py a bude stačit, když bude prázdný. Označuje totiž, že daný adresář obsahuje modul napsaný v Pythonu. Druhý soubor můžeme pojmenovat libovolně, já si zvolil název misc.py, protože do tohoto souboru potom možná časem přidám další různorodé funkce (anglicky miscellaneous). Obsah souboru vypadá takto:

# coding: utf-8
from base64 import b64encode
from django import template
from django.utils.safestring import mark_safe
from django.template.defaultfilters import stringfilter

register = template.Library()

@register.filter
@stringfilter
def email(value):
    return mark_safe('<script type="text/javascript">display_email("%s");</script><noscript>(e-mail je chráněn JavaScriptem)</noscript>' % b64encode(value))

Na sedmém řádku se nachází přiřazení, které určuje, že se jedná o knihovnu filtrů a značek. Proměnná se musí jmenovat register a musí obsahovat objekt template.Library — takto to stanovuje konvence. Na devátém a desátém řádku můžeme vidět dva dekorátory. První z nich (@register.filter) registruje nový filtr. Kdybychom chtěli přidat novou značku, napíšeme místo toho @register.tag. Tento dekorátor má nepovinný parametr name, jež určuje název nového filtru či značky. My jsme ho vynechali, takže se název filtru odvodí z názvu funkce. Druhý dekorátor dbá na to, aby funkce dostala jako vstup řetězec. V případě, kdy by filtr byl připojen např. k číslu, by při zpracování šablony došlo k vyhození výjimky AttributeError. Tento dekorátor také převádí objekty na řetězce voláním metod __str__ nebo __unicode__.

Samotný filtr vezme hodnotu a vrátí HTML kód s JavaScriptem. Funkce mark_safe označí řetězec za bezpečný. Nedojde tak k automatickému escapování HTML značek a entit, takže se kupříkladu místo kódu &lt;noscript&gt; vypíše očekávaná hodnota <noscript>. Tuto vlastnost vypínejte s rozmyslem, hlavně při vypisování uživatelem zadaných dat. Pokud byste chtěli ošetřit uživatelem zadaná data sami, můžete k tomuto účelu použít funkci escape z modulu django.utils.html. V našem případě zaručíme bezpečnost vstupu tím, že ho zakódujeme pomocí kódování base64, které obsahuje pouze písmena abecedy, číslice a znaky plus, lomítko a rovnítko (viz RFC 3548). Takto zakódovaný e-mail spambot rozezná těžko.

Dále nesmíme zapomenout upravit šablonu s výpisem poboček (templates/stores.html):

{% extends "base.html" %}
{% load misc %}

{% block content %}
<h1>{% block title %}Provozovny{% endblock %}</h1>

{% for object in object_list %}
  <h2>{{ object.store }}</h2>

  <ul class="store">
  <li>{{ object.address }}</li>
  <li>{{ object.city }}</li>
  <li>{{ object.postal_code }}</li>
  {% if object.email %}
    <li>{{ object.email|email }}</li>
  {% endif %}
  </ul>

  {% if object.description %}
    <p>{{ object.description }}</p>
  {% endif %}
{% endfor %}
{% endblock %}

V tomto souboru přibyla na druhém řádku značka pro načtení našeho modulu s filtrem misc.py. Na patnáctém řádku se e-mail nevypisuje přímo, ale přes filtr email což zatím nebude fungovat, protože nemáme definovanou javascriptovou funkci display_email. Přesto se ale můžeme podívat na to, co uvidí uživatelé s vypnutým JavaScriptem.

Django 12

Založíme si tedy někde v adresáři static javascriptový soubor, který poté načteme přes značku &lt;script&gt; v šabloně templates/base.html. Tento soubor bude obsahovat již zmiňovanou funkci pro výpis e-mailu:

function display_email(str) {
    email = b64decode(str);

    document.write('<a href="mailto:' + encodeURI(email) + '">' + email + '</a>');
}

Na druhém řádku se volá funkce b64decode pro převedení zakódovaného řetězce do původní podoby. Ta v JavaScriptu není standardně implementována, takže jsem ji si musel napsat sám. Protože je však celkem rozsáhlá a pro další vysvětlování není potřeba, případní zájemci se na ni mohou podívat v přiloženém ukázkovém příkladu (soubor static/js/scripts.js). Co se týče čtvrtého řádku této funkce, ten zobrazí uživateli klikatelný e-mail.

Django 12

Přidání proměnné do kontextu

Opět navážeme na poznámku ze šestého dílu seriálu, kde jsme se zmínili o kontextových procesorech. Díky nim můžeme v šablonách používat společné proměnné (což je např. {{ MEDIA_URL }} nebo {{ user }}), stačí vždy při volání metody render_to_response uvést parametr context_instance=RequestContext(request). Konstanta TEMPLATE_CONTEXT_PROCESSORS určuje, které kontextové procesory se v projektu použijí. V dokumentaci Djanga je popsáno několik základních procesorů, my si napíšeme vlastní.

Zadavatel našeho projektu dostal šílený nápad, že by se v hlavičce webu měla zobrazovat náhodně některá z předem připravených marketingových hlášek. Protože se tato funkce týká všech pohledů, při implementaci přímo v pohledech, by došlo k zbytečnému duplikování kódu. K tomuto účelu je lepší vybranou hlášku předat šabloně jako globální kontext. Náhodné vypisování by se to sice dalo vyřešit jednoduchým kódem v JavaScriptu, ale myslím, že skriptování v prohlížeči už dnes bylo dost.

Soubor s funkcí, která přidává další kontext, si můžeme založit kdekoliv. Například přímo v adresáři projektu. Pojmenujeme ho jako context_processors.py:

# coding: utf-8

from random import choice

def nonsense(request):
    quotes = [
        'Jsme nejlepší!',
        'Naše tituly do vašeho přehrávače.',
        'Dobrý den je, když si pustíte film.',
        'Je přece správné platit za půjčování.',
        'Tohle u konkurence nenajdete.',
    ]

    return {'NONSENSE': choice(quotes)}

Funkce pro přidání kontextu požaduje jako parametr objekt Request a vrací slovník s deklaracemi proměnných. Bývá zvykem proměnné z kontextového procesoru zapisovat verzálkami, aby se odlišily od těch z pohledů. V naší funkci náhodně vybíráme jeden z blábolů, ke kterému poté budeme mít možnost přistupovat pomocí proměnné {{ NONSENSE }}.

Tento kontextový procesor je potřeba přidat do nastavení. Otevřeme si tedy soubor settings.py a dopíšeme do něj následující řádky:

TEMPLATE_CONTEXT_PROCESSORS = (
    'django.core.context_processors.auth',
    'django.core.context_processors.debug',
    'django.core.context_processors.i18n',
    'django.core.context_processors.media',
    'hrajeme_si.context_processors.nonsense',
)

První čtyři procesory jsou výchozí, ten poslední je náš. Teď už stačí jenom upravit v hlavní šabloně templates/base.html horní část webu:

<div id="header">
Videopůjčovny s. r. o.
{% if NONSENSE %}
  <div id="nonsense">{{ NONSENSE }}</div>
{% endif %}
</div>

Django 12

Související odkazy

Příště se podíváme na tvorbu vícejazyčných webů.

Komentáře

Subscribe
Upozornit na
guest
0 Komentářů
Inline Feedbacks
View all comments

Enum a statická analýza kódu

Mám jednu univerzální radu pro začínající programátorty. V učení sice neexistují rychlé zkratky, ovšem tuhle radu můžete snadno začít používat a zrychlit tak tempo učení. Tou tajemnou ingrediencí je statická analýza kódu. Ukážeme si to na příkladu enum.