【发布时间】:2020-01-22 17:48:36
【问题描述】:
概念
首先,我有一个非常复杂的模型......这个想法是建造一艘星际飞船作为模型。所以每艘船都有一个类型(ship_type),它基于这个船型的蓝图。因此,当您创建 Ship 时,您必须决定模型应该使用哪个 ship_type(外键)。
因为我想改变一艘船(例如:购买另一个软件)而不是蓝图本身,所以每艘船在数据库中都有与蓝图船相同的字段(都继承自 ShipField )。当有人设置ship_type或更改它时,我希望Django去蓝图获取所有信息并覆盖船的信息。所以我尝试在 save 方法中完成这个行为。
函数和错误搜索
我写的函数总是在self.ship_type有变化的时候触发,目前为止还不错。而且所有“正常”字段也都发生了变化,只有多对多字段不起作用。
我投入其中并感到困惑。让我们假设我们的船在self.software 中没有条目,但新的ship_type 有3。如果我在保存(1.)之前打印出self.software,我得到了一个空查询集。当我在 super.save (2.) 之后执行此操作时,我得到了一个包含三个元素的查询集。所以它似乎一切正常。但是如果我在管理菜单中查看飞船,飞船根本没有软件。
结论
所以我的结论是,在保存方法之后的某个地方(可能在 post_save 事件中),软件又被删除了......此时我需要一些帮助。
想法
我希望你们明白我在这里想要做什么。我不是数据库专家,可以想象有更好的方法来实现这一点,所以我愿意接受彻底的改变。
模型(简化):
class ShipFields(models.Model):
body = models.ForeignKey(to=Body, verbose_name="Body", on_delete=models.SET_NULL,
null=True, blank=False, default=None)
software = models.ManyToManyField(Software, default=None, blank=True)
...
class ShipBlueprints(ShipFields, models.Model):
class Meta:
ordering = ['name']
verbose_name = "Ship Blueprint"
verbose_name_plural = "Ship Blueprints"
class Ship(ShipFields, models.Model):
name = models.CharField(max_length=256, unique=True)
ship_type = models.ForeignKey(to=ShipBlueprints, on_delete=models.SET_NULL, null=True)
...
__original_ship_type = None
def __init__(self, *args, **kwargs):
super(Ship, self).__init__(*args, **kwargs)
self.__original_ship_type = self.ship_type
def save(self, force_insert=False, force_update=False, *args, **kwargs):
# check if the ship type is changed
if self.ship_type != self.__original_ship_type:
...
# copy all fields from the related ShipBlueprints to the fields of Ship
# 1.
print(self.software.all())
self.body = self.ship_type.body
self.software.set(self.ship_type.software.all())
# or
# for soft in self.ship_type.software.all():
# self.software.add(soft)
# 2.
print(self.software.all())
...
super(Ship, self).save(force_insert, force_update, *args, **kwargs)
# 2.
print(self.software.all())
print(Ship.objects.get(name=self.name).software.all())
self.__original_ship_type = self.ship_type
我想我缩小了问题的范围。当我通过管理员更改 ship_type 时,many_to_many_fields 不会更新。 但是当我通过 django shell 更改 ship_type 时,它可以完美运行!
当我在视图中使用表单时,它也可以工作。所以我的代码工作得很好,但管理页面在某种程度上是问题......对我来说没关系,但它看起来像管理员保存方法中的错误,也许我会报告这个。
谢谢大家的意见。
【问题讨论】:
-
我认为问题可能是您在添加软件 set() 后没有调用
save()。所以我认为可能发生的是 self.software 正在内存中更新,而不是在数据库中。这就是为什么你在打印而不是在 django 管理员上看到它的原因。尝试在 Django 文档中搜索.add()方法:docs.djangoproject.com/en/3.0/topics/db/examples/many_to_many 如果对您有帮助,请告诉我,以便我将其作为答案。 -
首先感谢您的提示。我之前尝试过添加:
[selft.software.add(soft) in selft.ship_type.software.all()]但最后还是一样。save()所以你想说我必须先保存软件然后再添加它?我什么时候必须拯救他们?并且在软件模型中的数据库中肯定存在过 -
我现在尝试了这个:
self.software.save()(在set()之后)但我得到一个错误:'ManyRelatedManager' 对象没有属性'save'
标签: django django-models many-to-many