Интеграция пользовательской функции в Django
Я хотел бы получить доступ и распечатать метаданные (атрибуты и значения), обслуживаемые сервером ERDDAP, который является разновидностью OPeNDAP, на моем Django-сайте.
поэтому я подготовил простой пример функции под названием get_conventions для доступа к полю метаданных на этом публичном сервере, где хранятся данные и метаданные. Чтобы начать работу, я установил необходимые пакеты:
$ pip install pandas erddapy
и затем,
import pandas as pd
from erddapy import ERDDAP
def get_conventions(dataset_id):
e = ERDDAP(server='https://gliders.ioos.us/erddap/', protocol='tabledap', response='csv')
url = e.get_info_url(dataset_id, response='csv')
df = pd.read_csv(url)
# this replace spaces with underscores in column names
df.columns = [col_name.replace(' ', '_') for col_name in df.columns]
conventions = df[df.Attribute_Name == 'Conventions'].Value
return conventions
Используя интерпретатор Python, можно вызвать функцию следующим образом, указав в качестве аргумента id набора данных (amelia-20180501T0000), который находится на сервере ; вывод будет следующим:
>>> get_conventions('amelia-20180501T0000')
6 Unidata Dataset Discovery v1.0, COARDS, CF-1.6
Name: Value, dtype: object
>>>
Я хотел бы, чтобы мой сайт выводил на веб-страницу вывод вышеуказанной функции.
Я могу вывести строку аргумента на странице (model.py, views.py и соответствующие html-шаблоны - они похожи на Django tutorial), но я не знаю, как передать аргумент функции (и ожидать возврата) или как/где интегрировать функцию в структуру Django.
Аргумент хранится в локальной базе данных, к которой можно обратиться с помощью models/views/template
Но я не уверен, как интегрировать часть, включающую функцию в Django?
Подход будет зависеть от того, будет ли функция использоваться кросс-ап, в одном приложении или привязана к модели Django.
Для кросс-прикладных функций я обычно создаю отдельное приложение под названием core или utils с файлами python для каждого набора функций. Для примера назовем его erddapy.py. В views.py, в котором находится ваше представление, просто from utils.erddapy import get_conventions и вызовите его в своем представлении, передав аргумент. Затем верните результат как контекст шаблону.
Если он используется только в одном приложении, но не привязан к модели, вы также можете создать файл utils.py в этом приложении и вместо этого сделать from .utils import get_conventions в вашем views.py, а затем вызвать его в вашем представлении.
Если вы определили модель для наборов данных и храните там id набора данных, то, вероятно, лучше использовать метод модели. Таким образом, вы сможете использовать API queryset в представлении для получения экземпляра, а затем просто вызвать instance.get_conventions(). Для такого подхода аргумент не нужен, поскольку вы можете просто получить id набора данных из self.dataset_id в логике метода.
# view
id = self.kwargs.get('id')
if id:
instance = get_object_or_404(MyModel, id=id)
data = instance.get_conventions()
# return the data as context in an http response
# model method
class MyModel(models.Model):
# model fields
def get_conventions(self):
dataset_id = self.dataset_id
# get the data
Полагаю, основной вопрос заключается в том, как вы храните или получаете идентификатор набора данных? Если он находится в отдельной локальной базе данных, вам может потребоваться запросить его, чтобы получить идентификатор набора данных, что я бы сделал в отдельной функции. Затем либо передать его в функцию как аргумент, либо хранить его в вашей Django db как экземпляр модели и использовать метод, описанный выше.
Я смог заставить это работать после прочтения этой статьи Д. Пателя.
Для этого нужно было добавить следующее в файл с именем services.py, который был помещен в подпапку приложения под названием templatetags. Именно здесь находится пользовательская функция get_conventions:
from django import template
...
register = template.Library()
@register.filter
def get_conventions(dataset_id):
...
return conventions
и в шаблоне, я должен был загрузить файл services и добавить следующее в html-шаблон:
{% load services %}
{% block content %}
<p><strong>Conventions:</strong> {{ station.dataset_id | get_conventions }}</p>
...
{% endblock %}
station.dataset_id - аргумент для функции get_conventions в паре | с возвращаемым значением
и все сработало, как было задумано. Это было довольно просто.