samedi 29 juillet 2017

ModelForm + ModelMultipleChoiceField can't validate populated list of checkboxes

everybody. I'm trying to build some checklist application. Basically, I have list of checkboxes with states stored in db. I need to load and display their initial state, made changes (select/deselect some of them) and store new checkboxes state back to db.

First phase is done - I've got a view that load checkboxes and states, but when I'm trying to put it back via calling ModelForm with request.POST data (), it fails due some fields\types incompatibility. I've tried to modify my model and POST results, but no result.

Here is my views.py:

class IndexView(generic.ListView):
    template_name = 'polls/index.html'
    context_object_name = 'latest_infinibox_list'
    def get_queryset(self):
        return Infinibox.objects.all()
def detail(request,infinibox_id):
    # print(request.GET)
    if request.POST:
        print('-=posting data=-',request.POST)
        form=ChoiceForm(request.POST)
        print(form.is_valid()) #Here I constanty get False
        return HttpResponseRedirect(reverse('polls:detail', args=(infinibox_id,)))
    else:
        try:
            infinibox = Infinibox.objects.get(pk=infinibox_id)
        except Infinibox.DoesNotExist:
            raise Http404('Infinibox does not exist')
        choice = Choice.objects.filter(infinibox_id=infinibox_id)
        votes = [ch.id for ch in choice if ch.votes == 1]
        choice_text=[ch.choice_text for ch in choice if ch.votes == 1]
        form = ChoiceForm(initial={'infinibox':infinibox,'votes':votes,'choice_text':choice_text},q_pk=infinibox_id)
        return render(request, 'polls/detail.html', {'form': form, 'infinibox': infinibox,})

Here is my models.py:

from django.db import models
from django.utils import timezone
import datetime
class Infinibox(models.Model):
    infinibox_name = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')
    def __str__(self):
        return self.infinibox_name

    def was_published_recently(self):
        now = timezone.now()
        return now - datetime.timedelta(days=1) <= self.pub_date <= now

class Choice(models.Model):
    infinibox = models.ForeignKey(Infinibox, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.BooleanField(default=0)

    def __str__(self):
        return self.choice_text

Here is my forms.py:

from django import forms
from .models import Choice

class ChoiceForm(forms.ModelForm):
    votes = forms.ModelMultipleChoiceField(queryset=None, widget=forms.CheckboxSelectMultiple)
    def __init__(self, *args, **kwargs):
        q_pk = kwargs.pop('q_pk', None)
        super(ChoiceForm, self).__init__(*args, **kwargs)
        self.fields['votes'].queryset = Choice.objects.filter(infinibox_id=q_pk)

    class Meta:
        model = Choice
        fields = ('votes',)

Temporary I've just write some primitive code to get it work:

    def detail(request,infinibox_id):
    if request.POST:
        print('-=posting data=-',request.POST)
        choice = Choice.objects.filter(infinibox_id=infinibox_id)
        vot = [int(item) for item in request.POST.getlist('votes')]
        for variant in choice:
            if variant.id in vot:
                variant.votes = 1
                variant.save()
            else:
                variant.votes = 0
                variant.save()

        return HttpResponseRedirect(reverse('polls:detail', args=(infinibox_id,)))

But I suppose, that this approach is more slowly and unsafe,... maybe it possible to get my request.POST passed to db trough a django's form validation/population logic?

Thanks in advance, Boris




Aucun commentaire:

Enregistrer un commentaire