0

I am trying to style errors using twitter bootstrap in my Django project. Right now, I have a simple form that asks for a person's email address, has them press a button, and then submits it to the database. It also has validation checking to see if the email is unique in the database. If it is not unique, it raises an error saying "This email is already registered". However, when the error is raised, for a duplicate email, it brings an ugly bullet point list next to the input field with the text This email is already registered. I'm trying to style it to where it has a little dialog show under the input text with a yellow i icon like it does when the input does not include an @ sign, i.e. it isn't an email. The ugly bullet point also appears when a valid domain isn't included in the email, e.g. there isn't a .com appended.

I think the problem lies with the way my form html is set up, or how the view handles the form's errors. Maybe, because the form field is an EmailField, the is_valid indicator doesn't validate and therefore shows the twitter bootstrap alert.

How do I get it to show the alert every time? Below is my code:

form part of the index.html

        <form class="form-inline" method="post">
          <div class="input-group input-group-newsletter">
            <div class="form-group">
              {% csrf_token %}
              {{ form }}
            </div>
            <div class="form-group">
              <div class="input-group-append">
                <button class="btn btn-secondary" type="submit">Button Text</button>
              </div>
            </div>
          </div>
        </form>

views.py

from django.shortcuts import render, HttpResponse
from django.views.generic import TemplateView

from appname.forms import AppForm


class AppView(TemplateView):
    template_name = 'apps/index.html'

    def get(self, request):
        form = AppForm()
        return render(request, self.template_name, {'form': form})

    def post(self, request):
        form = AppForm(request.POST)
        if form.is_valid():
            email = form.cleaned_data['email']
            form.save()
            form = AppForm()
            args = {'form': form, 'email': email, 'signedup': True}
        else:
            args = {'form': form, 'signedup': False}
        return render(request, self.template_name, args)

forms.py

from django import forms
from .models import AppModel


class AppForm(forms.ModelForm):
    email = forms.EmailField(required=True,
                             label='',
                             widget=forms.EmailInput(attrs={'class': 'form-control',
                                                                           'placeholder': 'Enter email...',
                                                                           'name': 'email',
                                                                           'aria-label': 'Enter email...',
                                                                           'aria-describedby': 'basic-addon'}))

    class Meta:
        model = AppModel
        fields = ('email',)

    def clean_email(self, *args, **kwargs):
        email = self.cleaned_data.get("email")
        if AppModel.objects.filter(email__iexact=email).exists():
            raise forms.ValidationError("This email is already registered.")
        return email
Evan Bloemer
  • 1,051
  • 2
  • 11
  • 31
  • It's the form that Django handles errors. Check [this](https://stackoverflow.com/q/7419535/10322652). – Cheche Nov 05 '18 at 02:13
  • The problem isn't that the error isn't displaying. The problem is that the error isn't using twitter bootstrap to create an alert like it does with other errors. – Evan Bloemer Nov 05 '18 at 02:18

1 Answers1

1

You may want to try Django messages framework. This site shows how its done. I have tried it myself and works fine, though I haven't tried putting icons into it.

https://simpleisbetterthancomplex.com/tips/2016/09/06/django-tip-14-messages-framework.html

Update based on the comment below:

Here are the snippets in my project

in settings.py

from django.contrib.messages import constants as messages
...
MESSAGE_TAGS = {
    messages.DEBUG: 'alert-info',
    messages.INFO: 'alert-info',
    messages.SUCCESS: 'alert-success',
    messages.WARNING: 'alert-warning',
    messages.ERROR: 'alert-danger',
}

messages.html template which can be included in any template where you want to have notifications

{% if messages %}
    {% for message in messages %}
        <div class="alert {{ message.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>
    {% endfor %}
{% endif %}

log-in.html template

<body>
{% include 'trip_monitor/messages.html' %}
<div class="login-form">
    <form method="post">
        {% csrf_token %}
        <h2 class="text-center">Materials Management</h2>
        <p align="center">Please <strong>log in</strong> to continue.</p>

        <div class="form-group">
            <input name="username" type="text" class="form-control" placeholder="Username" required="required" autofocus>
        </div>
        <div class="form-group">
            <input  name="password" type="password" class="form-control" placeholder="Password" required="required" id="password">
        </div>
        <div class="form-group">
            <button type="submit" class="btn btn-primary btn-block">Log in</button>
        </div>
    </form>
</div>
</body>

views.py

from django.contrib import messages

def login(request):
    if request.method == 'POST':
        _username = request.POST['username']
        _password = request.POST['password']
        user = authenticate(request, username=_username, password=_password)
        if user is not None:
            auth_login(request, user)
            return redirect('/trip/')
        else:
            messages.error(request, 'Username or Password is incorrect!')  # this will be shown as pop-up message
            return render(request, 'trip_monitor/login.html')
    elif request.method == 'GET':
        if request.user.is_authenticated:
            return redirect('/trip/')
        else:
            return render(request, 'trip_monitor/login.html')
Josh21
  • 506
  • 5
  • 15
  • Whilst this may theoretically answer the question, [it would be preferable](//meta.stackoverflow.com/q/8259) to include the essential parts of the answer here, and provide the link for reference. – Selcuk Nov 05 '18 at 03:21
  • 1
    @Selcuk, updated my answer, did not know that there exist a guide such as aforementioned. – Josh21 Nov 05 '18 at 05:35