0

I'm a django newbie so a verbose answer will be greatly appreciated. I'm enforcing a capacity limit on any newly created Bottle objects in my model, like so:

class Bottle(models.Model):
    name = models.CharField(max_length=150, blank=False, default="")
    brand = models.ForeignKey(Brand, on_delete=models.CASCADE, related_name="bottles")
    vintage = models.IntegerField('vintage', choices=YEAR_CHOICES, default=datetime.datetime.now().year)
    capacity = models.IntegerField(default=750,
                                   validators=[MaxValueValidator(2000, message="Must be less than 2000")
                                    ,MinValueValidator(50, message="Must be more than 50")])

My BottleForm looks like so:

class BottleForm(ModelForm):

    class Meta:
        model = Bottle
        fields = '__all__'

My view (with form validation logic based on this answer):

def index(request):
    args = {}

    user = request.user
    object = Bottle.objects.filter(brand__business__owner_id=user.id).all(). \
    values('brand__name', 'name', 'capacity', 'vintage').annotate(Count('brand')).order_by('brand__count')

    args['object'] = object

    if request.method == "POST":
        form = BottleForm(request.POST)

        if form.is_valid():
            bottle = form.save(commit=False)
            bottle.save()
            return redirect('index')

    else:
        form = BottleForm()
    args['form'] = form
    return render(request, template_name="index.pug", context=args)

And my template (in pug format), like so:

            form(class="form-horizontal")(method="post" action=".")
                | {% csrf_token %}
                for field in da_form
                    div(class="form-group")
                        label(class="col-lg-3 col-md-3 col-sm-3 control-label") {{field.label_tag}}
                        div(class="col-lg-9 col-md-9 col-sm-9")
                            | {{ field|add_class:"form-control" }}
                input(class="btn btn-primary")(type="submit" value="submit")

After a few hours of messing with my code and browsing SO, I managed to display the error by adding {{ form.errors }} to my template, but that only shows after the page has already been reloaded and in a very ugly form: see here.

What I'd like is to utilize django's built-in popover error messages without reloading page (see example on default non-empty field), which is so much better from a UX standpoint.

zerohedge
  • 3,185
  • 4
  • 28
  • 63

1 Answers1

1

That is not a Django message. That is an HTML5 validation message, which is enforced directly by your browser. Django simply outputs the input field as type number with a max attribute:

<input type="number" name="capacity" max="750">

I'm not sure if your (horrible) pug templating thing is getting in the way, or whether it's just that Django doesn't pass on these arguments when you use validators. You may need to redefine the field in the form, specifying the max and min values:

class BottleForm(ModelForm):
    capacity = forms.IntegerField(initial=750, max_value=2000, min_value=250)

(Note, doing {{ field.errors }} alongside each field gives a much better display than just doing {{ form.errors }} at the top, anyway.)

Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
  • I'll try your suggestion, thank you for the clarification! (You should try pug even if I implement it horribly) – zerohedge May 22 '17 at 19:05
  • I'm getting "unexpected argument" warning when I try to do models.IntegerField inside my form like your example. – zerohedge May 22 '17 at 19:12
  • Argh, sorry, that should have been `forms.IntegerField` of course. Corrected. – Daniel Roseman May 22 '17 at 19:14
  • That works for the form, thank you! It just doesn't seem to take default as a parameter. So as I understand if I need this functionality I will have to give up using fields = "__all__" because then I will two capacity fields? – zerohedge May 22 '17 at 19:19
  • Really sorry again, it should be `initial` not `default` in a form field. No you don't need to change the `fields` definition; defining a field at form level simply overrides any definition by that name that comes from the model. – Daniel Roseman May 22 '17 at 19:23
  • Thank you. But when I use `fields = "__all__" with your `capacity` line I get two capacity fields in the form itself. (Edit: scratch that, I misspelled capacity!!) – zerohedge May 22 '17 at 19:24