【问题标题】:updating multiple database tables in one PUT/PATCH在一个 PUT/PATCH 中更新多个数据库表
【发布时间】:2016-11-30 03:17:47
【问题描述】:

我正在用 rest-framework-mongoengine 编写一个 django-rest-framework 后端。到目前为止,我有 2 种类型的模式 - 用户和设备(框)。来源如下:

models.py:

from __future__ import unicode_literals

import datetime
from mongoengine import Document, connect, EmbeddedDocument, fields, DynamicDocument
from django.db import models

# Create your models here.
from mongoengine import signals

connect('yourdb', alias='default')

class GPS(EmbeddedDocument):
    lat = fields.FloatField(null=False, required=True)
    lon = fields.FloatField(null=False, required=True)


class PPM(EmbeddedDocument):
    time = fields.DateTimeField(default=datetime.datetime.now())
    value = fields.IntField(null=False, required=True)

    @classmethod
    def pre_save(cls, sender, document, **kwargs):
        document.time = datetime.datetime.now()


signals.pre_save.connect(PPM.pre_save, sender=PPM)

class BuyHistory(EmbeddedDocument):
    time = fields.DateTimeField(default=datetime.datetime.now())
    boxid = fields.StringField(max_length=128, null=False, required=True)
    username = fields.StringField(max_length=128, null=False, required=True)
    product = fields.StringField(max_length=128, null=False, required=True)
    amount = fields.IntField()

    @classmethod
    def pre_save(cls, sender, document, **kwargs):
        document.time = datetime.datetime.now()


signals.pre_save.connect(BuyHistory.pre_save, sender=BuyHistory)

class RecycleHistory(EmbeddedDocument):
    time = fields.DateTimeField(default=datetime.datetime.now())
    boxid = fields.StringField(max_length=128, null=False, required=True)
    username = fields.StringField(max_length=128, null=False, required=True)
    amount = fields.IntField()

    @classmethod
    def pre_save(cls, sender, document, **kwargs):
        document.time = datetime.datetime.now()


signals.pre_save.connect(RecycleHistory.pre_save, sender=RecycleHistory)

class Box(Document):
    boxid = fields.StringField(max_length=128, null=False, required=True)
    gps = fields.EmbeddedDocumentField(GPS, required=True)
    buy_history = fields.EmbeddedDocumentListField(BuyHistory, default='[]')
    recycle_history = fields.EmbeddedDocumentListField(RecycleHistory, default='[]')
    ppm_history = fields.EmbeddedDocumentListField(PPM, default='[]')

class User(Document):
    username = fields.StringField(max_length=128, null=False, required=True)
    rfid = fields.StringField(max_length=32, null=False, required=True)
    buy_history = fields.EmbeddedDocumentListField(BuyHistory)
    recycle_history = fields.EmbeddedDocumentListField(RecycleHistory)

serializers.py:

from rest_framework_mongoengine import serializers
from models import User, BuyHistory, Box, RecycleHistory, PPM

class UserSerializer(serializers.DocumentSerializer):
    class Meta:
        model = User
        fields = ('username', 'rfid', 'buy_history', 'recycle_history')


class PPMSerializer(serializers.DocumentSerializer):
    class Meta:
        model = PPM
        fields = ('time', 'value')


class BuyHistorySerializer(serializers.EmbeddedDocumentSerializer):
    class Meta:
        model = BuyHistory
        fields = ('time', 'boxid', 'username', 'product', 'amount')


class RecycleHistorySerializer(serializers.EmbeddedDocumentSerializer):
    class Meta:
        model = RecycleHistory
        fields = ('time', 'boxid', 'username', 'product', 'amount')


class BoxSerializer(serializers.DocumentSerializer):
    class Meta:
        model = Box
        fields = ('id', 'boxid', 'gps', 'buy_history', 'recycle_history', 'ppm_history')

    def update(self, instance, validated_data):
        buy = validated_data.pop('buy_history')
        recycle = validated_data.pop('recycle_history')
        ppm = validated_data.pop('ppm_history')
        updated_instance = super(BoxSerializer, self).update(instance, validated_data)

        for buy_data in buy:
            updated_instance.buy_history.append(BuyHistory(**buy_data))
        for recycle_data in recycle:
            updated_instance.recycle_history.append(RecycleHistory(**recycle_data))
        for ppm_data in ppm:
            updated_instance.ppm_history.append(PPM(**ppm_data))
        updated_instance.save()
        return updated_instance

我的目标是在更新Box 对象时更新用户的buy_historyrecycle_history。我该怎么做?

【问题讨论】:

  • 数据库在哪里出现??
  • 尝试将标题更改为更合适的内容
  • Kostya,您不应该为EmbeddedDocuments 手动创建EmbeddedDocumentSerializers,例如RecycleHistoryBuyHistory 等 - 顶级DocumentSerializer 会自动生成它们。我不确定pre_save 信号是否适用于EmbeddedDocuments,因为您在顶级文档上调用save(),而不是它们的嵌入式子json。
  • @Bob 谢谢,我已经注释掉了EmbeddedDocuments 的序列化程序,它工作得很好。我只是按照这个手册。对于pre-save 信号 - 它或多或少有效,但是后续更新的时间戳很奇怪 - 它们之间的差异以微秒为单位,但一般时间戳是正确的。
  • @ConstantineSamoilenko 序列化器工作得很好。不幸的是,我玩信号的时间还不够长,无法理解为什么时间戳会与现实不同,但感谢您的通知。

标签: python django django-rest-framework mongoengine restframeworkmongoengine


【解决方案1】:

好的,我找到了一个解决方案,显然它非常简单,但如果有人有类似的困惑,这就是答案:

只需将userusername 一起设置在这样的嵌套对象中即可。

for buy_data in buy:
    buy_history_s = BuyHistory(**buy_data)
    try:
        user = User.objects.get(username=buy_history_s.username)
    except errors.DoesNotExist:
        raise exceptions.AuthenticationFailed()
    if buy_history_s.time is None:
        buy_history_s.time = datetime.datetime.now()
    updated_instance.buy_history.append(buy_history_s)
    user.buy_history.append(buy_history_s)
    user.save()

干杯

【讨论】:

  • 虽然如果有人知道比AuthenticationFailed()更好的例外,欢迎评论
猜你喜欢
  • 2016-06-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-09
  • 2023-04-07
  • 2012-10-16
  • 1970-01-01
  • 2018-04-10
相关资源
最近更新 更多