【问题标题】:How can I do a bulk_create in django REST Framework with nested models?如何使用嵌套模型在 django REST Framework 中进行 bulk_create?
【发布时间】:2015-05-23 14:12:02
【问题描述】:

我对 DRF 比较陌生,我正试图找出这个问题,它似乎与我能找到的所有文档略有不同。在我的玩具示例中,假设我在一个模型中有数十万条人的记录,另一个模型拥有所有汽车,另一个模型拥有所有其他财产:

class Person(models.Model):
    first_name = models.CharField()
    last_name = models.CharField()
    zipcode = models.IntegerField()
    favorite_color = models.CharField()
    class Meta:
        unique_together = ('first_name', 'last_name', 'zipcode', 'favorite_color')

class Car(models.Model):
    person = models.ForeignKey(Person)
    carmake = models.CharField()
    carmodel = models.CharField()
    VIN = models.CharField()

class OtherProperty(models.Model):
    person = models.ForeignKey(Person)
    prop_type = models.CharField()
    prop_value = models.Integer()

假设我已经将所有人员加载到数据库中。现在我有一大批新的万人购买新车的记录。有的人买了多辆车,有的人没有买车。我想制作一个功能强大的 API 并使客户端程序保持简单,所以我想直接上传(通过 POST 调用)所有新车购买。诀窍是客户端程序没有每个 Person 记录的唯一主键。所以,我希望客户端提交一个类似这样的 json POST:

[ {'person' : {'first_name':'Joe', 
               'last_name': 'Smith',
               'zipcode': 80110,
               'favorite_color': 'Blue'},
   'carmake' : 'Subaru',
   'carmodel' : 'Outback',
   'VIN' : 12345123123},
  {'person' : {'first_name':'Amy', 
               'last_name': 'Adams',
               'zipcode': 92075,
               'favorite_color': 'White'},
   'carmake' : 'BMW',
   'carmodel' : '325ic',
   'VIN' : 987165334},
   .... 10,000 more records... ]

现在,我有一个解决方案,我使用 views.py 读取 request.data,验证 Person 字段是否存在经过验证的内容,将 QuerySet 写入 Person 模型以加载所有 Person 主键进入字典,如果不是所有的 Person 实例都已经存在,则返回错误。然后我根据 request.data 制作一个新的字典,但所有的人子字典都替换为新找到的主键。然后我调用 CarSerializer,它有一个使用 django 函数 bulk_create 的 list_serializer_class 的 Meta 字段(根据文档:http://www.django-rest-framework.org/api-guide/serializers/#customizing-multiple-create)。这行得通。

但是,我认为 Person 查找代码不属于 Car ViewSet,对吧?而且,我可能重复了很多 django/DRF 已经在验证方面所做的工作。此外,现在我需要将该代码复制并粘贴到 OtherProperty ViewSet 以执行相同的 Person 主键查找。实际上,我有更多的模型对 Person 模型具有 ForeignKey,我知道我不应该复制/粘贴所有主键查找和验证代码。

所以,我的问题是,我可以将 Person 主键查找代码放在哪里?这似乎是序列化程序应该做的事情,但我不想保存任何新的 Person 实例。而且,由于我正在创建大量“Cars”(或“OtherProperty”)实例,我需要将其作为 ListSerializer (bulk_create) 调用,所以我认为我不能仅仅依靠嵌套关系并期望它工作。我错过了一个明显的解决方案吗?

感谢您的任何建议。

编辑

我有几个想法作为潜在的解决方案:

  1. 创建一个未附加到 Person 模型的 PersonLookup 序列化程序。该序列化程序将具有 Person 字段,接收完整的 request.data 并使用序列化程序功能进行验证,但随后不会创建任何记录,而是返回带有 PK 的原始 request.data 而不是详细的 Person 信息,以便返回的数据可以由 ViewSet 处理并发送到 Car 或 OtherProperty Serializers。

  2. 向 Person 模型添加一个唯一字段,该字段是所有非唯一字段的下划线分隔连接。然后客户端将能够通过连接创建这些字段,并且 request.data 不会被嵌套。实际上,这可能行不通,因为 bulk_create 将需要主键,而不是一些唯一字段,我认为(?)。另一个问题是,我会将所有 Person 字段存储两次,一次存储在唯一名称中,另一次存储在单个字段中。也许有一个经理技巧来解决这个问题。

【问题讨论】:

标签: django-rest-framework


【解决方案1】:

所以我认为我不能仅仅依靠嵌套关系并期望它起作用。

不,你不能。因为 DRF(从 3.0 版开始)不再支持任何类型的嵌套创建/更新(参见 'Writable nested serialization'

至于你的问题,你做的方式就是要走的路。唯一可能的改进是缓存您的 Person pks,以供进一步使用。这样,您只需在创建 Cars 时访问数据库一次。之后,将从缓存中检索每个 Person 的 pk。

希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 2017-05-22
    • 1970-01-01
    • 1970-01-01
    • 2019-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多