gpt4 book ai didi

python - 从内存中的数据初始化属于 ManyToManyField 的对象

转载 作者:太空宇宙 更新时间:2023-11-03 15:10:23 25 4
gpt4 key购买 nike

我正在处理数据库模型的实例,我需要从内存中的数据构造对象(使用 Python 风格的 o = Object() 而不是 ModelClass.objects .create()。是否将数据保存在数据库中将在稍后调用 o.save() 时决定。

这些模型有一个 ManyToManyField 并拥有许多子对象。问题是,在实际保存子对象之前,我无法将 add() 添加到 ManyToManyField 中。我怎样才能以以后可以调用 save() 的方式构造这些对象?我发现的这个问题的每一个潜在解决方案实际上都没有达到我想要的效果。

下面是一些示例代码,展示了我正在尝试做的事情:

class Author:
# ...
@classmethod
def create(cls, data):
# ...
pass

class Book(models.Model):
title = models.CharField(max_length=128)
pages = models.PositiveIntegerField()
authors = models.ManyToManyField(Author)

@classmethod
@transaction.atomic
def create(cls, data):
try:
with transaction.atomic():
b = cls(title=data["title"],
pages=data["pages"])

# This works, but has an unwanted side effect: authors are saved to the database
# as they're created here while the Book is not saved.
b.authors = Author.objects.bulk_create([Author.create(a) for a in data["authors"]])
return b

except Exception:
# ...
raise

################### Later on...
# This data is NOT static - it's formed from JSON which comes from an API. Just is here as an example.
data = {
"title": 1,
"pages": 934,
"authors": [
{
"name": "John Smith",
# ...
}
]
}

# We're going to use this now, but we're unsure if we want to actually save
# the object to the database.
b = Book.create(data)

# Save the data to the database if we want to.
b.save()

最佳答案

我能想到的唯一解决方案是将操作排队并在您调用 save() 时执行它们。

class PostponedOpMixin(models.Model):
def __init__(self, *args, **kwargs):
self._postponed_ops = []
super(PostponedOpMixin, self).__init__(*args, **kwargs)

def _getattr(self, attr):
result = self
for part in attr.split('.'):
result = getattr(result, part)
return result

def postpone(self, op, *args, **kwargs):
if self.pk: # execute now if self already has a pk
return self._getattr(op)(*args, **kwargs)
self._postponed_ops.append((op, *args, **kwargs))

def save(self, *args, *kwargs):
super(PostponedOpMixin, self).save(*args, **kwargs)
while self._postponed_ops:
op, args, kwargs = self._postponed_ops.pop(0):
self._getattr(op)(*args, **kwargs)

def Meta:
abstract = True

这样你就可以做到:

class Book(PostponedOpMixin):
...
authors = models.ManyToManyField(Author)
...

instance = Book()
instance.title = "Romeo and Juliet"
instance.postpone('authors.add', shakespeare)
...

# and some time later:
instance.save()

此代码未经测试,旨在作为起点。任何错误都留给读者作为练习。

关于python - 从内存中的数据初始化属于 ManyToManyField 的对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27550458/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com