1

I am using a ListView to set a form and to show results. However i am not sure how can I make form validation and having the same form with errors in case form.is_valid() is not True.

this is my code

forms.py
class InsolventiForm(forms.Form):

    anno_validator = RegexValidator(r'[0-9]{4}', 'L\'anno deve essere un numero di 4 caratteri')
    anno = forms.CharField(label='Anno', required=True, max_length=4,validators=[anno_validator])

    def clean_anno(self):
        anno = self.cleaned_data['anno']
        return anno

views.py

from .forms import InsolventiForm
class InsolventiView(LoginRequiredMixin, ListView):

    template_name = 'insolventi.html'
    model = Archivio
    form_class = InsolventiForm

    def get(self, request):

        import datetime

        if self.request.GET.get('anno'):

            form = self.form_class(self.request.GET)

            if form.is_valid():
                date = '31/12/'+self.request.GET.get('anno')
                dateTime = datetime.datetime.strptime(date, "%d/%m/%Y")
                dateC = '01/01/'+self.request.GET.get('anno')
                dateTimeC = datetime.datetime.strptime(dateC, "%d/%m/%Y")

                context = Archivio.objects.filter(~Q(quoteiscrizione__anno_quota__exact=self.request.GET.get('anno')) \
                & Q(data_iscrizione__lte=dateTime) \
                & (Q(cancellato__exact=False) | (Q(cancellato__exact=True) & (Q(data_canc__gte=dateTimeC)))))

                self.request.session['insolventi_queryset'] = serialize('json', context)

                return render(request, self.template_name, {'form':form})

            else: return redirect(reverse('insolventi'))

        return render(request, self.template_name, {'form':self.form_class()}) 

this is my template and I am displaying the form manually.

insolventi.html

<form method="get" action="">
    {% for field in form %}
        {{ field.errors }}
        {{ field.as_widget() }}
    {% endfor %} 
    <input type="submit" value="Ricerca" />
</form>

Even if there are errors and form.is_valid() is returning False (giving me a redirect to the same view) on the template I never get {{ form.errors }}. I don't know what is missing!

I am thinking: Because i use the input of the form to get the query in JSON with django rest and post it on the same template with DataTables, maybe I do not need to use a ListView ??

Brown Bear
  • 19,655
  • 10
  • 58
  • 76
Rodriguez David
  • 541
  • 9
  • 25
  • 1
    Remove this line: `else: return redirect(reverse('insolventi'))`. You are redirecting to the same view, but that will not render the form with errors, it will create a new blank form. Edit: and you need to `render` the form with the bound data, not a new instance. – Paulo Almeida Aug 30 '17 at 12:02
  • Removing that else condition with this line 'return render(request, self.template_name, {'form':form})' made me get the errors on my form! – Rodriguez David Aug 30 '17 at 13:19
  • Yes, that works too. The usual way to do it is like in @ivo's answer. You don't put an `else` in `form.is_valid()` and let the `render` at the end deal with the form. Of course, to do that you need to have an `else` for `self.request.GET.get('anno')` where you create an empty form and then use `{'form': form}` as the context in the `render`. Anyway, it's working, so do whatever feels more natural to you. – Paulo Almeida Aug 30 '17 at 14:00
  • Thanks for your help :) – Rodriguez David Aug 30 '17 at 14:12
  • Do you think I miss some kind of control or something if I process my requests, like in this case, overriding the get() method ?? – Rodriguez David Aug 30 '17 at 14:15
  • You don't lose any control by overriding `get`, on the contrary, but it does make me wonder why you use a `ListView` instead of a `View`. Since you don't seem to be using any of the [`ListView`'s `get`](https://ccbv.co.uk/projects/Django/1.11/django.views.generic.list/ListView/#get) functionality, why use it at all? – Paulo Almeida Aug 30 '17 at 14:36
  • I don't really know why! I was thinking about it but I was afraid that View is too generic... I am also seeing this https://ccbv.co.uk/projects/Django/1.11/django.views.generic.base/View/ and it looks like that View class doesn't have a get method at all! – Rodriguez David Aug 30 '17 at 14:45
  • Well, this is really out of the scope of the question, I'm getting the warning to avoid extended discussion :) Anyway, the `View` doesn't have a `get` method because you're supposed to implement it, like you do in your view. It's true that it also doesn't have the template and form machinery, so you could use a `FormView` instead. – Paulo Almeida Aug 30 '17 at 15:38
  • FormView seems to be an intersting alternative!!! I really appreciate your help :) – Rodriguez David Aug 30 '17 at 15:53

2 Answers2

1

You should not be redirecting if there are errors since redirecting will lose all the form data.

Try removing the line:

            else: return redirect(reverse('insolventi'))

and letting it fall through to the render() line.

ivo
  • 1,103
  • 10
  • 13
  • 1
    Instead of removing it I needed to replace with a return statement of the render funcion.. and pass it the bound form :).. thank you – Rodriguez David Aug 30 '17 at 13:36
0

Hi can you try this post

custom form validation

also refer django document

django custom validation as per document

Robert
  • 3,373
  • 1
  • 18
  • 34