Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to deal with KeyError: 'pk' in Django Formview

Tags:

python

django

I'm trying to construct a form using Django FormView which will redirect me to page if the form is valid. I want to see a success message in a modal window after redirect. That did not work well as I'd get KeyError: 'pk' upon form submission.

views.py:

class ApplyView(FormView):
    template_name = 'vouchers/apply.html'
    model = Voucher
    voucher = None
    form_class = VoucherApplyForm

    def form_valid(self, form):
        self.code = form.cleaned_data['code']
        now = timezone.now()
        Voucher.objects.filter(code__iexact=self.code,
                               valid_from__lte=now,
                               valid_to__gte=now,
                               usage_limit=3,
                               active=True)
        form.apply_voucher()
        return super(ApplyView, self).form_valid(form)

    def get_success_url(self):
        messages.add_message(self.request, messages.INFO,
                             "Congratulations! You've successfully redeemed {{ voucher.value }} "
                             "{{ voucher.get_type_display }} off the selected item(s).")
        return reverse('vouchers:apply', args=(self.kwargs['pk'],))


class VoucherDetailView(generic.DetailView):
    template_name = 'vouchers/detail.html'
    model = Voucher

    def get_context_data(self, **kwargs):
        context = super(VoucherDetailView, self).get_context_data(**kwargs)
        context['redemption_form'] = VoucherApplyForm(initial={'voucher':self.object})
        return context

urls.py:

urlpatterns = [
    path('<int:pk>/', views.VoucherDetailView.as_view(), name='detail'),
    path('<int:voucher_id>/apply/', views.ApplyView.as_view(), name='apply'),
]

detail.html:

<h1>Redeem your voucher!</h1>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<form action="{% url 'vouchers:apply' voucher.id %}" method="post">
{{ redemption_form }}
{% csrf_token %}
<input type="submit" value="Apply">
</form>

apply.html:

{% if messages %}
<ul class="messages">    
{% for message in messages %}
    <li {% if message.tags %} class="{{ message.tags }}" {% endif %}>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}

And i ended up receiving error as follows:

return reverse('vouchers:detail', args=(self.kwargs['pk'],))
KeyError: 'pk'

Your help is much appreciated. Thanks!

like image 341
hs96 Avatar asked Sep 19 '25 22:09

hs96


1 Answers

It should be:

    return reverse('vouchers:apply', args=(self.kwargs['voucher_id'],))

Since the url associated with the ApplyView has as parameter a voucher_id, not a pk.

It might be better to use kwargs here however:

    return reverse('vouchers:apply', kwargs={'voucher_id': self.kwargs['voucher_id'] })
like image 59
Willem Van Onsem Avatar answered Sep 21 '25 14:09

Willem Van Onsem