Django REST Framework:在列表响应中呈现表单元素
Posted
技术标签:
【中文标题】Django REST Framework:在列表响应中呈现表单元素【英文标题】:Django REST Framework: rendering form elements in list response 【发布时间】:2019-09-07 06:48:06 【问题描述】:如何使用 Django REST Framework 来呈现具有用户可编辑的特定字段的模型实例列表?
我使用 Django 几个月了,而 DRF 只用了几天。我尝试了几种不同的方法,但似乎无法理解它。
在使用 DRF 之前,我的工作流程是设置一个视图(和关联的 URL):查询我的模型,从 forms.py 中选择我的自定义表单(仅公开我需要的字段),将两者放在一起到字典中,并将其发送到模板。
然后,我可以在模板中循环遍历我的模型实例并设置我的可编辑字段,并根据需要通过 django 清晰的表单将它们传递给它们。
然后我可以通过 AJAX 获取请求调用此模板。
models.py
class Buyer(models.Model):
name = models.CharField(unique=True, max_length = 20)
class Item(models.Model):
name = models.CharField(unique=True, max_length = 50)
active = models.BooleanField(default=True)
bought_by = models.ForeignKey(Buyer, null=True, blank=True, to_field="name",)
views.py
class ItemViewSet(viewsets.ModelViewSet):
queryset = models.Item.objects.select_related("bought_by")
serializer_class= serializers.ItemSerializer
filterset_fields = ("bought_by")
序列化器.py
class ItemSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = models.Item
fields = "__all__"
extra_kwargs = "url": "view_name: "myapp:item-detail"
urls.py
router = routers.DefaultRouter()
router.register(r"items", views.ItemViewSet)
模板.html
% load static %
% load rest_framework %
<table id="item_table" class="table">
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col">Active</th>
<th scope="col">Buyer</th>
</tr>
</thead>
<tbody>
% for item in data %
<tr scope="row">
<td> item.name </td>
<td> item.active </td>
<td> item.bought_by </td>
</tr>
% endfor %
</tbody>
</table>
一些Js文件
function getData()
updateRequest = $.ajax(
type: "GET",
url: "myapp/items/",
success: function(data)
//....
);
第一种方法: 为 ItemViewSet 自定义 ListModelMixin 以呈现模板并传递序列化程序。大致如下:
def list(self,request, *args, **kwargs):
...
return Response ('data': queryset, 'serializer': serializer, template_name = "myapp/template.html")
然后在 template.html 中将 item.active 更改为:
<form action=" item.url " method="post">
% csrf_token %
render_form serializer
</form>
错误:序列化程序不可迭代。有道理。改为:
render_field item.bought_by
错误:需要“风格”,补充说。继续得到其他错误
第二种方法: 尝试修改 ListModelMixin 以收集序列化模型实例的字典,例如:
items= dict()
for item in queryset:
items[item] = serializers.ItemSerializer(item, data=request.data)
从未完全弄清楚这一点,因为 serializers.ItemSerializer(item, data=request.data) 似乎不是字典项,因此不能使用 data.items() 在模板中对其进行迭代。
很抱歉写了这么长的文章,但我有点不知所措,不太确定如何继续。
返回所有模型实例列表的最优雅的 DRF 方式是什么?
我总是可以使用较旧的方法,但感觉这里的 DRF 缺少一些明显的东西。
参考资料:
https://www.django-rest-framework.org/topics/html-and-forms/
Django Rest Framework serializers render form individually
Rendering a form with django rest framework's ModelViewSet class insead of APIView
【问题讨论】:
【参考方案1】:已解决
方法二最接近:有条件地选择一个渲染器并覆盖默认的 .list()。
views.py:
from rest_framework import renderers
from rest_framework.response import Response
class ItemViewSet(viewsets.ModelViewSet):
queryset = models.Item.objects.select_related("bought_by")
serializer_class= serializers.ItemSerializer
filterset_fields = ("bought_by")
renderer_classes = [renderers.JSONRenderer, renderers.BrowsableAPIRenderer, renderers.TemplateHTMLRenderer]
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
if request.accepted_renderer.format == "html":
items = list()
for item in queryset:
items.append("serializer": self.get_serializer(ticket), "item": item)
return Response(
"items_info": items,
"style": "template_pack": "rest_framework/inline/",
,
template_name="myapp/items_list.html",
)
else:
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
这将检查请求的 url 是否有 /?format=html suffix。如果是这样,它将序列化查询集中的每个项目,并在发送到 items_list.html 的字典(上下文)中包含 serializer:item 字典列表。
为了渲染字段,DRF 需要定义一个style。
如果格式后缀不是 html,或者没有指定,则优先使用 JSON 渲染器或 BrowsableAPI 渲染器(default renderers)。这样,我们的可浏览 API 和 JSON api 仍然可以轻松工作。
要使用每个实例可编辑的 buy_by 字段来呈现此内容,请按照以下几行修改您的模板(在本例中为 items_list.html):
% load static %
% load rest_framework %
% if items_info %
% csrf_token %
<table id="Items_Table" class="table">
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col">Active</th>
<th scope="col">Bought By</th>
</tr>
</thead>
<tbody>
% for pair in items_info %
<tr scope="row">
<td> pair.item.name </td>
<td> pair.item.active </td>
<td>
<form action="% url "myapp:item-detail" pair.item.pk %" method="PATCH">
% render_field pair.serializer.bought_by style=style %
</form>
</td>
</tr>
% endfor %
</tbody>
</table>
% else %
<p class="text-center">No items to show.</p>
% endif %
现在,在您的 GET 请求中,只需将“/?format=html”附加到 URL。
如果您使用 AJAX,则在发送 POST/PUT/PATCH/等时。请求,include the csrf token as described in the Django documentation。
【讨论】:
这有助于在模板中手动布局表单,而不是依赖于直接的 DRF 垂直/水平/等选项。 +1以上是关于Django REST Framework:在列表响应中呈现表单元素的主要内容,如果未能解决你的问题,请参考以下文章
如何从 django-rest-framework 中的文件列表中过滤图像
Django REST Framework:直接显示在 GenericView 的结果列表中
Django rest framework 之 DictField、ListField、自定义字段
如何在 Django REST Framework 中序列化“对象列表”