首页 > 解决方案 > Django 类视图 - MultipleObjectsReturned 错误

问题描述

我还是 django 的新手,所以请多多包涵。我正在尝试建立一个关于书籍的网站。现在我有这样的错误

MultipleObjectsReturned at /premium/1/ get() 返回了不止一本书——它返回了 2!

我不知道在哪里寻找错误。这是我的示例代码。

class PageDetailView(LoginRequiredMixin, generic.View):

    def get(self, request, *args, **kwargs):
        book = get_object_or_404(Book)
        page = get_object_or_404(Page)
        user_membership = get_object_or_404(Customer, user=request.user)
        user_membership_type = user_membership.membership.membership_type
        user_allowed = book.allowedMembership.all()
        context = {'object': None}
        if user_allowed.filter(membership_type=user_membership_type).exists():
            context = {'object': page}
        return render(request, "catalog/page_detail.html", context)

追溯:

内部 34 中的文件“C:\Users\admin\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\core\handlers\exception.py”。 response = get_response(request)

_get_response 126 中的文件“C:\Users\admin\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\core\handlers\base.py”。response = self.process_exception_by_middleware(e, request )

_get_response 124 中的文件“C:\Users\admin\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\core\handlers\base.py”。 response = Wrapped_callback(request, *callback_args, **callback_kwargs)

视图 68 中的文件“C:\Users\admin\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\views\generic\base.py”。 return self.dispatch(request, *args , **kwargs)

文件 "C:\Users\admin\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\contrib\auth\mixins.py" 在 dispatch 52. return super().dispatch(request, *args, **kwargs)

调度 88 中的文件“C:\Users\admin\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\views\generic\base.py”。返回处理程序(请求,*args,* *夸格斯)

获取 127 中的文件“C:\Users\admin\thesis\blackink_website\catalog\views.py”。book = get_object_or_404(Book)

get_object_or_404 中的文件“C:\Users\admin\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\shortcuts.py” 93. return queryset.get(*args, **kwargs)

获取 403 中的文件“C:\Users\admin\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\db\models\query.py”。(self.model._meta.object_name,数)

异常类型:MultipleObjectsReturned at /premium/1/ 异常值:get() 返回了不止一本书——它返回了 2!

如果信息不够,我会更新帖子。提前致谢。

更新

这是我的models.py

class Book(models.Model):


title = models.CharField(max_length=200) #i deleted some info to make it shorter

allowedMembership = models.ManyToManyField(Membership, blank=True)


def get_absolute_url(self):
    return reverse('book-detail',  args=[str(self.id)])

def __str__(self):
    return self.title

@property
def pages(self):
    return self.page_set.all()



class Page(models.Model):
book = models.ForeignKey(Book, on_delete=models.CASCADE, null=True)
file = models.FileField(upload_to='book_content', validators=[pdf_file_extension], help_text="PDF File Only")
timestamp = models.DateTimeField(default=timezone.now)


def __str__(self):
    return self.book.title

def get_absolute_url(self):
    return reverse('page-detail',   args=[str(self.id)])

page_detail.html

{% if user_membership and user_membership.user == request.user %}
        {% for content in book.pages %}
            <a href="{{ content.get_absolute_url }}" class="site-btn">Read</a>
        {% endfor %}
        {% else %}
        <button class="site-btn" disabled="disabled">VIP</button>
        {% endif %}

标签: djangodjango-views

解决方案


如果只需要一个对象,但返回多个对象,则查询会引发MultipleObjectsReturned异常。此异常的基本版本在django.core.exceptions中提供;每个模型类都包含一个子类版本,可用于识别已返回多个对象的特定对象类型。

我假设您使用的是最新的 Django 版本。通过从最底部切换官方站点,查看基于您自己版本的正确文档。

以下将是您的最佳链接。

像这样尝试,我没有测试过,但我相信它会像我之前测试过的那样工作。还要检查上面的文档,这足以解决这个问题。

根据https://docs.djangoproject.com/en/2.1/topics/class-based-...配置您的 url,这样您就可以通过page_id并且您的 url 模式应该类似于path('pages/<int:page_id>', PageDetailView.as_view())or re_path("^pages/(?<page_id>\d+)$", PageDetailView. as_view())

使用path()re_path()url()时要小心,因为它们有自己的风格 + 优势。

更新:

在查看了 Book(父模型)和 Page(子模型)之间的关系后,我将 urlpattern 从path('pages/<int:page_id>/books/<int:book'topath('pages/<page_id>和 id 更改为足以获取相关书籍,因为两个模型之间存在ForeignKey关系。

由于您的视图是PageDetailView,因此最好只传递页面的 id 以进行更好的设计,就像其他人建议的那样(您也可以根据要求传递几个 url 参数,但这里我们不需要)。

from django.http import Http404

class PageDetailView(LoginRequiredMixin, generic.View):

    def get(self, request, *args, **kwargs):
        try:
            # page = get_object_or_404(Page)
            page_id = self.kwargs["page_id"]
            page = Page.objects.get(pk=page_id) 

            # book = get_object_or_404(Book)
            book_id = page.book.pk
            book = Book.objects.get(pk=book_id)

            # user_membership = get_object_or_404(Customer, user=request.user)
            user_membership = Customer.objects.get(user=request.user)

            user_membership_type = user_membership.membership.membership_type
            user_allowed = book.allowedMembership.all()
            context = {'object': None}
            if user_allowed.filter(membership_type=user_membership_type).exists():
                context = {'object': page}
            return render(request, "catalog/page_detail.html", context)
        except Book.DoesNotExist:
            raise Http404("Book with id {0} does not exist".format(book_id))
        except Page.DoesNotExist:
            raise Http404("Page with id {0} does not exist".format(page_id))
        except Customer.DoesNotExist:
            raise Http404("Cutomer does not exist")
        except Exception as e: 
            raise Exception(str(e)) 

推荐阅读