python - Django Exception Type: KeyError Exception Value: 'pk'



I am probably doing something stupid but cant figure out what and it makes me insane since it is trivial and I have other apps working with same logic.

So I have a Model Customer and Model Notes. Each customer I can create a lot of Notes. In Notes Customer is defined as Foreign key .

def note_new(request,pk):
    contact = get_object_or_404(Contacts, pk=pk)
    if request.method == "POST":
        form = NoteForm(request.POST)
        if form.is_valid():
            note =
            note.pub_date =
            return redirect('contact_details',
        form = NoteForm(
    return render(request, 'customer/note_edit.html', {'form': form})

class NoteForm(forms.ModelForm):
    class Meta:
        model = Note
        fields = [ 'title','body','contact' ]

    def __init__(self,*args,**kwargs):
        contact_id = kwargs.pop('pk')
        # self.fields['contact'].initial = contact_id
        self.initial['contact'] = contact_id
        self.fields['contact'].widget.attrs['readonly'] = True

So form displays ok and after I click save I am getting

KeyError at /customer/note/new/9 'pk' Request Method: POST Request URL: Django Version: 1.8 Exception Type: KeyError Exception Value:
'pk' Exception Location: C:\Users\I812624\dev\mrp\src\customer\ in __init__, line 48 Python Version: 2.7.1

It should redirect me to contact_details where contact info is displayed and it loops over all Notes.


 {% for field in data.notes %}

       <td> {{ field }}</td>

    {% endfor %}

Any suggestions?

Thank you .

2 Answers: 

@Shang has already explained why you are getting the error and how to fix it, so I won't repeat that. My answer is to suggest a different approach in your view.

If you don't want the contact field to be editable, it is best to exclude it from the form.

class NoteForm(forms.ModelForm):
        class Meta:
            model = Note
            fields = [ 'title','body']

Then in your view, you can set the contact after saving with commit=False

    if form.is_valid():
        note =
        note.pub_date = = contact
        return redirect('contact_details',

Now you shouldn't have to override your form's __init__ method at all.

If you want to display the contact in the template, then include it in the template context.

return render(request, 'customer/note_edit.html', {'form': form, 'contact': contact})

Then include {{ contact }} in the template.


This is because you try to do this in your form __init__:

contact_id = kwargs.pop('pk')

but in your method you didn't pass it to the form constructor. Change your note_new method to pass the pk in form:

form = NoteForm(request.POST, pk=pk)

A safer way for avoid the exception is to use default parameter for pop:

contact_id = kwargs.pop('pk', None)
if contact_id:
    # do something if pk is passed, otherwise contact_id is None