0

Referring this answer

I couldn't access the kwargs in the html template by {{ view.kwargs.foo }}. Not sure why, is it because something's different with DRF so I need a different syntax to access it?

My html template ('polls/character_description_list.html'):

{% block content %}
<table>
    {% for description in descriptions %}
    <tr>
        <td><b>{{ description.title }}</b></td>
        <td>{{ description.content }}</td>
    </tr>
    {% endfor %}
</table>

<form action="{% url 'polls:description_detail_create_from_character' %}">
    <input type="hidden" value="{{ view.kwargs.character_id }}" name="character_id"> <!-- This is where I attempt to access the kwargs but can't get it, although I can attempt to output it anywhere else for debugging -->
    <input type="submit" value="New Description"/>
</form>
{% endblock %}

Therefore when submitting I expect to go to:

http://localhost:8000/myapp/description_detail_create_from_character/?character_id=1

But in reality the id is missing:

http://localhost:8000/myapp/description_detail_create_from_character/?character_id=

To check if the character_id token I am looking for is in kwargs, I did try to breakpoint (using PyCharm) in get_serializer_context:

    def get_serializer_context(self):
        context = super(CharacterDescriptionListView, self).get_serializer_context()
        return context

Examined the context, I can find 'view' -> kwargs -> 'character_id', with the value I am expecting, so it should work.

This is my views.py:

# Already has a chain of hierarchy but basically it descends from generics.ListCreateAPIView
class CharacterDescriptionListView(DescriptionViewMixin, CustomNovelListCreateView):
    template_name = 'polls/character_description_list.html'

    def get_filter_object(self):
        return get_object_or_404(Character, id=self.kwargs['character_id'])

    def get_queryset(self):
        characterObj = self.get_filter_object()
        return Description.objects.filter(character=characterObj)

daichou03
  • 55
  • 9
  • Try using [`{% debug %}`](https://docs.djangoproject.com/en/dev/ref/templates/builtins/#debug) to check the context in the template. – Alasdair Aug 09 '19 at 10:06
  • I'm not sure why you are using a DRF view here. Why not a standard Django view? – Daniel Roseman Aug 09 '19 at 11:16
  • What is `CustomNovelListCreateView` and `DescriptionViewMixin`? I don't understand why you think there's a `view` context variable but maybe these classes provide it... The only thing you need is adding the id to your context. If you view class has a `get_context_data()` method, override that and add the variable to your context there. Then you can access it in your template like any other context variable. – dirkgroten Aug 09 '19 at 11:48
  • @Alasdair Wow I didn't know that! After some trial and error I got the answer: Yes, if using DRF the way to get the context IS different - it is something like {{ serializer.context.character_id }}. Regarding the problem I met and how it is solved, you worth the "accepted answer" :-) – daichou03 Aug 09 '19 at 12:32
  • @DanielRoseman Yeah that's a good question, I am learning by doing Django and heard that it's good to have DRF earlier than late if I might use API later at some point. TBH it gave me a deeper learning curve than I would have been using a standard one, but there are some good points even for just html, mainly the Serializers. What's the most point that you think DRF for html is bad? I am curious :) – daichou03 Aug 09 '19 at 12:41
  • Glad you figured out the problem. I'll let you write your own answer because I'm not sure whether it's Django Rest Framework or your own view/mixin/parent classes that stopped `view` from being added to the template context. – Alasdair Aug 09 '19 at 12:42
  • @dirkgroten Ah, there's a chain of hierarchy here for the purpose of reusing codes as much as possible, but basically it descends from generics.ListCreateAPIView (have added a comment about this). Regarding adding the context in get_context_data(), yep I have checked that the context is already there and even if I add it again:`context.update({ "character_id": self.kwargs['character_id'] })` it won't help. – daichou03 Aug 09 '19 at 12:44
  • @daichou03 DRF isn't bad in itself, but for plain HTML pages, there's usually no need to serialise objects or use the DRF API views because they have the purpose of serialising objects so they can rendered as JSON. I never use DRF for my HTML pages, but I do when one of my pages has JS that requests updates via ajax (then it's an API that returns JSON). – dirkgroten Aug 09 '19 at 12:55
  • @daichou03 I didn't realise your view was descending from a DRF API view. `get_context_data()` isn't defined on DRF class-based views so obviously implementing it won't do anything. It's not even called. – dirkgroten Aug 09 '19 at 12:58
  • @Alasdair OK I will do that then :) Did some research and I can confirm it is because of DRF. I will write them down in the answer. – daichou03 Aug 09 '19 at 13:02
  • @dirkgroten Yeah, in DRF API view it is called get_serializer_context which does the same thing. Was trying on that although the context is already there in my case. – daichou03 Aug 09 '19 at 13:05

1 Answers1

1

This is because I am using DRF's generics.ListCreateAPIView. In that case, the syntax for accessing the context I am looking for should be:

{{ serializer.context.character_id }}

Which I found after I learned that I can {% debug %} in the html template thanks to @Alasdair.


This can be confirmed by checking the source code of GenericAPIView in DRF -- which descends from View but not TemplateView so that it doesn't have get_context_data. Therefore for GenericAPIView can only access the context like {{ serializer.context.character_id }} but not {{ view.kwargs.character_id }}.

daichou03
  • 55
  • 9