やりたいこと
Djangoテンプレート機能のカスタムフィルタで任意のクエリを発行し、その実行結果をテンプレートで表示すること
前提条件
- Django 2.0
- python 3.6
アプリ構成
manage.py
polls/
__init__.py
models.py
templatetags/
__init__.py
poll_extras.py
templates/
index.html
実現方法
manage.py
#!/usr/bin/env python
import os
import django
from django.shortcuts import render_to_response
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "sample.settings")
django.setup()
# テンプレートに渡すキーを取得
from polls.models import Child
childs = Child.objects.raw('SELECT id, name FROM child where id = 1')
child = childs[0]
# テンプレートを発行
app_data = {'child': child}
print(render_to_response(template_name='/sample/templates/index.html', context=app_data))
polls/model.py
from django.db import models
class Child(models.Model):
class Meta:
db_table = 'child'
polls/templatetags/poll_extras.py
from django import template
from polls.models import Child
register = template.Library()
@register.filter
def fetch_object(sql):
# childテーブル限定だがここも可変にしたい
records = Child.objects.raw(sql)
return records
templates/index.html
{% load poll_extras %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!-- 描画元から渡されキーを元にクエリを作成し、childオブジェクトを取得 -->
{{% with 'select id, name from child where id = '|add:child.id as sql %}
name: {% with sql|fetch_object as objects %}
<!-- childオブジェクトのプロパティを描画 -->
{% for object in objects %}
{{ object.name}}, id: {{ object.id }}
{% endfor %}
{% endwith %}
{% endwith %}
</body>
</html>
発行されたhtml
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
name:Child1, id: 1
</body>
</html>
データ構造
childテーブル定義
Table: child
Create Table: CREATE TABLE `child` (
`id` varchar(20) NOT NULL,
`name` varchar(20) DEFAULT NULL,
`parent_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
childテーブルレコード
+----+--------+-----------+
| id | name | parent_id |
+----+--------+-----------+
| 1 | Child1 | 1 |
| 2 | Child2 | 1 |
| 3 | Child3 | 1 |
| 4 | Child4 | 2 |
| 5 | Child5 | 2 |
| 6 | Child6 | 2 |
| 7 | Child7 | 3 |
| 8 | Child8 | 3 |
| 9 | Child9 | 3 |
+----+--------+-----------+
ハマったところ
-
QuerySet API
でraw
を使用する場合は必ずPKを取得しないといけない - 上記制約から
raw
以外のAPI使用が良い - デフォルトフィルタの
add
は文字列と数値の足し算はできないため、その場合は空文字を返す - Django、python自体(入門者なのでエラー発生の切り分けがむずい)