python - APIView的POST方法中的Django Rest Framework验证
问题描述
我是 DRF 的新手,正在尝试构建一个 rest api,我需要为任务执行创建一个 api,而不仅仅是为 CRUD,这就是为什么我将 APIView 的 POST 方法覆盖为:
class DeploymentsList(viewsets.ModelViewSet):
queryset = DeploymentOnUserModel.objects.all()
serializer_class = DeploymentonUserSerializer
def create(self, request, *args, **kwargs):
"""overwrite this for extra actions"""
serializer = self.serializer_class(data=request.data)
if serializer.is_valid(raise_exception=True):
print('valid request')
serializer.save()
return Response(serializer.data)
else:
print('Something invalid')
return Response('Invalid request')
模型.py:
services = (
('Single', 'Single'),
('Multiple', 'Multiple'),
)
class DeploymentOnUserModel(models.Model):
deployment_name = models.CharField(max_length=256, )
credentials = models.TextField(blank=False)
project_name = models.CharField(max_length=150, blank=False)
project_id = models.CharField(max_length=150, blank=True)
cluster_name = models.CharField(max_length=256, blank=False)
zone_region = models.CharField(max_length=150, blank=False)
services = models.CharField(max_length=150, choices=services)
configuration = models.TextField()
routing = models.TextField()
def save(self, **kwargs):
if not self.id and self.services == 'Multiple' and not self.routing and not self.configuration:
raise ValidationError("You must have to provide routing for multiple services deployment.")
super().save(**kwargs)
序列化程序.py:
class DeploymentonUserSerializer(serializers.ModelSerializer):
model = DeploymentOnUserModel
fields = '__all__'
readonly_fields = 'pk'
网址.py:
app_name = 'deployments'
urlpatterns = [
path('deployments/', apiview.DeploymentsList.as_view({'get': 'list', 'post': 'create'}), name='deployment_list'),
path('deployments/<int:pk>', apiview.DeploymentDetail.as_view(), name='deployment_detail')
]
错误返回:
AttributeError:“str”对象没有属性“values”
更新:完整追溯
Internal Server Error: /api/v1/deployments/
Traceback (most recent call last):
File "/Users/abdul/KontainerApi/lib/python3.6/site-packages/django/core/handlers/exception.py", line 35, in inner
response = get_response(request)
File "/Users/abdul/KontainerApi/lib/python3.6/site-packages/django/core/handlers/base.py", line 128, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/Users/abdul/KontainerApi/lib/python3.6/site-packages/django/core/handlers/base.py", line 126, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Users/abdul/KontainerApi/lib/python3.6/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "/Users/abdul/KontainerApi/lib/python3.6/site-packages/rest_framework/viewsets.py", line 95, in view
return self.dispatch(request, *args, **kwargs)
File "/Users/abdul/KontainerApi/lib/python3.6/site-packages/rest_framework/views.py", line 494, in dispatch
response = self.handle_exception(exc)
File "/Users/abdul/KontainerApi/lib/python3.6/site-packages/rest_framework/views.py", line 454, in handle_exception
self.raise_uncaught_exception(exc)
File "/Users/abdul/KontainerApi/lib/python3.6/site-packages/rest_framework/views.py", line 491, in dispatch
response = handler(request, *args, **kwargs)
File "/Users/abdul/PycharmProjects/KontainerApi/deployments/apiview.py", line 15, in create
serializer.is_valid(raise_exception=False)
File "/Users/abdul/KontainerApi/lib/python3.6/site-packages/rest_framework/serializers.py", line 236, in is_valid
self._validated_data = self.run_validation(self.initial_data)
File "/Users/abdul/KontainerApi/lib/python3.6/site-packages/rest_framework/serializers.py", line 435, in run_validation
value = self.to_internal_value(data)
File "/Users/abdul/KontainerApi/lib/python3.6/site-packages/rest_framework/serializers.py", line 459, in to_internal_value
fields = self._writable_fields
File "/Users/abdul/KontainerApi/lib/python3.6/site-packages/django/utils/functional.py", line 36, in __get__
res = instance.__dict__[self.name] = self.func(instance)
File "/Users/abdul/KontainerApi/lib/python3.6/site-packages/rest_framework/serializers.py", line 370, in _writable_fields
field for field in self.fields.values()
AttributeError: 'str' object has no attribute 'values'
[27/Jun/2018 16:11:41] "POST /api/v1/deployments/ HTTP/1.1" 500 15073
但我不知道如何验证请求?当我覆盖 APIView 的 POST 方法时。
发布数据:
{
"deployment_name": "dep5",
"credentials": "cre4",
"project_name": "pro4",
"project_id": "004",
"cluster_name": "clus4",
"zone_region": "zon4",
"services": "Single",
"configuration": "conf4",
"routing": "route4"
}
解决方案
目前还不是很清楚你想要实现什么。
我会说您希望在收到请求并验证输入数据后执行其他任务。
虽然不确定您想要执行什么样的任务以及何时 - 在保存模型之前或之后。
但是您可以在创建模型之前像这样进行创建:
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
**.... your task - access to data via serializer.validated_data....**
self.perform_create(serializer)
return Response(serializer.data)
或者如果您想在创建模型后执行某些操作,您可以覆盖 perform_create (正如我们从 create 方法的实现中看到的,它在输入被验证后被调用)
def perform_create(self, serializer):
instance = serializer.save()
.... your task ....
更新以解决问题“AttributeError:'str'对象没有属性'values'”
问题在于您对 viewset 的使用 - Viewset 为您提供了一个“资源控制视图”,您可以使用它来列出、检索、更新、删除资源。
您不需要在 urlconf 中为列表/创建和详细信息显式注册视图。
相反,使用路由器类执行此操作,它将为您提供所有视图(包括细节):
router = DefaultRouter()
router.register(r'deployment', DeploymentsList, base_name='deployment')
urlpatterns = router.urls
现在你可以这样做:
- GET部署/
- 发布部署
- 获取部署/{id} -> 详细信息
您遇到的另一个问题是验证。我不建议在模型的保存功能中提高 ValidationError。
有一个序列化程序来处理您的验证,您可以在 DeploymentUserSerializer 的 validate 函数中执行此操作
def validate(self, attrs):
# perform your validation here
return attrs
推荐阅读
- python - 使用函数制作“折叠列表”
- c# - 如何创建带参数的函数以在对象列表中查找特定对象
- javascript - 如何在 Chrome 或 Firefox 中监控或分析 DOM 更新?
- c# - 在 SqlBulkCopy.WriteToServer 异常上查找失败的行并通过省略那些失败的行来重试 SqlBulkCopy
- excel - Excel 数据表示,轴标签非数字
- mysql - 如何在 MySQL 中循环遍历 JSON 数据
- python - 如何为 forms.ChoiceField() 设置默认值?
- c# - 可变结构作为成员变量,用于序列化/JSON 生成中的性能
- arrays - 如何使用迭代器创建一个循环,该迭代器将只使用不同的计数器运行相同的命令 - 在 PowerShell 中
- confluent-platform - 将查询推送到 ksqlDB,而不是在第一个结果行中返回最终结果