pythondjangopython-3.xdjango-templatesdjango-context

Python/Django universal method passed to template engine


I have a large Django Project that has hundreds of views already. I am creating a tasks feature where users are able to complete specific tasks associated with the specific application in the project they are using. I have multiple interfaces (aka Django apps in the project) : admin, management, onsite, etc... and each interface has its own navigation with a tasks link.

What I want is to be able to change the color of this link if a user is in an interface where a task has yet to be completed.

This is easy to check in each view and then I could universally render the correct color for the link based on a variable passed into the view, but that is extremely tedious with hundreds of views.

I suppose I could add a filter in each interface/Django App to simplify this a bit, but is that the most simple solution?

Here is an example of the method I want to be called in each interface's navigation:

from objects_client.task_models.task_models import Tasks


def does_interface_have_open_tasks(current_interface, db_alias):
    if Tasks.objects.using(db_alias)\
            .filter(interface=current_interface, completed=0).exists():
        return True
    return False


Solution

  • I ended up using a Context Processor to solve my needs like I show below:

    import traceback
    from objects_client.task_models.task_models import Tasks
    
    
    def universally_used_data(request):
        # I use multiple DBs
        db_alias = request.session.get('db_alias')
    
        # dictionary for global context values
        dictionary_to_return = dict()
    
        # interfaces and URL equivalents
        interface_dictionary = {
            'adm': 'admin',
            'mgt': 'management',
            'onsite': 'onsite',
            'secu': 'security',
            'maint': 'maintenance'
        }
    
        try:
            # get interface url
            short_url = request.path[1:-1].split('/')[1]
            # get interface from dictionary above
            interface = interface_dictionary.get(short_url)
    
            dictionary_to_return['SHORT_URL'] = short_url
    
            dictionary_to_return['INTERFACE'] = interface
    
            # see if there is an open task...
            if Tasks.objects.using(db_alias) \
                    .filter(interface=interface, completed=0).exists():
    
                dictionary_to_return['OPEN_TASKS'] = True
            else:
                dictionary_to_return['OPEN_TASKS'] = False
    
        except Exception as ex:
            print(ex, traceback.format_exc())
    
        return dictionary_to_return
    
    
    

    Here is how I load the Context Processor:

    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
    
            'DIRS': [
                os.path.join(BASE_DIR, 'templates'),
                ... 
            ]
            ,
            'APP_DIRS': True,
            'OPTIONS': {
                'context_processors': [
                   ... 
                    # custom processors
                    'utils.context_processors.context_processors.universally_used_data'
                ],
            },
        },
    ]
    
    

    Then I can just call the this variable in the template like so to change an HTML element's color, no {% load [whatever] %} or anything:

    {% if OPEN_TASKS %}
        style="color:red;"
    {% endif %}
    

    Thank you @Daniel Roseman for the suggestion/comment. This had me stumped for a bit :)