jsondjangodjango-viewsdjango-templates

Use JSON data in Django fields


Problem applying values from JSON config in HTML file using Django.

Template error:
In template C:\Users\at\pp\project\check\templates\check_list.html, error at line 52
   Could not parse the remainder: '=check_status.get_status_by_id(check.status)' from 'status=check_status.get_status_by_id(check.status)'
   42 :                 {% block content %}
   43 :                 {% for check in checks %}
   44 :                 
   45 :                     
   46 :                     
<!-- Some data from check model -->
   48 :                     
   49 :                     
   50 :                     
   51 :                         <span class="check-status">
   52 :                              {{ status=check_status_config.get_status_by_id(check.status) }} 
   53 :                             {% with status %}
   54 :                                 {% if status %}
   55 :                                     <div class="check-status-svg" title="{{ check_status_config.items|get_item:check.status.id.title }}">
   56 :                                         {{ status.svg|safe }}
   57 :                                     </div>
   58 :                                 {% else %}
   59 :                                     Not found
   60 :                                 {% endif %}
   61 :                             {% endwith %}
   62 :                         </span>

config.py This describes the basic functionality of the child classes of configs.

import json


class Config:
    def __init__(self):
        self.config = None
        self.config_file = "conf/"

    def get_element_by_id(self, element_id):
        for element in self.config.get("items", []):
            if element.get("id") == element_id:
                return element
        return None

    def load_config(self):
        try:
            with open(self.config_file, "r", encoding='utf-8') as f:
                self.config = json.load(f)
            print(f"'{self.config_file}' +")
        except FileNotFoundError:
            print(f"'{self.config_file}' ***")
            self.create_default_config()

    def get_config(self):
        return self.config

    def create_default_config(self):
        self.config = self.default_config
        with open(self.config_file, "w", encoding='utf-8') as f:
            json.dump(self.config, f, indent=4)

check_status.py This describes the functionality of a specific class that creates and uses a JSON file. The created config was not edited separately.

from utils.config import Config


class CheckStatus(Config):
    def __init__(self, config_file="check_status.json"):
        super().__init__()
        self.config_file += config_file
        self.default_config = {
            "items": [
                {
                    "id": 0,
                    "title": "New",
                    "svg": '<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M13 3H8.2C7.0799 3 6.51984 3 6.09202 3.21799C5.71569 3.40973 5.40973 3.71569 5.21799 4.09202C5 4.51984 5 5.0799 5 6.2V17.8C5 18.9201 5 19.4802 5.21799 19.908C5.40973 20.2843 5.71569 20.5903 6.09202 20.782C6.51984 21 7.0799 21 8.2 21H12M13 3L19 9M13 3V7.4C13 7.96005 13 8.24008 13.109 8.45399C13.2049 8.64215 13.3578 8.79513 13.546 8.89101C13.7599 9 14.0399 9 14.6 9H19M19 9V12M17 19H21M19 17V21" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>'
                },
                {
                    "id": 1,
                    "title": "In work",
                    "svg": '<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M13 3H8.2C7.0799 3 6.51984 3 6.09202 3.21799C5.71569 3.40973 5.40973 3.71569 5.21799 4.09202C5 4.51984 5 5.0799 5 6.2V17.8C5 18.9201 5 19.4802 5.21799 19.908C5.40973 20.2843 5.71569 20.5903 6.09202 20.782C6.51984 21 7.0799 21 8.2 21H10M13 3L19 9M13 3V7.4C13 7.96005 13 8.24008 13.109 8.45399C13.2049 8.64215 13.3578 8.79513 13.546 8.89101C13.7599 9 14.0399 9 14.6 9H19M19 9V10M14 21L16.025 20.595C16.2015 20.5597 16.2898 20.542 16.3721 20.5097C16.4452 20.4811 16.5147 20.4439 16.579 20.399C16.6516 20.3484 16.7152 20.2848 16.8426 20.1574L21 16C21.5523 15.4477 21.5523 14.5523 21 14C20.4477 13.4477 19.5523 13.4477 19 14L14.8426 18.1574C14.7152 18.2848 14.6516 18.3484 14.601 18.421C14.5561 18.4853 14.5189 18.5548 14.4903 18.6279C14.458 18.7102 14.4403 18.7985 14.405 18.975L14 21Z" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>'
                },
                {
                    "id": 2,
                    "title": "In check",
                    "svg": '<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M13 3H8.2C7.0799 3 6.51984 3 6.09202 3.21799C5.71569 3.40973 5.40973 3.71569 5.21799 4.09202C5 4.51984 5 5.0799 5 6.2V17.8C5 18.9201 5 19.4802 5.21799 19.908C5.40973 20.2843 5.71569 20.5903 6.09202 20.782C6.51984 21 7.0799 21 8.2 21H12M13 3L19 9M13 3V7.4C13 7.96005 13 8.24008 13.109 8.45399C13.2049 8.64215 13.3578 8.79513 13.546 8.89101C13.7599 9 14.0399 9 14.6 9H19M19 9V11M19.2686 19.2686L21 21M20 17.5C20 18.8807 18.8807 20 17.5 20C16.1193 20 15 18.8807 15 17.5C15 16.1193 16.1193 15 17.5 15C18.8807 15 20 16.1193 20 17.5Z" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>'
                },
                {
                    "id": 3,
                    "title": "Rejected",
                    "svg": '<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M17 17L21 21M21 17L17 21M13 3H8.2C7.0799 3 6.51984 3 6.09202 3.21799C5.71569 3.40973 5.40973 3.71569 5.21799 4.09202C5 4.51984 5 5.0799 5 6.2V17.8C5 18.9201 5 19.4802 5.21799 19.908C5.40973 20.2843 5.71569 20.5903 6.09202 20.782C6.51984 21 7.0799 21 8.2 21H13M13 3L19 9M13 3V7.4C13 7.96005 13 8.24008 13.109 8.45399C13.2049 8.64215 13.3578 8.79513 13.546 8.89101C13.7599 9 14.0399 9 14.6 9H19M19 9V14" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>'
                },
                {
                    "id": 4,
                    "title": "Confirmed",
                    "svg": '<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M15 19L17 21L21 17M13 3H8.2C7.0799 3 6.51984 3 6.09202 3.21799C5.71569 3.40973 5.40973 3.71569 5.21799 4.09202C5 4.51984 5 5.0799 5 6.2V17.8C5 18.9201 5 19.4802 5.21799 19.908C5.40973 20.2843 5.71569 20.5903 6.09202 20.782C6.51984 21 7.0799 21 8.2 21H12M13 3L19 9M13 3V7.4C13 7.96005 13 8.24008 13.109 8.45399C13.2049 8.64215 13.3578 8.79513 13.546 8.89101C13.7599 9 14.0399 9 14.6 9H19M19 9V13.5" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>'
                }
            ]
        }
        self.load_config()

    def get_status_by_id(self, status_id):
        for item in self.config.get("items", []):
            if item.get("id") == status_id:
                return item
        return None

check_view.py This describes the view that is called when a page is opened by Django.

from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.decorators import login_required

from project.models import Project
from check.models import Check
from check.conf import CheckStatus

@login_required
def check_list(request, project_id):
    return render(request, 'check_list.html', {
        'project': get_object_or_404(Project, pk=project_id),
        'checks': Check.objects.filter(project_uuid=project_id),
        'check_status_config': CheckStatus().get_config(),
    })

I need to output an svg element and in the title to it display the name of the elements that are in the config.


Solution

  • Django's templates enginge (Jinja) have it's limitations. To overcome them Django has got something called Custom Tags. Quick usage:

    import datetime
    from django import template
    
    register = template.Library()
    
    @register.filter
    def get_title(items, item_id):
        for item in items:
            if item["id"] == item_id:
                return item["title"]
        return "ERROR"
    

    Then in your template:

    {{ check_status_config.items|get_title:id_of_your_item }}
    

    I am also not sure if you are using that correctly:

    {{ status=check_status_config.get_status_by_id(check.status) }} 
    

    You cannot use paranthesis like that in templates.