python - Django REST 框架 : HTML render Generic APIView

标签 python html django rest django-rest-framework

我是 Django REST 框架的新手。我尝试做的是在 HTML 中呈现通用 APIView (RetrieveUpdateDestroyAPIView),类似于在 Browsable API 中自动呈现 ViewSet 的方式。

关注官方documentation ,我的 myApp/views.py 中有:

class AnnounceViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows announces to be viewed or edited.
    """
    queryset = Announce.objects.all()
    serializer_class = AnnounceSerializer
    permission_classes = (permissions.IsAuthenticatedOrReadOnly,
                          IsOwnerOrReadOnly,)


    def perform_create(self, serializer): # without this, the POST request of the announce doesnt work
        serializer.save(owner=self.request.user)


class AnnounceList(APIView):
    renderer_classes = [TemplateHTMLRenderer]
    template_name = 'myApp/announces_list.html'
    permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

    def get(self, request):
        queryset = Announce.objects.all()
        return Response({'announces': queryset})

class AnnounceDetail(generics.RetrieveUpdateDestroyAPIView):
   queryset = Announce.objects.all()
   serializer_class = AnnounceSerializer
   renderer_classes = [TemplateHTMLRenderer]
   template_name = 'myApp/announce_detail.html'
   permission_classes = (permissions.IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly,)

在我的 urls.py 中:

from django.conf.urls import url, include
from rest_framework import routers
from myApp import views
from django.contrib import admin


router = routers.DefaultRouter()
router.register(r'api/users', views.UserViewSet)
router.register(r'api/groups', views.GroupViewSet)
router.register(r'api/announces', views.AnnounceViewSet)

# Wire up our API using automatic URL routing.
# Additionally, we include login URLs for the browsable API.
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'', include('myApp.urls')),
    url(r'^', include(router.urls)),
    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
    url(r'^accounts/', include('allauth.urls')),
    url(r'^announces/$', views.AnnounceList.as_view(), name='announces-list'),
    url(r'^announces/(?P<pk>[0-9]+)/$', views.AnnounceDetail.as_view(), name='announce-detail'),

当我进入 Browsable API 时,通过链接/api/announces/3/,我可以正确地看到 announce 对象,根据经过身份验证的用户具有正确的权限。

但是当我转到/announces/3/时,出现了这个错误:

NoReverseMatch at /announces/3/

Reverse for 'announce-detail' with keyword arguments '{'pk': ''}' not found. 3 pattern(s) tried: ['announces/(?P<pk>[0-9]+)/$', 'api/announces/(?P<pk>[^/.]+)\\.(?P<format>[a-z0-9]+)/?$', 'api/announces/(?P<pk>[^/.]+)/$']

这是我的announce_detail.html 模板:

{% load rest_framework %}

{% block content %}

<form action="{% url 'announce-detail' pk=announce.pk %}" method="POST">
    {% csrf_token %}
    {% render_form serializer %}
    <input type="submit" value="Save">
</form>

{% endblock content %}

如果我理解得很好,Django REST View (无论是 ViewSet 还是 ViewAPI)用于以 JSON 格式检索/放置数据,而 Django 普通 View 用于 HTML 通常呈现。然而,Django REST View 也可以用于正常的 Django HTML 渲染。通过公开 API 端点,数据可以被其他应用程序(相同的网络应用程序或其他网络应用程序/移动应用程序等)检索和使用。如果我错了,请纠正我。

我不明白为什么我会收到错误... 感谢您的帮助!

更新 在创建一个普通的 APIView 之后,我设法呈现了表单,并且权限得到了很好的尊重(当用户尝试单击“保存”按钮时状态 403 禁止,当他/她不是所有者时。但是,字段仍然显示为“可修改”,即我们可以在区域内输入文本,但如果不是所有者进行修改,则保存按钮不会保存数据。

我的应用/views.py

class AnnounceDetail(APIView):  
    renderer_classes = [TemplateHTMLRenderer]
    template_name = 'myApp/announce_detail.html'
    permission_classes = (permissions.IsAuthenticatedOrReadOnly,
                          IsOwnerOrReadOnly,)



    def get(self, request, pk):
        announce = get_object_or_404(Announce, pk=pk)
        self.check_object_permissions(self.request, announce) # required for IsOwnerOrReadOnly to work fine see https://stackoverflow.com/questions/25554415/django-rest-framework-ignoring-my-isownerorreadonly-permissions
        serializer_context = {
            'request': Request(request),
        }
        serializer = AnnounceSerializer(announce, context=serializer_context)
        return Response({'serializer': serializer, 'announce': announce})

    def post(self, request, pk):
        announce = get_object_or_404(Announce, pk=pk)
        self.check_object_permissions(self.request, announce) # required for IsOwnerOrReadOnly to work fine see https://stackoverflow.com/questions/25554415/django-rest-framework-ignoring-my-isownerorreadonly-permissions
        serializer_context = {
            'request': Request(request),
        }
        serializer = AnnounceSerializer(announce, context=serializer_context, data=request.data)
        if not serializer.is_valid():
            return Response({'serializer': serializer, 'announce': announce})
        serializer.save()
        return HttpResponseRedirect(reverse('announces-list')) # redirect to URL that is associated with the name announces-list

最佳答案

views.py

from django.shortcuts import get_object_or_404
from rest_framework.response import Response

class AnnounceDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = Announce.objects.all()
    serializer_class = AnnounceSerializer
    renderer_classes = [TemplateHTMLRenderer]
    template_name = 'myApp/announce_detail.html'
    permission_classes = (permissions.IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly,)

    def retrieve(self, request, pk, *args, **kwargs):
        announce = get_object_or_404(Announce, pk=pk)
        serializer = self.get_serializer(announce)  # typo fixed
        return Response({'serializer': serializer, 'announce': announce})

announce_detail.html

{% load rest_framework %}
{% load staticfiles %}

{% block content %}

<form action="{% url 'announce-detail' pk=announce.pk %}" data-method="PUT">
    {% csrf_token %}
    {% render_form serializer %}
    <input type="submit" value="Save">
</form>

{% endblock content %}

<script>
    window.drf = {
        csrfHeaderName: "X-CSRFTOKEN",
        csrfCookieName: "csrftoken"
    };
</script>
<script src="{% static 'rest_framework/js/jquery-1.12.4.min.js' %}"></script>
<script src="{% static 'rest_framework/js/ajax-form.js' %}"></script>
<script src="{% static 'rest_framework/js/csrf.js' %}"></script>
<script src="{% static 'rest_framework/js/bootstrap.min.js' %}"></script>
<script src="{% static 'rest_framework/js/prettify-min.js' %}"></script>
<script src="{% static 'rest_framework/js/default.js' %}"></script>
<script>
    $(document).ready(function() {
        $('form').ajaxForm();
    });
</script>

关于python - Django REST 框架 : HTML render Generic APIView,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47375469/

相关文章:

javascript - 倾斜边框第 n 个子元素悬停

html - 为什么我的 div 背景围绕标题分开?

python - FacePy Facebook 帖子错误

python - 在Python中复制复合对象

javascript - 如何有多个下拉菜单

python - 没有 for 循环的 numpy 数组求和

python - 在django中迭代manyToOne关系执行数百个查询

javascript - 在整个文档中格式化整数千位分隔符

python - Tkinter 全屏应用

python - 从不同的目录调用多个 python 函数