Django - KeyError в поле формы
Поэтому я получаю KeyError, каждый раз, когда пытаюсь отправить набор форм.
Я задавал подобный вопрос раньше здесь, и решение, казалось, работало некоторое время, но теперь я получаю вышеупомянутую KeyError.
Код и трассировка ниже:
Форма:
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
Посмотреть:
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()
Шаблон:
<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 & Next">
</div>
</div>
</form>
</div>
И след:
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'
Что я делаю неправильно? Я перепробовал все, что мог придумать, но ничего не работает.
Любая помощь очень ценится!
Обновление: я снова посмотрел на локальные переменные и заметил, что form
пустой:
formset <django.forms.formsets.CodingFormFormSet object at 0x10eb9dd10>
form {}
С чего бы это?
Обновление 2: Проблема была совсем в другом: плагин JavaScript, который я использовал, работал с HTML-тегом "name" моих входов, поэтому Django видел только пустую форму.
Я принимаю ответ @Francis, потому что он был самым подробным и все же полезным. Моя награда также не должна пропасть даром.
Что мы узнаем из этого? Проверьте свой JS.
3 ответа
Я не настроил этот пример в своем тестовом проекте, но одна из проблем, которая мне кажется возможной, заключается в следующем:
relevance = forms.NullBooleanField('relevance')
NullBooleanField
allows NULL as one of the options
, Интересно, видит ли форма NULL/None и удаляет ключ / значение из dict cleaned_data...
в любом случае, я бы назвал метод super super формы и начал бы оттуда...
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
дополнительно оберните вызовы, чтобы продиктовать подобные элементы, чтобы предотвратить ключевые ошибки
if 'relevance' in form:
if form['relevance'] == False:
...
elif form['relevance'] == True:
...
или же
try:
if form['relevance'] == False:
...
elif form['relevance'] == True:
...
except KeyError, e:
...
В вашем чистом методе есть ошибка. Должно начинаться с
cleaned_data = super(CodingForm, self).clean()
как пример в документах.
Так должно быть form.fields['relevance']
на месте form['relevance']
,