Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

django allauth custom messages: Styling messages with html/css

Allauth's the messages are stored as text files in the templates directory by default and these look something like:

{% load i18n %}
{% blocktrans %}You cannot remove your primary e-mail address ({{email}}).{% endblocktrans %}

These use django's template tags but aren't 'HTML friendly'. I would like to style these and have something like:

{% load i18n %}
<div class="alert alert-danger alert-dismissible" role="alert">
            <button type="button" class="close" data-dismiss="alert" aria-label="Close">
                <span aria-hidden="true">&times;</span>
            </button>
            {% blocktrans %}You cannot remove your primary e-mail address ({{email}}).{% endblocktrans %}
 </div>

But the code above simply renders the HTML as text. I cannot put this HTML in a template and just do {{ message }} within the template because I would like to change some of it on a per message bias (at least the color!).

How could I accomplish this? Thank you!

like image 782
Max Smith Avatar asked May 29 '17 23:05

Max Smith


1 Answers

The template is the place for message styling markup, not the messages .txt files. You should be able to achieve the per case variation through Django's defaults, or conditional statements if needed. I see you're using Bootstrap, and for many use cases, the default Django messaging tags map nicely onto Bootstrap's own alert classes. When you create a message in a view...

messages.success(request, 'You have logged in successfully.')

...each Django message contains a string representation of its level ('info', 'success' etc.) as a tags attribute. You can use these tag properties for many contextual formatting needs. So you can pass it to the (e.g. base) template like:

<div class="alert alert-{{ messages.tags }} alert-dismissible" role="alert">
    <button type="button" class="close" data-dismiss="alert" aria-label="Close">
        <span aria-hidden="true">&times;</span>
    </button>
    {{ message }}
</div>

If your message has the level success then the rendered CSS class here will be alert-success, so Bootstrap will show a green alert. If the status is info, it will be alert-info and blue and so on.

Django's default message levels and string representations are defined in django/contrib/messages/constants.py:

DEFAULT_TAGS = {
    DEBUG: 'debug',
    INFO: 'info',
    SUCCESS: 'success',
    WARNING: 'warning',
    ERROR: 'error',
}

DEFAULT_LEVELS = {
    'DEBUG': DEBUG,
    'INFO': INFO,
    'SUCCESS': SUCCESS,
    'WARNING': WARNING,
    'ERROR': ERROR,
}

Compare this with Bootstrap's default alert classes and contextual formatting:

Bootstrap default alert classes and contextual colours

info, success and warning classes mirror Django's message levels, so these messages will automatically get Bootstrap's correct formatting. But Django's most severe level is error whereas Bootstrap's is danger.

A suggested workaround for this name clash is: keep the Django template tag unchanged, which will give the element a class called alert-error. Then use a couple of lines of Javascript somewhere in your HTML template to add alert-danger as an extra class to these elements:

// Javascript somewhere in your HTML template
let errorElements = document.getElementsByClassName('alert-error');
[...errorElements].forEach(el => {el.classList.add('alert-danger')});

This will add the class 'alert-danger' to elements which have the class 'alert-error'. 'alert-error' will be ignored by Bootstrap, but with 'alert-danger' added to the elements' class lists, they will get Bootstrap's red contextual formatting.

If you want to customise things specifically with allauth, for example setting different message levels from allauth's defaults - say, the login message as info level rather than success - you can change them directly in allauth.account.views (and allauth.socialaccount.views).

You can also pass in extra tags to Django messages and use these for conditional formatting: see extra message tags in the docs and this answer, for example.

(EDIT: removed original idea about changing Django core code - bad.)

like image 165
birophilo Avatar answered Sep 30 '22 16:09

birophilo