Django类视图-MultipleObjectsReturned错误

时间:2019-03-18 15:36:40

标签: django django-views

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

  

MultipleObjects返回/ 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)
  

跟踪:

     

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

     

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

     

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

     

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

     

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

     

文件   “ C:\ Users \ admin \ AppData \ Local \ Programs \ Python \ Python37-32 \ lib \ site-packages \ django \ views \ generic \ base.py”   在派遣中     88. return handler(请求,* args,** kwargs)

     

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

     

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

     

文件   “ C:\ Users \ admin \ AppData \ Local \ Programs \ Python \ Python37-32 \ lib \ site-packages \ django \ db \ models \ query.py”   在得到     403.(self.model._meta.object_name,num)

     

异常类型:MultipleObjects在/ premium / 1 /返回   值:get()返回了不止一本书-它返回了2!

如果信息不足,我将更新帖子。预先感谢。

更新

这是我的模型。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 %}

2 个答案:

答案 0 :(得分:1)

如果仅预期一个对象,但返回多个对象,则查询会引发

MultipleObjectsReturned 异常。 django.core.exceptions 中提供了此异常的基本版本。每个模型类都包含一个子类版本,可用于标识已返回多个对象的特定对象类型。

  

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

以下是最适合您的链接。

只需尝试这样,我还没有测试过,但是我相信它会像我之前已经测试过的那样工作。另外,请查看上面的文档,足以消除此问题。

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

  

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

更新:

在研究Book(父模型)和Page(子模型)之间的关系之后,我将urlpattern从path('pages/<int:page_id>/books/<int:book'更改为path('pages/<page_id>,并且page 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)) 

答案 1 :(得分:0)

出现此错误的原因是因为您使用get_object_or_404来获得一本单本,但是问题是您的查询返回了多本图书。当您用来查找书籍的字段上没有唯一约束时,通常会发生这种情况(例如,通过 title 获取对象,“ Jungle Book”将返回具有相同标题的两本书)。

要解决此问题,请使用保证唯一的字段(例如 id )来获取对象。例如:

urls.py

path('page-details/<str:book_id>/<str:page_id>/', PageDetailView.as_view(), name='page_details'),

views.py

class PageDetailView(LoginRequiredMixin, generic.View):
    def get(self, request, *args, **kwargs):
        book = get_object_or_404(id=kwargs['book_id'])
        page = get_object_or_404(id=kwargs['page_id'])
        [...]