在一个PUT/PATCH中更新多个数据库表
问题描述:
我正在用rest-framework-mongoengine编写一个django-rest-framework后端。到目前为止,我有两种类型的架构 - 用户和设备(Box)。来源如下:在一个PUT/PATCH中更新多个数据库表
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
我的目标是更新用户的buy_history
和recycle_history
更新Box
对象时。我该怎么做?
答
好吧,我已经找到了解决办法,显然这是超级简单,但如果有人有类似的困惑,这里的答案:
只是这是在嵌套对象设置这样username
得到user
。
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()
干杯
+0
尽管如果有人知道比'AuthenticationFailed()'更好的异常,请欢迎评论 –
和你在哪里的做数据库进入画面? – e4c5
为改变标题更适合 –
Kostya,你不应该为'EmbeddedDocuments'手动创建'EmbeddedDocumentSerializers',例如'RecycleHistory','BuyHistory'等等 - *'DocumentSerializer'会自动产生'我不确定,pre_save信号是否适用于EmbeddedDocument,会导致您在*文档上调用save(),而不是其嵌入式子JSON。 –