Frage

So I'm getting a KeyError, every time I try to submit a formset.
I asked a similar question before here, and the solution seemed to work for a while, but now I get the above mentioned KeyError.
Code and Trace below:

Form:

class CodingForm(forms.Form):
    NATIONAL = 0
    REGIONAL = 1
    LOCAL = 2
    NA = 99
    SCOPE_CHOICES = (
        (NA, 'No Report'),
        (NATIONAL, 'National'),
        (REGIONAL, 'Regional'),
        (LOCAL, 'Local'),
    )

    NO_VIO = 0
    PROP_DMG = 1
    INJ = 2
    KILL = 3

    PART_VIO = (
        (NA, 'No Report'),
        (NO_VIO, 'No Violence'),
        (PROP_DMG, 'Property Damage'),
        (INJ, 'People Injured'),
        (KILL, 'People Killed'),
    )

    NO_PRES = 0
    PRES = 1
    INT = 2
    LETHAL_INT = 3

    SEC_ENG = (
        (NA, 'No Report'),
        (NO_PRES, 'No Presence'),
        (PRES, 'Presence'),
        (INT, 'Intervention'),
        (LETHAL_INT, 'Lethal Intervention'),
    )

    event_date = forms.DateField(required=False)
    location = GeonamesChoiceField(queryset=Geonames.objects.all(), required=False)
    actors = forms.CharField(max_length=100, required=False)
    num_participants = forms.CharField(max_length=200, required=False)  
    issue = forms.CharField(max_length=200, required=False)
    side = forms.NullBooleanField('Side')
    scope = forms.TypedChoiceField(choices=SCOPE_CHOICES, coerce=int, empty_value=None)
    part_violence = forms.TypedChoiceField(choices=PART_VIO, coerce=int, empty_value=None)
    sec_engagement = forms.TypedChoiceField(choices=SEC_ENG, coerce=int)
    relevance = forms.NullBooleanField('relevance')


    def clean(self):
            cleaned_data = self.cleaned_data
            event_date = cleaned_data.get("event_date")
            location = cleaned_data.get("location")

            if event_date and location:
                cleaned_data['relevance'] = True
                print cleaned_data["relevance"]
            else:
                cleaned_data['relevance'] = False

            return cleaned_data

View:

def assignment(request, pk):
"""View for each assignment"""
if request.user.is_authenticated():

    #### Get correct articles
    assignment = get_object_or_404(Assignment, pk=pk)
    country = assignment.country.cowcode
    start_date = assignment.start_date
    end_date = assignment.end_date
    articles = Article.objects.filter(cowcode=country).filter(pubdate__range=(start_date,end_date))

    #### Pagination ####
    paginator = Paginator(articles, 1)
    page = request.GET.get('page')
    try:
        articles = paginator.page(page)
    except PageNotAnInteger:
        articles = paginator.page(1)
    except EmptyPage:
        articles = paginator(page(paginator.num_pages))

    # Check if on first page and enable redirect
    if page is None:
        current_page = 1
    else:
        current_page = page
    redirect_to = "?page=%s" % current_page

    CodingFormSet = formset_factory(CodingForm, extra=0)
    formset = CodingFormSet(request.POST or None, prefix="coding_form")

    location_queryset = Geonames.objects.filter(cowcode=country).order_by('name')
    for form in formset.forms:
           form.fields['location'].queryset = location_queryset

    ##### Check if coder wants to go to next page or stay
    if "coding_form_next" in request.POST:
        process_form(formset, request, current_page, paginator)
        current_page = int(current_page) + 1
        redirect_to = "?page=%s" % current_page
        return HttpResponseRedirect(redirect_to)
    elif "coding_form_save" in request.POST:
        process_form(formset, request, current_page, paginator)
        redirect_to = "?page=%s" % current_page
        return HttpResponseRedirect(redirect_to)

else:
    print ERROR
return render(request, 'coding/assignment.html', 
{'articles':articles,'assignment':assignment,'formset':formset})

def process_form(formset, request, current_page, paginator):
if formset.is_valid():
    for form in formset.forms:
        form = form.cleaned_data

        if form['relevance'] == False:
            pass
        elif form['relevance'] == True:


            event_form = EventRecordForm()

            event = event_form.save(commit=False)
            event.article = paginator.page(current_page).object_list[0]
            event.coder = request.user
            event.last_updated = datetime.datetime.today()
            event.event_date = form["event_date"]
            event.location = form["location"]
            event.actors = form["actors"]
            event.num_participants = form["num_participants"]
            event.issue = form["issue"]
            event.side = form["side"]
            event.scope = form["scope"]
            event.part_violence = form["part_violence"]
            event.sec_engagement = form["sec_engagement"]
            event.save()

    ##### Add info on who worked on the article when
    history_form = ArticleHistoryForm()
    article_history = history_form.save(commit=False)
    article_history.article = paginator.page(current_page).object_list[0]
    article_history.coder = request.user
    article_history.last_updated = datetime.datetime.now()
    article_history.save()

Template:

<div id="coding">
<div id="coding-inner">
    {% with formset.empty_form as form %}
    <div id="empty_form" style="display:none">
        <table border="0" cellspacing="5" cellpadding="5">
            <tbody>
            <tr>
                <td>{{ form.event_date.label_tag}}</td>
                <td>{{ form.event_date}}</td>
            </tr>
            <tr>
                <td>{{ form.location.label_tag }}</td>
                <td><div class="location_wrapper">{{ form.location }}</div></td>
            </tr>
            <tr>
                <td>{{ form.actors.label_tag }}</td>
                <td>{{ form.actors }}</td>
            </tr>
            <tr>
                <td>{{ form.num_participants.label_tag }}</td>
                <td>{{ form.num_participants }}</td>
            </tr>
            <tr>
                <td>{{ form.issue.label_tag }}</td>
                <td>{{ form.issue }}</td>
            </tr>
            <tr>
                <td>{{ form.side.label_tag }}</td>
                <td>{{ form.side }}</td>
            </tr>
            <tr>
                <td>{{ form.scope.label_tag }}</td>
                <td>{{ form.scope }}</td>
            </tr>
            <tr>
                <td>{{ form.part_violence.label_tag}}</td>
                <td>{{ form.part_violence}}</td>
            </tr>
            <tr>
                <td>{{ form.sec_engagement.label_tag }}</td>
                <td>{{ form.sec_engagement }}</td>
            </tr>
            <tr>
                <td>{{ form.relevance.label_tag }}<td>
                <td>{{ form.relevance }}<td>
            </tr>
        </tbody>
        </table>
    </div>
    {% endwith %}
    <form action="" method="post" accept-charset="utf-8" id="form"> 
        {% csrf_token %}
        <div class="form-container"></div>
        {{ formset.management_form }}
        <div id="form-nav">

            <div id="save-stay">
                <input type="submit" name="coding_form_save" value="Save">
            </div>
            <div id="save-next">
                <input type="submit" name="coding_form_next" value="Save &#38; Next">
            </div>

        </div>
    </form>

</div>

And the Trace:

Environment:
Request Method: POST
Request URL: http://127.0.0.1:8000/coding/assignment/1/?page=1

Django Version: 1.5
Python Version: 2.7.2
Installed Applications:
('django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.sites',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'django.contrib.admin',
 'coding',
 'south')
Installed Middleware:
('django.middleware.common.CommonMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware')


Traceback:
File "/Users/lukaskawerau/.virtualenvs/MMAD/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
  115.                         response = callback(request, *callback_args, **callback_kwargs)
File "/Users/lukaskawerau/Dropbox/Coding/mmad/app/mmad/coding/views.py" in assignment
  179.             process_form(formset, request, current_page, paginator)
File "/Users/lukaskawerau/Dropbox/Coding/mmad/app/mmad/coding/views.py" in process_form
  36.             if form['relevance'] == False:

Exception Type: KeyError at /coding/assignment/1/
Exception Value: 'relevance'

What am I doing wrong? I've tried everything I could think of, but nothing works.
Any help is hugely appreciated!

Update: I looked at local vars again, and notices that form is empty:

formset <django.forms.formsets.CodingFormFormSet object at 0x10eb9dd10>
form    {}

Why would that be?

Update 2: The problem was a different thing entirely: The JavaScript plugin I was using was messing with the HTML "name" tag of my inputs, so Django only saw an empty form.
I'm accepting @Francis answer, because it was the most detailed and still helpful. My bounty also shouldn't go to waste.
What do we learn from this? Check your JS.

War es hilfreich?

Lösung

I haven't set up this example in my test project, but something that strikes me as a possible problem is this:

relevance = forms.NullBooleanField('relevance')

The NullBooleanField allows NULL as one of the options. I wonder if the form is seeing a NULL/None and removing the key/value from the cleaned_data dict...

either way, I'd call the form's super's clean method and start from there...

def clean(self):
    #this line is kinda important
    cleaned_data = super(CodingForm, self).clean()

    event_date = cleaned_data.get("event_date")
    location = cleaned_data.get("location")

    if event_date and location:
        cleaned_data['relevance'] = True
        print cleaned_data["relevance"]
    else:
        cleaned_data['relevance'] = False

    return cleaned_data

additionally wrap calls to dict elements like this to prevent key errors

if 'relevance' in form:
    if form['relevance'] == False:
        ...
    elif form['relevance'] == True:
        ...

or

try: 
    if form['relevance'] == False:
        ...
    elif form['relevance'] == True:
        ...
except KeyError, e:
    ...

Andere Tipps

It should be form.fields['relevance'] in place of form['relevance'].

There's an error in your clean method. It should start with

cleaned_data = super(CodingForm, self).clean()

like the example in the docs.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top