DRF Create: Response не возвращает мой шаблон с контекстными переменными, несмотря на использование встроенной функции render_to_string()

Фон

Я хочу создавать и отображать ответы без необходимости обновлять страницу. Я знаю, что это можно сделать, отправив форму с помощью AJAX или Fetch(), и использовать возвращенный ответ для добавления в нижнюю часть списка комментариев. Я пытаюсь достичь этого, используя DRF и AJAX. Я выбрал DRF HTMLRenderer + Django render_to_string(), чтобы не создавать литерал шаблона JS для рендеринга шаблона из JSON, и мне было бы намного проще вносить изменения в шаблон, если бы я просто позволил системе шаблонов Django сделать это за меня.

Проблема

Мой ответ не заполняет мой шаблон контекстными переменными, несмотря на то, что я передаю контекст встроенной функции render_to_string(). Вероятность того, что render_to_string() виноват, очень мала, и я, честно говоря, не знаю, как решить эту проблему. Я также попробовал заменить render_to_string() на render(), чтобы проверить, устранит ли это проблему. Однако проблема все равно осталась.

Я знаю это из-за следующих двух ошибок атрибутов при просмотре ответа из консоли:

  1. 'str' object has no attribute 'is_authenticated'
  2. Reverse for 'profile_detail' with arguments '('',)' not found. 1 pattern(s) tried: ['account/user/(?P<slug>[^/]+)/$']

И то, и другое не произошло бы, если бы контекст оценивался в моем шаблоне.

Сам ответ создается и виден, если я вручную обновляю страницу после AJAX-поста.

Информация

Похоже, что проблем с фактическим контекстом нет, потому что точка разрыва показывает ожидаемые результаты (... я заменяю фактический текст для краткости):

{'reply': <Reply: Reply object (47527)>, 'post': <Post: ....>, 'recipient': <Profile: ....>}}

Вопросы

  1. Is my problem happening with the render_to_string(), or is there something else at fault?
  2. Am I on the right track to sending and rendering replies? Is there anything that can be improved? (code review)

Итак, проблема, скорее всего, возникает здесь, но это было бы очень странно, потому что какова вероятность того, что встроенная функция не работает?

response['render_reply'] = render_to_string(
   template_name=self.template_name, context=context, request=request
)

Релевантный код

Viewset

Я создал свое собственное действие, потому что не был уверен, как добиться этого с помощью стандартного create().

class ReplyActionViewSet(viewsets.ModelViewSet):
    queryset = Reply.objects.all()
    serializer_class = ReplySerializer
    permission_classes = [IsAuthenticated]
    renderer_classes = [JSONRenderer, TemplateHTMLRenderer]
    template_name = "post/partials/render-reply.html"

    def get_queryset(self):
        return self.queryset.filter(user=self.request.user)

    @action(detail=True, methods=['post'])
    def create_reply(self, request, pk=None):
        response = {}

        post = get_object_or_404(
            Post.public_or_member_objects.all(), pk=pk
        )
        serializer = ReplySerializer(data=request.POST)

        if serializer.is_valid():
            ...

            reply = Reply.objects.create(**data)
            ...

            context = {'reply': reply, 'post': post, 'data': {"post": post, "recipient": reply.recipient}}

            response['render_reply'] = render_to_string(
                template_name=self.template_name, context=context, request=request
            )
            return Response(response)

        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

Фрагмент шаблона ответа, где происходит одна из проблем:

<div class="d-flex flex-row align-items-center">
    <div class="avatar avatar-sm me-2" style="background-color:{{ post.user.avatar_color }};">
        {{ reply.user.nickname|slice:1 }}
    </div>
    <a href="{% url "profile_detail" reply.user.username %}" class="text-decoration-none">
        <span style="font-weight: 500; color:{{ post.user.avatar_color }};">{{ reply.user.nickname }}</span>
    </a>
</div>

А вот мой JS:

'use strict';

$(document).on("submit", ".js-reply-form", function (event) {
  event.preventDefault();

  const form = $(this);
  const url = form.attr('action');

  $.ajax({
    type: "POST",
    url: url,
    dataType: 'html',
    data: form.serialize(),
    success: function (data) {
      form.trigger('reset');
      
    },
    error: function (response) {
      console.log(response);
      console.log("failed!");

    },
  });
});

Пожалуйста, опубликуйте всю трассировку 1-й ошибки

<str> object has no ... 

Ваша 2-я ошибка означает, что в

<a href="{% url "profile_detail" reply.user.username %}"

имя пользователя пустое.

Решение, честно говоря, было довольно простым. response['render_reply'] оценивается в {'render_reply':'long string'}, который является JSON.

Поэтому мне нужно было изменить dataType в моем AJAX-посте, чтобы использовать json вместо html.

Я также просто передал отрисованный шаблон, поэтому мне не пришлось вызывать data["render_reply"].

        context = {
            'reply': reply,
            'post': post,
            'recipient': reply.recipient
        }

        rendered_template = render_to_string(
            template_name='journal/partials/reply-render-reply.html',
            context=context,
            request=request
        )

        return Response(rendered_template)
Вернуться на верх