Wagtail добавляет функции в models.py

Я пытаюсь сделать пользовательскую plotly-графику на домашней странице wagtail. У меня получилось вот что. Я переопределяю модель wagtail Page-model, изменяя контекст, возвращаемый в шаблон. Правильно ли я делаю, возможно ли это в models.py ?

Thnx in advanced.

from django.db import models

from wagtail.models import Page
from wagtail.fields import RichTextField
from wagtail.admin.panels import FieldPanel

import psycopg2
from psycopg2 import sql
import pandas as pd
import plotly.graph_objs as go
from plotly.offline import plot

class CasPage(Page):
    body = RichTextField(blank=True)

    content_panels = Page.content_panels + [
        FieldPanel('body'),
    ]

    def get_connection(self):
        try:
            return psycopg2.connect(
                database="xxxx",
                user="xxxx",
                password="xxxx",
                host="xxxxxxxxxxxxx",
                port=xxxxx,
            )
        except:
            return False
    conn = get_connection()
    cursor = conn.cursor()

    strquery = (f'''SELECT t.datum, t.grwaarde - LAG(t.grwaarde,1) OVER (ORDER BY datum) AS 
      gebruiktgas
                FROM XXX
                     ''')

    data = pd.read_sql(strquery, conn)

    fig1 = go.Figure(
    data = data,
    layout=go.Layout(
        title="Gas-verbruik",
        yaxis_title="aantal M3")
        )

    output = plotly.plot(fig1, output_type='div', include_plotlyjs=False)

    # https://stackoverflow.com/questions/32626815/wagtail-views-extra-context
    def get_context(self, request):
        context = super(CasPage, self).get_context(request)
        context['output'] = output
        return context

Вроде бы правильный путь. Однако вам следует перенести весь код сюжета в свой собственный метод. В настоящее время код графика запускается при инициализации сайта, а затем остается в памяти.

Теперь есть три обычных способа получить сюжет на отрисованную страницу.

  1. Как вы делали с контекстом
  2. Как свойство или метод класса страницы
  3. Как тег шаблона, вызываемый из шаблона

Первые два метода имеют более или менее одинаковый эффект, за исключением того, что второй делает свойство доступным везде, а не только в шаблоне. Метод контекста выполняется до начала рендеринга страницы, а два других - во время этого процесса. Полагаю, единственное реальное различие заключается в том, что если вы используете кэширование шаблонов, контекст будет выполняться всегда при загрузке страницы, а два других метода выполняются только тогда, когда кэш недействителен, или если код выводится из кэша (для кэширования фрагментов).

Чтобы вызвать сюжет как свойство класса вашей страницы, вы просто вытащите код в def с декоратором @property:

class CasPage(Page):
    ....
    @property
    def plot(self):
        try:
            conn = psycopg2.connect(
                database="xxxx",
                user="xxxx",
                password="xxxx",
                host="xxxxxxxxxxxxx",
                port=xxxxx,
            )
            cursor = conn.cursor()
            strquery = (f'''SELECT t.datum, t.grwaarde - LAG(t.grwaarde,1) OVER (ORDER BY datum) AS 
                            gebruiktgas FROM XXX''')
            data = pd.read_sql(strquery, conn)

            fig1 = go.Figure(
                data = data,
                layout=go.Layout(
                    title="Gas-verbruik",
                    yaxis_title="aantal M3")
                )
            return plotly.plot(fig1, output_type='div', include_plotlyjs=False)        
            
        except Exception as e:
            print(f"{type(e).__name__} at line {e.__traceback__.tb_lineno} of {__file__}: {e}")       
            return None

^ Я не пробовал этот код... он должен работать как есть, но нет гарантий, что я не сделал опечатку ;)

Теперь вы можете получить доступ к вашему сюжету с помощью {{ self.plot }} в шаблоне.

Если вы хотите придерживаться контекста, тогда вы останетесь с def выше, но просто измените строку вывода на

context['output'] = self.plot

Теги шаблонов более полезны, когда они используются в StructBlocks, а не как часть класса страницы, как сейчас. Тогда вы перенесете весь этот сюжетный код в файл тегов шаблона, зарегистрируете его и вызовете в шаблоне с помощью {% plot %}. Теги шаблонов Wagtail работают так же, как и Django: https://docs.djangoproject.com/en/4.1/howto/custom-template-tags/

Находятся ли данные сюжета вне базы данных сайта? Если нет, то вы, вероятно, можете получить данные через ORM, если они определены как модель. Если да, то, вероятно, стоит написать представление (или хранимую процедуру, если вы хотите передавать параметры) на сервере базы данных и вызвать его, а не жестко кодировать SQL в вашем python.

Другим соображением является время загрузки страницы - если набор данных большой, это может занять некоторое время и помешать загрузке страницы. В этом случае вам, вероятно, понадобится внешнее решение.

Вернуться на верх