django - Django模型中的ManyToManyField
问题描述
我需要创建一组这样的模型:
class Step(models.Model):
field1 = models.CharField(max_length=50)
field2 = models.CharField(max_length=50)
class Scenario(models.Model):
name = models.CharField(max_length=50)
steps = models.ManyToManyField(Step, related_name="scenarios")
问题是我希望该场景按照我将指定的顺序包含几个步骤,甚至多次包含相同的步骤。像这样:
Scenario1:
step1
step2
step1
step3
我希望此步骤的顺序可以在管理站点中轻松编辑。我发现了filter_horizontal
,它看起来很像我在管理站点中需要的东西,但是它没有选择再添加一个步骤并上下移动步骤。
解决方案
计算机科学中有句谚语说:“计算机科学中的所有问题都可以通过另一个层次的间接性来解决”——大卫·惠勒。
在这种情况下,您应该使用“通过”表,例如:
class Step(models.Model):
field1 = models.CharField(max_length=50)
field2 = models.CharField(max_length=50)
class Scenario(models.Model):
name = models.CharField(max_length=50)
steps = models.ManyToManyField(
Step,
through='ScenarioStep',
related_name="scenarios"
)
class ScenarioStep(models.Model):
scenario = models.ForeignKey(
'Scenario',
on_delete=models.CASCADE,
related_name='scenariostep'
)
step = models.ForeignKey(
'Step'
on_delete=models.CASCADE,
related_name='scenariostep'
)
order = models.PositiveIntegerField()
class Meta:
ordering = ['order']
因此,我们在这里引入了一个额外的模型,它替换了已经由ManyToManyField
.
AScenario
因此有一个Step
,假设有一个ScenarioStep
记录,我们通过一个Order
字段对其进行排序。
例如,我们可以将给定的步骤添加到scenario
with:
s1 = Step.objects.create(field1='step1')
s2 = Step.objects.create(field1='step1')
s3 = Step.objects.create(field1='step1')
sc1 = Scenario.objects.create(name='Scenario1')
ScenarioStep.objects.create(order=1, scenario=sc1, step=s1)
ScenarioStep.objects.create(order=2, scenario=sc1, step=s2)
ScenarioStep.objects.create(order=3, scenario=sc1, step=s1)
ScenarioStep.objects.create(order=4, scenario=sc1, step=s3)
然后我们可以迭代这些步骤:
for step in sc1.steps.order_by('scenariostep'):
# ... (do something with the step)
pass
推荐阅读
- python - 如何定义类对象的新属性
- sql - 使用 Join 和 Window 函数获取结果
- python - 在数据框中填写缺失的天数并在 Python 中添加零值
- python - Django - 如何在模型中定义 MySQL CHAR 数据类型?
- vba - 每次我使用即时窗口时,MS Access 都会崩溃
- timescaledb - 具有非规范化日期列的基于时间的超表分区
- c# - 将指针传递给本机函数时出现 AccessViolationException
- c# - 尝试发布使用 PackageReference 的 WPF 时出错
- postgresql - 在 postgres 用户下运行的 2 个进程消耗非常高的 cpu
- c# - Rx .Net 触发基于对象日期时间属性的动作(即日期从未来传递到过去)