我正在使用Django构建项目的后端,并使用Vuejs构建前端。
我已经在Django中定义了模型,并使用Django表单将数据保存到模型中。对于单个表单,我只需在POST请求的主体中传递一个JSON对象。这工作得很好。
但是现在我需要同时保存多个记录。我发现Django模型表单集可以做到这一点。但是,我不知道如何格式化POST请求。 Django文档假定我将使用Django模板(这很烦人),因此对请求本身的格式一无所知。
该应用程序是API文档工具,我需要允许用户定义API的参数。到目前为止,我有以下内容:
from django.forms import modelformset_factory
from docs.models import ApiParams
ParamsFormSet = modelformset_factory(ApiParams, exclude=('param_id',))
def create_params(request):
body_unicode = request.body.decode('utf-8')
body = json.loads(body_unicode)
formset = ParamsFormSet(body)
instaces = formset.save()
return HttpResponse(instances)
我使用以下数据调用了此API:
[
{
"api": 2,
"param_name": "param1",
"param_type": "string",
"param_required": true,
"param_sample": "param"
},
{
"api": 2,
"param_name": "param2",
"param_type": "numeric",
"param_required": false,
"param_sample": "3"
}
]
但这会导致以下错误:
Internal Server Error: /create-params/
Traceback (most recent call last):
File "D:\Documents\django\api-docs\venv\lib\site-packages\django\core\handlers\exception.py", line 34, in inner
response = get_response(request)
File "D:\Documents\django\api-docs\venv\lib\site-packages\django\core\handlers\base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File "D:\Documents\django\api-docs\venv\lib\site-packages\django\core\handlers\base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "D:\Documents\django\api-docs\venv\lib\site-packages\django\views\decorators\csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "D:\Documents\django\api-docs\docs\views.py", line 47, in create_api_params
if formset.is_valid():
File "D:\Documents\django\api-docs\venv\lib\site-packages\django\forms\formsets.py", line 308, in is_valid
self.errors
File "D:\Documents\django\api-docs\venv\lib\site-packages\django\forms\formsets.py", line 288, in errors
self.full_clean()
File "D:\Documents\django\api-docs\venv\lib\site-packages\django\forms\formsets.py", line 329, in full_clean
for i in range(0, self.total_form_count()):
File "D:\Documents\django\api-docs\venv\lib\site-packages\django\forms\formsets.py", line 112, in total_form_count
return min(self.management_form.cleaned_data[TOTAL_FORM_COUNT], self.absolute_max)
File "D:\Documents\django\api-docs\venv\lib\site-packages\django\utils\functional.py", line 48, in __get__
res = instance.__dict__[self.name] = self.func(instance)
File "D:\Documents\django\api-docs\venv\lib\site-packages\django\forms\formsets.py", line 91, in management_form
if not form.is_valid():
File "D:\Documents\django\api-docs\venv\lib\site-packages\django\forms\forms.py", line 180, in is_valid
return self.is_bound and not self.errors
File "D:\Documents\django\api-docs\venv\lib\site-packages\django\forms\forms.py", line 175, in errors
self.full_clean()
File "D:\Documents\django\api-docs\venv\lib\site-packages\django\forms\forms.py", line 376, in full_clean
self._clean_fields()
File "D:\Documents\django\api-docs\venv\lib\site-packages\django\forms\forms.py", line 388, in _clean_fields
value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))
File "D:\Documents\django\api-docs\venv\lib\site-packages\django\forms\widgets.py", line 258, in value_from_datadict
return data.get(name)
AttributeError: 'list' object has no attribute 'get'
P.S。我的问题与Vuejs没有任何关系,只是为了避免人们建议Django模板解决方案而提到Vuejs。我向Postman提出了上述POST请求,甚至还没有将API与我的前端集成。
答案 0 :(得分:1)
因此,让我们看看是否在DRF中执行此操作。我假设您的ApiParam模型是这样的:
_param_types = ["string", "integer", "array", "object"]
PARAM_TYPE_CHOICES = [(t, t) for t in _param_types]
class ApiParam(models.Model):
api = models.ForeignKey(Api, on_delete=models.CASCADE, related_name="parameters")
param_name = models.CharField(max_length=100)
param_type = models.CharField(max_length=10, choices=PARAM_TYPE_CHOICES)
param_required = models.BooleanField(default=False)
param_sample = models.TextField()
序列化为:
class ApiParamSerializer(serializers.ModelSerializer):
class Meta:
model = ApiParam
fields = [ # Explicit > Implicit
"param_name",
"param_type",
"param_required",
"param_sample"
]
从标题中的表单集来看,您对有效负载的意图似乎是使用其他参数更新Api模型,该参数是反向外键甚至是ManyToMany。
在这种情况下,最好将有效载荷构造为:
{
"api": 2,
"parameters": [
{
"param_name": "param1",
"param_type": "string",
"param_required": true,
"param_sample": "param"
},
{
"param_name": "param2",
"param_type": "numeric",
"param_required": false,
"param_sample": "3"
}
]
}
您的ApiSerializer将是:
class ApiSerializer(serializers.ModelSerializer):
api = serializers.IntegerField(source='api_id')
parameters = ApiParamSerializer(many=True)
class Meta:
model = Api
fields = ["api", "parameters"]
您的看法:
class ApiUpdateView(generics.UpdateAPIView):
serializer_class = ApiSerializer
我们应该做。如您所见,这都是声明性的。繁重的工作由Django / DRF完成。这需要一点时间来适应,但是一旦四分之一下降,它就非常简单。