Django Шаблон: Динамическая переменная шаблона внутри другой переменной

Надеюсь, это имеет смысл... Я создаю страницу списка криптоактивов (легко); однако, в цикле {% for %} я хотел бы включить переменную внутри переменной. Если показать код, это будет иметь больше смысла:

Tempalte.html

{% for crypto_asset in objects__list_cryptoAssets %}
   <tr role="row" class="body-row">
      <td role="cell">{{ api_external_prices.bitcoin.usd }}</td>
   </tr>
{% endfor %}

Итак, цикл {% for %} захватывает все криптоактивы, а затем я могу использовать шаблон Django {{ asset_class.slug }} для захвата всех slug... ничего исключительного здесь нет. Эта переменная {{ api_external_prices.bitcoin.usd }} захватывает внешние долларовые цены на биткойн, {{ api_external_prices.bitcoin.eur }} цены в евро и так далее... здесь тоже нет ничего исключительного

Вот где возникает вопрос: идея состоит в том, чтобы иметь что-то вроде {{ api_external_prices.{{ asset_class.slug }}.usd }}... таким образом, каждая криптовалюта будет иметь свою собственную цену FX, полученную правильно. Возможно ли иметь переменную внутри переменной?

Есть несколько способов, которыми вы можете это реализовать:

Фильтры шаблона

Вы можете создать шаблонный фильтр api_external_prices, который принимает asset_class и тип криптовалюты в качестве параметров и возвращает значение.

Синтаксис будет выглядеть следующим образом, где api_external_prices - имя фильтра шаблонов:

{{ asset_class|api_external_prices:"usd" }}

Для получения дополнительной информации об этой функции смотрите здесь: https://docs.djangoproject.com/en/4.0/howto/custom-template-tags/#writing-custom-template-filters

Методы

Другим подходом было бы иметь api_external_prices в качестве метода на вашем объекте asset_class, который возвращает объект, имеющий свойство usd. api_external_prices здесь может быть просто оберткой, вызывающей центральный модуль/функцию, но это значительно упростит использование в шаблонах.

{{ asset_class.api_external_prices.usd }}

Первый подход похож на то, о чем вы спрашиваете, но лично я предпочел бы использовать второй подход, потому что он избавляет вас от внедрения фильтра шаблонов.

Надеюсь, это поможет вам понять, как реализовать метод 2 из вашего ответа выше.

Views.py

@login_required(login_url='xxx', redirect_field_name = '')
@require_http_methods(["GET", "POST"])
def view_cryptoAsset_list(request, *args, **kwargs):
    template_name = 'xxx'

    if request.user.is_authenticated and request.user.allow_private_access and request.user.is_superuser:
        if request.method == 'GET':
            context = {}
            objects__list_cryptoAssets = CryptoAsset.objects.all()
            objects__list_foreignExchange = ForeignExchange.objects.all()
            context = get_crypto_asset_list(objects__list_cryptoAssets, context)
            context = get_real_time_prices(objects__list_cryptoAssets, objects__list_foreignExchange, context)
            return render(request, template_name, context)
        else:
            return HttpResponseRedirect(reverse('page__error_404'))
    else:
        return HttpResponseRedirect(reverse('page__home'))

Utils.py

def get_crypto_asset_list(objects__list_cryptoAssets, context):
    if objects__list_cryptoAssets.count() > 0:
        extra_context = {   'xxx': xxx,
                            'xxx': xxx,
                            'xxx': xxx,
                            'xxx': xxx}
    else:
        extra_context = {   'xxx': xxx,
                            'xxx': xxx,
                            'xxx': xxx}
    context.update(extra_context)
    return context

def get_real_time_prices(objects__list_cryptoAssets, objects__list_foreignExchange, context):
    raw_crypto = objects__list_cryptoAssets.values('slug_name')
    dict_crypto = []
    for value in raw_crypto.values():
        raw_slugs = value.get('slug_name')
        dict_crypto.append(raw_slugs)
    stringCrypto = ",".join(dict_crypto)

    raw_foreign_exchange = objects__list_foreignExchange.values('slug')
    dict_fx = []
    for value in raw_foreign_exchange.values():
        raw_slugs = value.get('slug')
        dict_fx.append(raw_slugs)
    stringFX = ",".join(dict_fx)

    url = "xxx"
    response = urllib.request.urlopen(url)
    api_external_prices = json.loads(response.read())

    extra_context = {'api_external_prices': api_external_prices}
    context.update(extra_context)
    return context

В соответствии с просьбой я добавил весь код сюда.

Models.py

from django.db import models
from django.utils.text import slugify

class CryptoAsset(models.Model):
    is_active = models.BooleanField(default=True)
    name = models.CharField(max_length=128, blank=False)
    slug_name = models.SlugField(max_length=128, null=True, blank=True)
    ticker = models.CharField(max_length=8, blank=False, unique=True)
    slug_ticker = models.SlugField(max_length=16, null=True, blank=True)
    image = models.URLField(max_length=512, blank=False)
    scan_blockchain = models.URLField(max_length=512, blank=False)
    date_created = models.DateTimeField(auto_now_add=True)
    date_modified = models.DateTimeField(auto_now=True)
    
    def save(self, *args, **kwargs):
       self.slug_name = slugify(self.name)
       self.slug_ticker = slugify(self.ticker)
       self.ticker = self.ticker.upper()
       super(CryptoAsset, self).save(*args, **kwargs)

    class Meta:
        ordering = ['slug_name', 'slug_ticker']

class ForeignExchange(models.Model):
    is_active = models.BooleanField(default=True)
    name = models.CharField(max_length=128, blank=False)
    ticker = models.CharField(max_length=8, blank=False, unique=True)
    slug = models.SlugField(max_length=128, null=True, blank=True)

    def save(self, *args, **kwargs):
       self.ticker = self.ticker.upper()
       self.slug = slugify(self.ticker)
       super(ForeignExchange, self).save(*args, **kwargs)

    class Meta:
        ordering = ['slug']

Views.py

@login_required(login_url='xxx', redirect_field_name = '')
@require_http_methods(["GET", "POST"])
def view_cryptoAsset_list(request, *args, **kwargs):
    template_name = 'xxx'

    if request.user.is_authenticated and request.user.allow_private_access and request.user.is_superuser:
        if request.method == 'GET':
            context = {}
            objects__list_cryptoAssets = CryptoAsset.objects.all()
            objects__list_foreignExchange = ForeignExchange.objects.all()
            context = get_crypto_asset_list(objects__list_cryptoAssets, context)
            context = get_real_time_prices(objects__list_cryptoAssets, objects__list_foreignExchange, context)
            return render(request, template_name, context)
        else:
            return HttpResponseRedirect(reverse('page__error_404'))
    else:
        return HttpResponseRedirect(reverse('page__home'))

Utils.py

def get_crypto_asset_list(objects__list_cryptoAssets, context):
    if objects__list_cryptoAssets.count() > 0:
        extra_context = {   'total_crypto_assets': objects__list_cryptoAssets.count(),
                            'objects__list_cryptoAssets': objects__list_cryptoAssets,
                            'json_textGlobal': static_textGlobal,
                            'json_textLanguage': static_textLanguage}
    else:
        extra_context = {   'total_crypto_assets': 0,
                            'json_textGlobal': static_textGlobal,
                            'json_textLanguage': static_textLanguage}
    context.update(extra_context)
    return context

def get_real_time_prices(objects__list_cryptoAssets, objects__list_foreignExchange, context):
    raw_crypto = objects__list_cryptoAssets.values('slug_name')
    print(raw_crypto)
    dict_crypto = []
    for value in raw_crypto.values():
        raw_slugs = value.get('slug_name')
        dict_crypto.append(raw_slugs)
        print(dict_crypto)
    stringCrypto = ",".join(dict_crypto)
    print(stringCrypto)

    raw_foreign_exchange = objects__list_foreignExchange.values('slug')
    print(raw_foreign_exchange)
    dict_fx = []
    for value in raw_foreign_exchange.values():
        raw_slugs = value.get('slug')
        dict_fx.append(raw_slugs)
        print(dict_fx)
    stringFX = ",".join(dict_fx)
    print(stringFX)

    url = "https://api.xxxxxxx.com/api/price?ids="+ stringCrypto +"&vs_currencies="+ stringFX +""
    response = urllib.request.urlopen(url)
    api_external_prices = json.loads(response.read())
    print(api_external_prices)

    extra_context = {'api_external_prices': api_external_prices}
    context.update(extra_context)
    return context

Итак, из Utils.py upated, если мы поставим несколько prints() для bitcoin & ethereum и usd & eur, они генерируют следующее...

>>> print(raw_crypto) :: <QuerySet [{'slug_name': 'bitcoin'}, {'slug_name': 'ethereum'}]>
>>> print(dict_crypto) :: ['bitcoin', 'ethereum']
>>> print(stringCrypto) :: bitcoin,ethereum
>>> print(raw_foreign_exchange) :: <QuerySet [{'slug': 'eur'}, {'slug': 'usd'}]>
>>> print(dict_fx) :: ['eur', 'usd']
>>> print(stringFX) :: eur,usd
>>> print(api_external_prices) :: {'ethereum': {'eur': 1399.75, 'usd': 1472.54}, 'bitcoin': {'eur': 26240, 'usd': 27604}}

Tempalte.html

{% for crypto_asset in objects__list_cryptoAssets %}
   <tr role="row" class="body-row">
      <td role="cell">{{ api_external_prices.bitcoin.usd }}</td>
   </tr>
{% endfor %}

В шаблоне, если я сделаю {{ api_external_prices.bitcoin.usd }} я получу USD цену биткоина в долларах; однако, внутри цикла мне нужно, чтобы часть биткоина была динамической... поможет ли все это?

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