【问题标题】:How to save a nested relationship in django rest framework?如何在 django rest 框架中保存嵌套关系?
【发布时间】:2016-05-30 14:03:28
【问题描述】:

我正在尝试按照Django REST Framework guide 在 Django REST Framework 中保存嵌套关系,但我做不到。

我有一个类“Asiento”,它是另一个类“Apunte”的外键。当我得到每个“Asiento”时,Django REST Framework 会返回它们以及它们所有的“Apunte”对象。这可行,但是当我尝试使用可写嵌套序列化程序创建/更新“Asiento”时,我得到了AsientoSerializer(data=data).is_valid() == False

我的模型:

class Apunte(TxerpadBase):
    debe = models.DecimalField(null=True, blank=True, max_digits=18, decimal_places=6)
    haber = models.DecimalField(null=True, blank=True, max_digits=18, decimal_places=6)
    cuenta = models.ForeignKey(Cuenta, related_name='mayor', on_delete=models.PROTECT)
    partner = models.ForeignKey(Partner, null=True, blank=True, on_delete=models.PROTECT)
    asiento = models.ForeignKey(Asiento, related_name='apuntes')
    fecha = models.DateField()
    recc = models.BooleanField(blank=True, default=False)
    conciliacion = models.ForeignKey('Conciliacion', null=True, blank=True, on_delete=models.SET_NULL)
    estado = FSMField(default='borrador')


class Asiento(TxerpadBase):
    numero = models.PositiveIntegerField(null=True, blank=True)
    fecha = models.DateField(blank=True, default=datetime.datetime.now)
    libro = models.ForeignKey('Libro', on_delete=models.PROTECT)
    periodo = models.ForeignKey(Periodo, on_delete=models.PROTECT)
    estado = FSMField(default='borrador')

我的序列化器:

class ApunteSerializer(serializers.ModelSerializer):
    fecha = serializers.DateField(
        format='%d-%m-%Y', input_formats=('%d-%m-%Y',),
        error_messages={'invalid': 'La fecha del apunte no esta en el formato correcto.'}
    )

    class Meta:
        model = Apunte


class AsientoSerializer(serializers.ModelSerializer):
    fecha = serializers.DateField(
        format='%d-%m-%Y', input_formats=('%d-%m-%Y',),
        error_messages={'invalid': 'La fecha del asiento no esta en el formato correcto.'}
    )
    apuntes = ApunteSerializer(many=True)

    class Meta:
        model = Asiento

    def create(self, data):
        apuntes_data = data['apuntes']
        asiento_data = data
        asiento_data['fecha'] = datetime.datetime.strptime(asiento_data['fecha'], '%d-%m-%Y').date()
        del asiento_data['apuntes']
        asiento = Asiento.objects.create(**asiento_data)
        for apunte in apuntes_data:
            apunte['fecha'] = datetime.datetime.strptime(apunte['fecha'], '%d-%m-%Y').date()
            Apunte.objects.create(asiento=asiento, **apunte)

我的视图集:

class AsientoViewSet(viewsets.ModelViewSet):
    queryset = Asiento.objects.all()
    serializer_class = AsientoSerializer

    def create(self, validated_data):
        # JSON dictionary is inside validated_data.data
        serializer = AsientoSerializer(data=validated_data.data)
        if serializer.is_valid():
            return Response(serializer.data)
        else:
            raise AttributeError('Error al validar')

这是我随请求发送的 JSON:

{
    u'name': u'prueba 3000', 
    u'periodo': 13, 
    u'fecha': u'18-02-2016', 
    u'numero': None, 
    u'estado': u'borrador', 
    u'libro': 1, 
    u'apuntes': [
        {
            u'name': u'a', 
            u'recc': False, 
            u'debe': u'1', 
            u'haber': u'0.00', 
            u'cuenta': u'5', 
            u'partner': 8, u'fecha': 
            u'18-02-2016', 
            u'conciliacion': u''
        }
    ]
}

如果我调试代码,只有执行的“创建”方法是视图集的方法,但它不会从序列化程序运行“创建”方法。

使用此代码,我无法保存“Asiento”和“Apunte”。我究竟做错了什么?感谢您的任何回答!

我正在使用 python 2.7(由于外部原因无法更新)和 Django REST Framework 3.3.2。

【问题讨论】:

  • 您是否收到任何错误消息?

标签: python django python-2.7 django-rest-framework


【解决方案1】:

如果序列化无效,您应该做的第一件事是查看返回的消息 (serializer.data)。它将帮助您了解发生了什么问题。

我在这里的盲目猜测是您缺少与嵌套序列化程序相关的 queryset 参数。如果未设置,DRF 会将这些字段视为只读。

编辑:在 OP 版本之后,问题来自视图集。 如果序列化程序有效,您需要调用serializer.save()。 看看CreateMixin 是怎么做的。

【讨论】:

  • 我的 seriealizer.data 返回一个包含数据信息的字典。我不确定我错过了queryset 是什么意思。你建议我放什么?谢谢!
  • 我的意思是解释here。您能否提供 serializer.data 以便我们查看验证失败的位置?
  • 这就是我要做的serializer.data: {'apuntes': [{u'name': u'a', u'recc': False, u'debe': u'1 ', u'haber': u'0.00', u'cuenta': u'5', u'partner': 8, u'fecha': u'18-02-2016', u'conciliacion': u' '}],'periodo':13,'fecha':u'18-02-2016','numero':无,'estado':u'borrador','libro':1,'name':u' prueba 3000'}
  • 好的,您的自定义视图集是有原因的,我会相应地编辑我的答案。
  • 但是serializer.is_valid() 仍然是假的,所以它永远不会是serializer.save()
【解决方案2】:

好的,我发现我的问题是“Apunte”对象中的“asiento”属性不能为空,我没有发送它。现在,我已经更改了“Apunte”对象中的“asiento”属性,序列化程序终于可以工作了,并且不需要在 ViewSet 上使用“create”方法。

感谢大家的回答。

【讨论】:

    【解决方案3】:

    不确定这是否是解决方案。但是序列化程序的create 方法必须返回创建的对象。 尝试在最后一行添加return

    【讨论】:

    • 仍然无效。但是谢谢你,你说得对,我忘了放 return 声明。
    • 由于您只发送一个 Asiento,您应该删除 apuntes_data 上的循环。
    • Django REST Framwork 文档指定我必须首先创建“Asiento”,然后我必须循环“Apunte”对象作为“Apunte”的“asiento”字段传递给我刚刚创建的“Apunte” .所以我需要循环“Apunte”对象,不是吗?
    • 我想你误会了。您应该遍历 apuntes 创建,而不是 asiento
    • 我在“Asiento”创建中遍历“Apunte”对象。我不明白你。能不能说的具体点?
    猜你喜欢
    • 2014-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-28
    • 1970-01-01
    • 2017-02-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多