【发布时间】:2021-07-09 18:29:45
【问题描述】:
我遇到了一个相当神秘的 MultipleObjectsReturned 错误,该错误是在数周没有问题后突然出现的。我希望只是我缺少的一些简单的东西。
我有一个Order 模型,一个OrderLine 模型,它有一个Item 外键。每个Item 都有一个指向Product 的外键。以下是简化模型:
class OrderLine(models.Model):
order = models.ForeignKey(Order, related_name="lines", on_delete=models.CASCADE)
item = models.ForeignKey(Item, on_delete=models.SET_NULL, blank=True, null=True)
class Product(TimeStampedModel):
...
class Item(TimeStampedModel):
product = models.ForeignKey(Product, related_name='items', on_delete=models.CASCADE)
OrderLineForm 和 OrderLineAdmin 供参考:
class OrderLineForm(forms.ModelForm):
class Meta:
model = OrderLine
...
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['category'].queryset = ItemType.objects.all()
self.fields['product'].queryset = Product.objects.none()
self.fields['item'].queryset = Item.objects.none()
if self.instance.pk:
try: # When changing an existing OrderLine
...
current_item = Item.objects.filter(pk=self.instance.item.pk)
available_items = current_item.union(
get_available_items(...)
)
self.fields['item'].queryset = available_items
self.fields['category'].initial = item_type_id
except:
self.fields['item'].queryset = Item.objects.all()
...
@admin.register(OrderLine)
class OrderLineAdmin(admin.ModelAdmin):
form = OrderLineForm
现在,当我使用 Django 管理员编辑 OrderLine 时,它在 ModelChoiceField 查询集中具有多个 Item:
我在清理表单时收到以下错误:get() returned more than one Item -- it returned 2!
在仔细检查日志后,ModelChoiceField 似乎通过了正确的 Item id/pk,但 self.queryset.get(**{key:value}) 以某种方式从单个 id/pk 返回 2 个项目,即使项目有不同的 id/pks(49 和 50):
同样,只有当OrderLine 表单的Item 字段在查询集中有多个对象时才会发生这种情况。如果它只是一个Item,它保存得很好。任何想法为什么我现在收到此错误?谢谢!
我认为在数据库关系方面唯一发生变化的是我将formset.save_m2m() 添加到 Item 模型管理员,但是 Item 不是 m2m 关系,所以这可能导致一些数据库索引错误?
附:我从几年前发现了这个https://code.djangoproject.com/ticket/23354,它似乎引用了这个上下文中的错误,但票上说它已修复。
【问题讨论】:
-
我不太明白“OrderLine 在 ModelChoiceField 查询集中有多个项目”是什么意思?你能展示你的 ModelAdmin 吗?
-
@AbdulAzizBarkat 抱歉,我不知道如何简洁地说出这个词。我已将
OrderLineForm添加到OrderLineAdmin使用的问题中。在 OrderLineForm 初始化时,当前选择的Item和任何其他可用项目将作为self.fields['item'].queryset提供。因此,表单查询集可以包含 1 个或多个Items,并且当此查询集中有多个Item时,它当前会给出错误 -
我看到你在查询集上调用
union。请注意,根据文档,只能在结果查询集上调用特定方法(get不是其中之一)。如果没有union,就没有办法做到这一点吗?你能展示一下get_available_items到底做了什么吗? -
@AbdulAzizBarkat 就是这样!!!太感谢了。
get_available_items返回一个Items的查询集。由于当前正在编辑的OrderLine的Item在此查询集中不存在,因此我决定使用union将current_item与available items结合起来。当我移除工会时,它完美无缺。那么有没有不使用union的标准方法来组合QuerySets?
标签: django django-admin django-queryset modelform modelchoicefield