Skip to main content
 首页 » 编程设计

python之Django Rest Framework XML之与 Django 模型相比,使用不同的 xml 名称字段创建多个对象

2025年05月04日24softidea

我正在向 Django (1.6.11) Rest Framework (3.0.5) 发送一个包含以下信息的 XML 文件(我无法控制该文件)。

<?xml version="1.0" encoding="utf-8"?> 
<Company xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
  <Invoices> 
    <Invoice> 
      <Id /> 
      <Number>150</Number> 
      <Date>2012-11-20</Date> 
      <InvoiceItems> 
        <Item> 
          <Sku>MAT</Sku> 
          <Description>Example description</Description> 
          <Total>10</Total> 
        </Item> 
        <Item> 
          <Sku>RMS</Sku> 
          <Description>Example description 2</Description> 
          <Total>10</Total> 
        </Item> 
      </InvoiceItems> 
      <Carriage> 
        <Sku /> 
        <UnitPrice>20</UnitPrice> 
      </Carriage> 
      <ItemsTotal>50</ItemsTotal> 
    </Invoice> 
  </Invoices> 
</Company> 

如何遍历这些项目 (Invoices>Invoice>InvoiceItems>Items>) 并保存链接到其 Invoice 模型的每个对象 (Item)?

models.py 
 
class Invoice(models.Model): 
 
    id = models.CharField(primary_key=True,max_length=10) 
    invoice_date = models.DateTimeField() 
    total = models.DecimalField(max_digits=10, decimal_places=2, default=0) 
    items = models.ForeignKey('Item', blank=True, null=True, related_name='items') 
    carriage = models.ForeignKey('Carriage', blank=True, null=True, related_name='carriage') 
 
class Item(models.Model): 
 
    item_sku = models.CharField(max_length=100, blank=True) 
    item_description = models.CharField(max_length=400, blank=True) 
    item_total = models.DecimalField(max_digits=10, decimal_places=2, default=0) 
 
class Carriage(models.Model): 
 
    carriage_sku = models.CharField(max_length=100, blank=True) 
    carriage_price = models.DecimalField(max_digits=10, decimal_places=2, default=0) 
 
views.py 
 
@api_view(['POST']) 
@parser_classes((XMLParser,)) 
def zynk_upload(request, format=None): 
 
    if request.method == 'POST': 
        data = request.data       
        serializer = InvoiceSerializer(data=data) 
        if serializer.is_valid(): 
            serializer.save() 
            return Response(serializer.data, status=status.HTTP_201_CREATED) 
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) 
 
serializer.py 
 
class InvoiceSerializer(serializers.HyperlinkedModelSerializer): 
 
    class Meta: 
        model = Invoice 
        fields = ('id', 'invoice_date', 'total', 'carriage','items') 
 
    def to_internal_value(self, data): 
 
        id = data['Invoices']['Invoice']['Number'] 
        invoice_date = data['Invoices']['Invoice']['Date'] 
        total = data['Invoices']['Invoice']['ItemsTotal'] 
        carriage_sku = data['Invoices']['Invoice']['Carriage']['Sku'] 
        carriage_price = data['Invoices']['Invoice']['Carriage']['UnitPrice'] 
        item_sku = data['Invoices']['Invoice']['InvoiceItems']['Item']['Sku'] 
        item_description = data['Invoices']['Invoice']['InvoiceItems']['Item']['Description'] 
        item_total = data['Invoices']['Invoice']['InvoiceItems']['Item']['Total'] 
 
        return { 
            'id': id, 
            'invoice_date': invoice_date, 
            'total': total, 
            'carriage': { 
                        'carriage_sku': carriage_sku, 
                        'carriage_price': carriage_price, 
                    }, 
            'items': { 
                        'item_sku':item_sku, 
                        'item_description': item_description,  
                        'item_total': item_total,                       
                    }, 
        } 
 
    def create(self, validated_data):         
        carriage_data = validated_data.pop('carriage') 
        carriage_id = Carriage.objects.create(**carriage_data) 
        items_data = validated_data.pop('items') 
        items_id = Item.objects.create(**items_data) 
        return Invoice.objects.create(carriage=carriage_id, items=items_id,**validated_data) 

请您参考如下方法:

如果字段名称不同,我相信您可以通过类范围变量指定映射到/从名称:

class InvoiceSerializer(serializers.HyperlinkedModelSerializer): 
    my_xml_name = serializers.CharField(source='my_django_name') 
    [...] 
    class Meta: 
        [...] 
        fields = ([...], 'my_xml_name') 

More documentation on explict field names can be found here.