04 - Template Motoru

April 28, 2018 4 minute read

Eğer içeriği dinamik oluşturuyorsak, ortak sayfa bileşenlerini tekrar tekrar yazmak istemiyorsak, Template katmanını biraz daha yakından tanımamız gerekiyor.

Özet

  • Template katmanında layout kullanımına bir örnek göstereceğiz.
  • Örnek bir template tag ve filter yazmayı deneyeceğiz.
  • Admin panelimizde, göze hoş görünmesi için bir stil düzenlemesi yapacağız.
  • Bu yazıyla ilgili kodlara buradan erişebilirsiniz.

Layout Kullanımı

Template dosyaları yazmaya başladıkça bir şeyleri tekrar etmeye başlayacaksınız. Birçoğunun içinde head ve body var, bir çoğunda ortak stil dosyalarını kullanacaksınız, hatta hangi sayfa olursa olsun bazı meta tagları hiç değişmeyecek. Her Template dosyasında bunları tekrar tekrar yazmak zor ve anlamsız. Onun yerine, base.html adında bir layout oluşturup diğer Template dosyalarımızda bu layout’u kullanabiliriz. İşte biz bu tip işlevleri Django’nun arkasındaki Template motoru sayesinde yapabiliyoruz.

Django birden fazla Template motoru destekliyor. Varsayılan template motoru1, Jinja‘ya çok benziyor; fakat Jinja’nın tüm özelliklerini desteklemiyor. Ancak dilerseniz onu da tercih edebilirsiniz. Varsayılan Template motoru ile bir layout oluşturmayı deneyelim:

<!-- templates/base.html -->

<!doctype html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <!-- block'un içini varsayılan bir değerle doldurabilirsiniz. -->
        <!-- Örneğin burada varsayılan "Hello" -->
        <title>{% block title %}Hello{% endblock %}</title>
        <link rel="stylesheet" href="/static/main.css">
    </head>
    <body>
        {% block content %}{% endblock %}
    </body>
</html>

Basit bir layout örneği. İçinde iki block var ve bu block’lar sayesinde içeriği doldurabiliyoruz:

<!-- templates/new.html -->

{% extends 'base.html' %}<!-- Layout'u ilk satırda tanımlıyoruz. -->
<!-- extends ilk satır olmak zorunda. -->

<!-- title block'unun varsayılanını çağırmak için block.super kullanabilirsiniz. -->
{% block title %}{{ block.super }} - New{% endblock %}

{% block content %}
    <form action="" method="POST" enctype="multipart/form-data">
        ...
{% endblock %}

Yardımcı Fonksiyonlar

Biz View katmanında, kullanıcılara göstermek istediğimiz içerik verisini hazırlayıp sonra Template katmanı içinde kullanıyoruz. İçerik verisini hazırlarken değer hesaplama, veritabanından veri alma gibi birtakım işlemler gerçekleştiriyoruz. Fakat bazen bu işlemler bir sayfayı ilgilendiren bir işlem değil de, tüm sayfalarda gerektiğinde kullanabileceğimiz bir işlem olabiliyor. Eğer bu işlem, doğrudan Template katmanını ilgilendiren bir işlemse biz burada Template Tag veya Template Filter gibi yöntemleri kullanmayı tercih ediyoruz. Örneğin {% csrf_token %}.

Hatırlarsanız Palette uygulamamızda yeni resim yüklemek için hazırladığımız formda bu Template Tag’i kullanmıştık. Başında ve sonunda {% ve %} olması onun bir Template Tag olduğunu gösterir. Aslında if, for, with gibi temel programlama dili anahtar kelimeleri de Template katmanında bir Tag olarak isimlendirilebilir. Ancak eğer {{ color|default_if_none:"#fff" }} şeklinde bir kullanım görürseniz, burada default_if_none adında bir Template Filter kullanıldığını anlayabilirsiniz. Filter’in temel işlevi değişkenin kendisini modifiye etmek. Yani burada color değişkeni yoksa #fff değerini elde ederiz.

Django’yla birlikte kullanışlı birçok Template Tag ve Filter geliyor. Fakat bazen özel ihtiyaçlar üçüncü parti bir Django eklentisi kullanmak gerekebiliyor veya kendimiz bu ihtiyacı gideren basit bir Template Tag veya Filter yazmak isteyebiliriz.

Palette uygulamamıza dönelim ve renkleri kutu kutu göstermeyi deneyelim. Önce main.css dosyamıza basit bir stil ekleyelim:

/* static/main.css */

.colors {
  margin: 25px 0;
}

.colors .color-item { /* renk kutuları */
  display: inline-block;
  width: 50px;
  height: 50px;
  border: 2px solid #eee;
  background-color: #555;
  margin-right: 20px;
}

Sonra detail.html dosyasında renk kutuları göstermeye çalışalım:

<!-- templates/palette/detail.html -->

...
<div class="colors">
    {% for color in palette.colors %}
        <span class="color-item" style="background-color: {{ color }};" title="{{ color }}"></span>
    {% endfor %}
</div>
...

Bir sorunumuz var. palette.colors field’imizin veri tipi liste değil. O sadece virgülle ayrılmış renk kodlarını içeren string. Bizim string’i list’e çevirecek bir filtreye ihtiyacımız var. Burada hemen ilk filtremizi yazmaya başlayabiliriz. hello_palette uygulamasının içinde templatetags dizini oluşturup içinde __init__.py2 ve palette_tags.py adında iki dosya oluşturalım ve ilk filtremizi yazalım:

# hello_palette/templatetags/palette_tags.py

from django import template

register = template.Library()


@register.filter
def as_list(value):
  return value.split(',')

Bu sayede renk listesini şu şekilde elde edebiliriz:

<!-- templates/palette/detail.html -->

...
    {% for color in palette.colors|as_list %}
    ...

Şimdi bir soru. Bu renk listesine sadece Template katmanında mı ihtiyaç duyacağız? Yani bir Template Filter fonksiyonunu Template katmanı dışında bir yerde kullanmak istesek ne kadar hoş olurdu? İleriye dönük düşünürsek bunu Model katmanında da çözebilirdik:

# hello_palette/models.py

class Palette(models.Model):
    ...

    @property
    def colors_as_list(self):
        return self.colors.split(',')

Böylece Template katmanında şu şekilde kullanabilirdik:

<!-- templates/palette/detail.html -->

...
    {% for color in palette.colors_as_list %}
    ...

Color boxes

Admin Panelinde Stil Düzenlemesi

Admin panelinde de renk kodlarını güzel göstermek için SVG ile basit bir stil denemesi yapsak nasıl olur? Bunun için ilgili Admin class’ında özel bir column fonksiyonu yazmamız gerekiyor:

# hello_palette/admin.py

...
from django.utils.html import format_html
...


@admin.register(Palette)
class PaletteAdmin(admin.ModelAdmin):
    list_display = ('__str__', 'get_colors', 'created_at', 'is_deleted')  # colors'u sildik, fonskyionun adını yazdık.
    ...

    def get_colors(self, obj):
        # buradaki obj aslında bir Palette instance'i. Böylece renk kodlarımıza erişebileceğiz.
        # models.py'deki colors_as_list metodumuzu burada da kullanabiliyoruz.
        # format_html, HTML tag'lerini HTML dosyasında doğru şekilde çevirebilmek için gerekli.
        circle_template = '<svg width=16 height=16><circle cx=8 cy=8 r=5 style="fill: {};"></circle></svg>'
        return format_html(''.join(circle_template.format(c) for c in obj.colors_as_list))

    get_colors.short_description = "Colors"  # Column için isim veriyoruz.
    get_colors.allow_tags = True  # HTML tag'i kullanımına izin veriyoruz.

Admin color circles

Şimdi biraz daha göze hoş geliyor, değil mi? Böylece basit bir uygulamamızı tamamlamış olduk. Bundan sonra farklı uygulamalarla sizi Django’nun farklı güzellikleri konusunda bilgilendirmek istiyorum. Kısa zamanda tekrar görüşmek üzere.


  1. Buradan Template diline hızlı başlangıç yapabilirsiniz. [return]
  2. Bir dizinin Python paketi olduğunu anlatabilmemiz için __init__.py dosyasına ihtiyacımız var. [return]