【问题标题】:Django Rest Framework- how to put complex SQL query in views.pyDjango Rest Framework - 如何将复杂的 SQL 查询放入 views.py
【发布时间】:2018-02-16 03:21:40
【问题描述】:

我在 Django Rest views.py 中放置 sql 查询时遇到了一些问题。

views.py

from rest_framework import generics
from ..models import Stat
from .serializers import StatSerializer

class StatListView(generics.ListAPIView):
    queryset = Stat.objects.raw("SELECT parameter1, COUNT(*) FROM 
               statistic_stat GROUP BY parameter1 order by count(*) desc 
               LIMIT 10")
    serializer_class = StatSerializer

序列化器.py

from rest_framework import serializers
from ..models import Stat

class StatSerializer(serializers.ModelSerializer):
    class Meta:
        model = Stat
        fields = ('parameter1', 'parameter2')

当我运行此代码时,我收到如下错误:“get() 返回了多个 Stat -- 它返回了 122!”

相同的查询在另一个脚本中运行(使用相同的数据库)并返回如下结果:

[('something1', 56), ('something2', 32), ('something3', 21), ('something4', 
19), ('something5', 10), ('something6', 8), ('something7', 4), ('something8', 
3), ('something9', 2), ('something10', 1)]

追溯

Environment:


Request Method: GET
Request URL: http://127.0.0.1:8000/api/author/

Django Version: 1.11.3
Python Version: 3.6.1
Installed Applications:
['django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'statistic',
 'rest_framework']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware']



Traceback:

File "C:\Users\310041180\AppData\Local\Continuum\Miniconda3\lib\site-packages\django\core\handlers\exception.py" in inner
  41.             response = get_response(request)

File "C:\Users\310041180\AppData\Local\Continuum\Miniconda3\lib\site-packages\django\core\handlers\base.py" in _get_response
  187.                 response = self.process_exception_by_middleware(e, request)

File "C:\Users\310041180\AppData\Local\Continuum\Miniconda3\lib\site-packages\django\core\handlers\base.py" in _get_response
  185.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "C:\Users\310041180\AppData\Local\Continuum\Miniconda3\lib\site-packages\django\views\decorators\csrf.py" in wrapped_view
  58.         return view_func(*args, **kwargs)

File "C:\Users\310041180\AppData\Local\Continuum\Miniconda3\lib\site-packages\django\views\generic\base.py" in view
  68.             return self.dispatch(request, *args, **kwargs)

File "C:\Users\310041180\AppData\Local\Continuum\Miniconda3\lib\site-packages\rest_framework\views.py" in dispatch
  489.             response = self.handle_exception(exc)

File "C:\Users\310041180\AppData\Local\Continuum\Miniconda3\lib\site-packages\rest_framework\views.py" in handle_exception
  449.             self.raise_uncaught_exception(exc)

File "C:\Users\310041180\AppData\Local\Continuum\Miniconda3\lib\site-packages\rest_framework\views.py" in dispatch
  486.             response = handler(request, *args, **kwargs)

File "C:\Users\310041180\AppData\Local\Continuum\Miniconda3\lib\site-packages\rest_framework\generics.py" in get
  201.         return self.list(request, *args, **kwargs)

File "C:\Users\310041180\AppData\Local\Continuum\Miniconda3\lib\site-packages\rest_framework\mixins.py" in list
  48.         return Response(serializer.data)

File "C:\Users\310041180\AppData\Local\Continuum\Miniconda3\lib\site-packages\rest_framework\serializers.py" in data
  739.         ret = super(ListSerializer, self).data

File "C:\Users\310041180\AppData\Local\Continuum\Miniconda3\lib\site-packages\rest_framework\serializers.py" in data
  263.                 self._data = self.to_representation(self.instance)

File "C:\Users\310041180\AppData\Local\Continuum\Miniconda3\lib\site-packages\rest_framework\serializers.py" in to_representation
  657.             self.child.to_representation(item) for item in iterable

File "C:\Users\310041180\AppData\Local\Continuum\Miniconda3\lib\site-packages\rest_framework\serializers.py" in <listcomp>
  657.             self.child.to_representation(item) for item in iterable

File "C:\Users\310041180\AppData\Local\Continuum\Miniconda3\lib\site-packages\rest_framework\serializers.py" in to_representation
  488.                 attribute = field.get_attribute(instance)

File "C:\Users\310041180\AppData\Local\Continuum\Miniconda3\lib\site-packages\rest_framework\fields.py" in get_attribute
  445.             return get_attribute(instance, self.source_attrs)

File "C:\Users\310041180\AppData\Local\Continuum\Miniconda3\lib\site-packages\rest_framework\fields.py" in get_attribute
  104.                 instance = getattr(instance, attr)

File "C:\Users\310041180\AppData\Local\Continuum\Miniconda3\lib\site-packages\django\db\models\query_utils.py" in __get__
  116.                 instance.refresh_from_db(fields=[self.field_name])

File "C:\Users\310041180\AppData\Local\Continuum\Miniconda3\lib\site-packages\django\db\models\base.py" in refresh_from_db
  696.         db_instance = db_instance_qs.get()

File "C:\Users\310041180\AppData\Local\Continuum\Miniconda3\lib\site-packages\django\db\models\query.py" in get
  384.             (self.model._meta.object_name, num)

Exception Type: MultipleObjectsReturned at /api/author/
Exception Value: get() returned more than one Stat -- it returned 877!

有什么想法或建议有什么问题吗? 提前谢谢你

【问题讨论】:

  • 您是否发布了所有的StatListView ?看起来那里有更多代码
  • 是的,就是这样。它适用于像“SELECT * FROM statistic_stat”这样的简单查询
  • 如果没有回溯,这只是猜测。可以提供一下吗?
  • 已添加。我可能已经尝试了一切:(
  • /api/author/ 真的是加载 StatListView 的端点吗?

标签: python sql django django-models django-rest-framework


【解决方案1】:

不确定这是否是正确的答案,因为我无法重现您遇到的错误,但这对我有用;

from rest_framework.generics import ListAPIView
from rest_framework import serializers

# you're not serializing a model and since you want to display that count I guess, I'd suggest changing the serializer to this.
class StatSerializer(serializers.Serializer):
    parameter1 = serializers.CharField(max_length=128, required=True)
    count = serializers.integerField(required=True)

    class Meta:
        fields = ('parameter1', 'count')

class StatListView(ListAPIView):
    queryset = Stat.objects.raw("SELECT parameter1, COUNT(*) FROM 
               statistic_stat GROUP BY parameter1 order by count(*) desc 
               LIMIT 10")
    serializer_class = StatSerializer

    def list(self, request):
        queryset = self.get_queryset()
        # the serializer didn't take my RawQuerySet, so made it into a list
        serializer = StatSerializer(list(queryset), many=True)
        return Response(serializer.data)

【讨论】:

  • 我尝试在 serializers.py 文件中运行此代码并收到错误“未定义名称 ListAPIView”
  • 我尝试更改为 generics.ListAPIView,但随后出现错误:“尝试在序列化程序 StatSerializer 上获取字段 count 的值时出现 AttributeError。序列化程序字段可能被命名不正确且不匹配 Stat 实例上的任何属性或键。原始异常文本为:'Stat' 对象没有属性 'count'。"
  • 添加导入以修复未定义的问题。 “Got AttributeError”看起来像您使用了模型序列化程序而不是基本序列化程序。您真的使用了 class StatSerializer(serializers.Serializer) 还是将其更改为 class StatSerializer(serializers.ModelSerializer) ?您应该为您的用例使用 serializers.Serializer。
猜你喜欢
  • 2020-06-24
  • 1970-01-01
  • 2013-11-17
  • 2023-03-30
  • 2012-08-03
  • 2022-11-13
  • 2021-06-07
  • 2016-09-30
  • 2018-10-16
相关资源
最近更新 更多