DRF 是否不支持具有多部分/表单数据请求的嵌套序列化程序?



我想POST使用表单数据的请求,有一个嵌套的对象和一个文件,我找不到解决我的问题的方法。有没有人知道这是可能的,或者我必须写一些自定义的东西?

我试图发送一个文件使用FormData,也有一个JSON对象内的FormData对象。(我的客户端变量在JS中,我使用API调用我的其他API视图来获取所有信息,然后我将所有信息传递给JS中的客户端变量。变量,我将其字符串化并附加到我的FormData对象。)

我得到一个错误,说我的客户端是必需的,但我通过它。

有没有人知道我是否做错了什么,或者DRF只是不知道如何解析一个有嵌套对象的FormData对象。

我的JS代码:
$(document).ready(function () {

$('#form_add').submit(function (event) {
event.preventDefault();

let input_atasament = document.getElementById('input_atasament');
let client_pk   = $("#input_clienti").val();
let nr_data     = "test";
let tip         = $("#input_tip").val();
let obiectul    = $("#input_obiectul").val();
let termen      = $("#input_termen").val();
const url       = `/api/contract-post/`;
let client_url  = `/api/client-get/${client_pk}`;
let client      = $.ajax({    
url: client_url,
async: false,
dataType: 'json' 
}).responseJSON;

let client_string = JSON.stringify(client);

let data = new FormData();
data.append('nr_data', "test");
data.append('tip', tip);
data.append('obiectul', obiectul);
data.append('termen', termen);
data.append('atasament', input_atasament.files[0]);
data.append('client', client_string);
for(var p of data.entries())
{
console.log(p[1]);
}

var action = function(d) {
console.log(d);
};
$.ajax({
url: url,
data: data,
headers: {
'X-CSRFToken': csrftoken
},
type: "POST",
contentType: false,
processData: false,
success: action,
error: action
});
});
});

My API views:

@api_view(['POST'],)
def contract_post(request):

contract = Contract()

if request.method == 'POST':
serializer = ContractSerializer(contract, data=request.data)
data = {}
if serializer.is_valid():
serializer.create(validated_data=request.data)
handle_uploaded_file(request.FILES['atasament'])
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def handle_uploaded_file(f):
with open(f.name, 'wb+') as destination:
for chunk in f.chunks():
destination.write(chunk)

我的模型:

class Contract(models.Model):
TIPURI = (
('P', 'Proiectare'),
('E', 'Executie'),
('D', 'Documentatie'),
)
tip             = models.CharField(max_length=300, choices=TIPURI)
nr_data         = models.CharField(max_length=50)
obiectul        = models.TextField()
termen          = models.DateField(default=datetime.date.today)
atasament       = models.FileField(upload_to='main/documents/', blank=True, null=True) 
# For the moment it just need to set up stuff in settings, 
#  after that I should make a file server with a NFS share or something
client      = models.ForeignKey(Client, on_delete=models.SET_NULL, null=True)
def __str__(self):
return self.nr_data

class Meta:
verbose_name_plural = "Contracte"

我的序列化器:

class ContractSerializer(serializers.ModelSerializer):
client      = ClientSerializer(read_only=False)
termen      = serializers.DateField(format='%Y-%m-%d', default=datetime.date.today)
atasament   = serializers.FileField(max_length=None, allow_empty_file=True)
class Meta:
model   = Contract
fields  = (
'pk',
'tip',
'nr_data',
'obiectul',
'termen',
'atasament',
'client',
)


def create(self, validated_data):
client = validated_data.pop('client')
client_instance, created = Client.objects.get_or_create(**client)
contract_instance = Contract.objects.create(**validated_data, client=client_instance)
return client_instance

和我的形式:

<form id="form_add" enctype="multipart/form-data">
{% csrf_token %}
<div class="align-items-center">

<div class="form-group">
<label for="input_tip">Tip:</label>
<select class="form-control" name="input_tip" id="input_tip">
<option value="P">Proiectare</option>
<option value="E">Execuție</option>
<option value="D">Documentație</option>
</select>
</div>
<div class="form-group">
<label for="input_obiectul">Obiectul Contractului:</label>
<textarea class="form-control" name="Obiectul Contractului" id="input_obiectul" rows="3"></textarea>
</div>
<div class="form-group">
<label for="input_termen">Termen:</label>
<input type="date" class="form-control" id="input_termen" placeholder="Termen">
</div>
<div class="form-group">
<label for="input_atasament">Atașament:</label>
<input type="file" class="form-control" id="input_atasament">
</div>
<div class="form-group">
<label for="input_clienti">Client:</label>
<select name="input_clienti" class="form-control" id="input_clienti"></select>
<a class="btn btn-link"  style="font-size: normal; color: black; border: 1px solid grey; margin-top: 1em;" href="/clienti/add">Adaugă un client nou</a>
</div>
<div class="text-center alert alert-danger" hidden id="error_box">
</div>
<div class="text-center">
<button class="btn btn-primary" type="submit">Adaugă</button>
</div>
<div class="text-center" style="top: 10px;">
<a class="btn" href="/contracte">Înapoi</a>
</div>

</div>
</form>

我添加了我所有的代码,也许我做错了什么(很有可能)。

class A(Serializer):
pass
class B(Serializer):
nested_a = A(many=True, read_only=True)
nested_a_json = JsonField(write_only=True)
def validate_nested_a_json(self, value):
if not isinstance(value, list):
ValidationError("nested_a_json expects a list")
for item in value:
serializer = A(data=item)
serializer.is_valid(raise_exception=True)
return value

相关内容

  • 没有找到相关文章

最新更新