Django - get()返回了多个主题

101

当我试图将一个具有M到M关系的属性与另一个属性相关联时,收到了以下错误信息:

get()返回了不止一个主题——它返回了2个!

你们能告诉我这是什么意思,也许提前告诉我如何避免这个错误吗?

models

class LearningObjective(models.Model):
    learning_objective=models.TextField()

class Topic(models.Model):
    learning_objective_topic=models.ManyToManyField(LearningObjective)
    topic=models.TextField()
< p > LearningObjective.objects.all() 的输出

[<LearningObjective: lO1>, <LearningObjective: lO2>, <LearningObjective: lO3>]
< p > Topic.objects.all() 的输出结果

[<Topic: Topic object>, <Topic: Topic object>, <Topic: Topic object>, <Topic: Topic object>, <Topic: Topic object>, <Topic: Topic object>, <Topic: Topic object>, <Topic: Topic object>, <Topic: Topic object>, <Topic: Topic object>, <Topic: Topic object>, <Topic: Topic object>, <Topic: Topic object>, <Topic: Topic object>]

观点

 def create_themen(request):
     new_topic=Topic(topic=request.POST['topic'])
     new_topic.save()
     return render(request, 'topic.html', {'topic': topic.objects.all()})

 def create_learning_objective(request):
     new_learning_objective=LearningObjective(learning_objective=request.POST['learning_objective'])
     new_learning_objective.save()
     new_learning_objective_topic=Topic.objects.get(topic=request.POST['topic'])
     new_learning_objective_topic.new_learning_objective_topic.add(new_learning_objective)
     return render( request, 'learning_objective.html', {
                    'topic': Topic.objects.all(),
                    'todo': TodoList.objects.all(),
                    'learning_objective': LearningObjective.objects.all()
                  })

1
请提供更多的代码。 - Kamil Rykowski
5
请发出您需要翻译的英文句子。 - Yeray Diaz
9个回答

207

get() 返回了多个主题 -- 它返回了2个!

上述错误表明,在使用 get() 进行查询时,您传递的特定参数在数据库中有多条记录。

Model.objects.get(field_name=some_param)

为了避免未来出现这种错误,您需要根据您的模式设计进行查询。 在您的情况下,您设计了一个多对多关系的表格,所以显然该字段将有多个记录,这就是您出现上述错误的原因。
因此,您应该使用filter()而不是get(),它将返回多个记录。例如:
Model.objects.filter(field_name=some_param)

请阅读有关如何在Django中进行查询的 这里

23

get()方法返回单个对象。如果没有现有的对象可返回,则会收到<class>.DoesNotExist。如果查询结果返回多个对象,则会得到MultipleObjectsReturned。您可以在这里查看有关get()方法查询的更多详细信息。

同样,如果get()查询匹配多个项目,Django将报错。在这种情况下,它会引发MultipleObjectsReturned异常,它是模型类本身的属性。

M2M将返回与之相关的任意数量的查询。在这种情况下,您可以使用查询接收零个、一个或多个项。

您可以使用以下内容在您的模型中:

for _topic in topic.objects.all():
    _topic.learningobjective_set.all()

您可以使用_set在M2M上执行选择查询。在上述情况下,您将过滤与每个主题相关的所有learningObjective


6

get()方法应该返回一个且仅一个记录,要解决这个问题可以使用 filter() 方法,然后从返回的queryset中获取第一个元素来获得你期望的对象,同时,在取出第一个元素之前,检查至少是否返回了一条记录,以避免抛出 IndexError 异常。


1
是的 topicresults = topic.objects.filter(topic='主题') if topicresults: topicresult = topicresults[0] - lmc

6

我有同样的问题,解决方案是 obj = ClassName.objects.filter()


4
在你的Topic模型中,允许多个元素具有相同的topic字段。你已经创建了两个具有相同字段的元素。
topic=models.TextField(verbose_name='Thema')

现在,当尝试添加一个新的“learningObjective”时,您似乎只想将其添加到与表单匹配的一个“Topic”中。由于有多个具有相同“topic”字段的“Topic”,因此“get”找到了2个,因此出现了异常。
您可以将“learningObjective”添加到所有具有该“topic”字段的“Topic”中:
for t in topic.objects.filter(topic=request.POST['Thema']):
    t.learningObjectivesTopic.add(neuesLernziel)

或者限制Topic模型拥有唯一的topic字段,并继续使用get,但这可能不是您想要的。


好的,你的解决方案两种方式都有效,唯一字段当然有效,但不是我想要的,这一点你是对的 :) 而且 for 循环也像魅力一样工作。 - BoJack Horseman

0

在没有主键或唯一标识对象的情况下,使用此选项来获取单个记录。

XYZ.objects.filter(model_attribute=your_value)[0]

这将返回一个与.get()相同的普通对象。


0
补充CrazyGeek的答案,只有在数据库中存在一个对象实例时,getget_or_create查询才有效,filter用于两个或更多对象。
如果查询可以是单个或多个实例,则最好将ID添加到div并使用if语句。
def updateUserCollection(request):
    data = json.loads(request.body)
    card_id = data['card_id']
    action = data['action']

    user = request.user
    card = Cards.objects.get(card_id=card_id)

    if data-action == 'add':
        collection = Collection.objects.get_or_create(user=user, card=card)
        collection.quantity + 1
        collection.save()

    elif data-action == 'remove':
        collection = Cards.objects.filter(user=user, card=card)
        collection.quantity = 0
        collection.update()

注意:对于更新多个对象,.save() 变成了 .update()。希望这能帮助到某些人,这让我头疼了一整天。

0
使用.filter然后使用.latest按照主键选择来从筛选出的对象中获取一个对象
tempobj = Flattable()
        try:
             tempobj = Flattable.objects.filter(org_address__icontains=row[5]).latest('pk')
        except Flattable.DoesNotExist:
             tempobj = None

-1

不要这样做:

xyz = Blogs.objects.get(user_id=id)

使用方法:

xyz = Blogs.objects.all().filter(user_id=id)

1
为了提高这个答案的质量,您可以向我们解释为什么您的代码是更好的选择以及他们做错了什么。您的回答非常简短,可以至少包括一句话,说明您认为这是更好的方法。 - Tyler2P

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接