Django REST框架后端过滤React.js前端的问题



因此,我试图构建一个不那么简单的Todo应用程序,使用一些可能多余的实践和技术来展示开发技能。该应用程序是一种Trello复制品。后端是Django,它利用Django-REST框架来处理来自前端React.js的RESTful api请求。简而言之,我的Django_backend遇到了问题,可能特别是Django-REST框架,它似乎不喜欢被要求过滤其查询集。我已经尝试了几个django包以及DRF文档中描述的方法,我将对此进行详细说明,但我的尝试不起作用,我希望得到一些指导。非常感谢。

后端安装程序

我刚刚完成了redux传奇的实现,我有一些非常基本的传奇,可以获得每个模型的每个实例。但我显然不想请求每个实例,所以我们应该过滤响应。

Django REST框架使用诸如Serializer和ViewSets之类的内置类来返回模型实例的列表,REST框架可以用这些列表来响应请求。这些是我测试后端请求的初始视图集,它们都向我的前端返回了适当的JSON对象:视图集.py

from rest_framework import viewsets
from corkboard.models import Card, Stage, Board
from .serializers import CardSerializer, StageSerializer, BoardSerializer
# Card is the model for a "Todo" Instance
# Todo Cards viewset
class CardViewSet(viewsets.ModelViewSet):
queryset = Card.objects.all()
serializer_class = CardSerializer
# Stages of completion model viewsets
class StageViewSet(viewsets.ModelViewSet):
queryset = Stage.objects.all()
serializer_class = StageSerializer
# Board that "houses" all stages and cards
class BoardViewSet(viewsets.ModelViewSet):
queryset = Board.objects.all()
serializer_class = BoardSerializer

viewseturls.py:

from rest_framework import routers
from .views import CardViewSet, StageViewSet, BoardViewSet

# registering router paths for each of the viewsets
router = routers.DefaultRouter()
router.register('cards', CardViewSet, 'cards')
router.register('stages', StageViewSet, 'stages')
router.register('boards', BoardViewSet, 'boards')
urlpatterns = router.urls

并且这些url用于通过axios从前端进行的调用。最初,我尝试简单地将请求中的url从中更改

axios.get(`http://localhost:8000/api/cards)

axios.get(`http://localhost:800/api/cards/?stage=1`)

这个不同的url使用相同的JSON对象(所有卡实例,无论阶段如何)进行响应

查看DRF过滤文档,发现了一些似乎有用的过滤方法。它们涉及创建另一个视图类来覆盖get_queryset方法,如下所示:

from rest-framework import generics
class CardsFilteredByStageViewSet(generics.ListAPIView):
serializer_class = TodoSerializer
def get_queryset(self):
"""
This view should return a list of all the todo cards for
the stage as determined by the stage portion of the URL.
"""
stage = self.kwargs['stage']
return Card.objects.filter(stage=stage)

请注意,这涉及到使用

rest-framework.generics.ListAPIView

我也试着继承

views.ViewSets

在两者之后,我在urls.py:中编辑路由器url

from .views import StageCardViewSet
router.register('stage_cards', StageCardViewSet, 'stage_cards') 

然后尝试

http://localhost:8000/api/stage_cards/

http://localhost:8000/api/stage_cards/?stage=1

但两者都有KeyError:

Request Method: GET
Request URL:    http://localhost:8000/api/stage_cards/?stage=1
Django Version: 3.0.5
Exception Type: KeyError
Exception Value: 'stage'

DRF文档还提供了django-filter等包的源代码,安装似乎很顺利。我使用

pipenv install django-filter

正如你稍后在这篇文章中看到的,这个包出现在我的requirements.txt和我的Pipfile中,所以它肯定已经安装好了。它也被添加到django_backend.settings中。是的,"s"应该在下面的"django-filters"中:

INSTALLED_APPS = [
# confusing pluralization
'django-filters',
...
]
REST_FRAMEWORK = {
'DEFAULT_FILTER_BACKENDS': [
'django_filters.rest_framework.DjangoFilterBackend',
],
...
} 

如果它没有作为包添加,这应该会给出一个错误,对吗?

将其添加为已安装的应用程序后,开发现有的视图集(或通用列表,取决于您使用的内容)

from django_filters.rest_framework import DjangoFilterBackend #added
class CardViewSet(viewsets.ModelViewSet):
queryset = Card.objects.all()
serializer_class = CardSerializer
filter_backends = [DjangoFilterBackend] #added
filterset_fields = ['stage', 'id']      #added

但我得到了一个";无法导入";IDE中出现错误。探索这个错误发现了这篇文章,它建议添加django-rest框架过滤器,但在安装后,我立即开始收到关于没有adjango.utils.six的错误,我发现它已经从django>3,但对于django-rest框架过滤器是必需的。尽管其他一些文档提到许多d-r-r-f特性被添加回django过滤器中。删除/卸载d-r-f-f可以修复错误并允许服务器运行,但我仍然收到无法将django过滤器导入到我的视图集的红色下划线:

Unable to import 'django_filters.rest_framework'pylint(import-error)

在更新的视图中:

from django_filters.rest_framework import DjangoFilterBackend
#^^^ here is the unable to import error underline 

我只想过滤我的模型的实例,这样我就可以将相关信息返回到前端。请帮忙。

额外的,也许相关的信息

虽然我的项目也包含一个用于本地VDE的Pipfile,但它也有一个requirements.txt文件,用于安装Docker构建的依赖项。我把两者都包括在内
requirements.txt:

appdirs==1.4.3
asgiref==3.2.7
astroid==2.3.3
certifi==2019.11.28
distlib==0.3.0
Django==3.0.5
django-environ==0.4.5
django-filter==2.2.0
djangorestframework==3.11.0
filelock==3.0.12
isort==4.3.21
lazy-object-proxy==1.4.3
mccabe==0.6.1
pipenv==2018.11.26
pylint==2.4.4
pylint-django==2.0.15
pylint-plugin-utils==0.6
pytz==2019.3
six==1.14.0
sqlparse==0.3.1
virtualenv==20.0.2
virtualenv-clone==0.5.3
wrapt==1.11.2

Pipfile:

[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true
[dev-packages]
[packages]
appdirs = "==1.4.3"
asgiref = "==3.2.7"
astroid = "==2.3.3"
certifi = "==2019.11.28"
distlib = "==0.3.0"
djangorestframework = "==3.11.0"
filelock = "==3.0.12"
isort = "==4.3.21"
lazy-object-proxy = "==1.4.3"
mccabe = "==0.6.1"
pipenv = "==2018.11.26"
pylint = "==2.4.4"
pytz = "==2019.3"
six = "==1.14.0"
sqlparse = "==0.3.1"
virtualenv = "==20.0.2"
virtualenv-clone = "==0.5.3"
wrapt = "==1.11.2"
Django = "==3.0.5"
django-environ = "*"
django-filter = "*"
[requires]
python_version = "3.8"

django_backend:的Dockerfile

# Use an official Python runtime as a parent image
FROM python:latest
# Adding backend directory to make absolute filepaths consistent across services
WORKDIR /usr/src/app/django-backend
# Install Python dependencies
ADD requirements.txt .
RUN pip3 install --upgrade pip -r requirements.txt
# Add the rest of the code
ADD . .
# Make port 8000 available for the app
EXPOSE 8000
# Be sure to use 0.0.0.0 for the host within the Docker container,
# otherwise the browser won't be able to find it
CMD python3 manage.py runserver 0.0.0.0:8000

前端

前端是React.js,带有reduxredux-saga。我不认为它与这篇文章有关,因为在我开始更改django_backend中的代码之前,一切都很好

当然,如果我不够清楚,可以问任何问题,提前谢谢。

我的第一篇帖子最终是因为一个愚蠢的错误。我自己回答,因为为什么不呢。

pylint错误是一个很大的标志。这可能只是一个IDE配置问题,如果我能够用python manage.py runserver在本地主持而没有任何错误,那么您可能正确地实现了它。如果我得到的只是一个pylint错误,那么无论如何都要尝试运行它。正如您所说,它在删除django-rest框架过滤器后立即运行,没有任何错误。

我给出的代码部分似乎是django-filter的正确实现,因为DRF文档很好地解释了如何将其用于基本过滤。他们还推荐了另一个名为django-rest framework filters的包,如前所述,但我知道从django>3中删除django.utils.six存在问题。该线程的一条注释包括通过安装据称与Django 3.0.4兼容的six包进行的修复,因此我将探讨实例相互关系是否对过滤很重要。

事实上,我已经正确地执行了它。我的猜测是,我错过了它,因为在这个过程中有其他错误重叠,而pylint错误让我失去了嗅觉。我只是错过了它实际上在运行;我只是没有测试它的功能。我还想开始使用Stackoverflow作为开发资源,但通过这个过程我找到了答案。有趣的

重申正确的实施程序:

pipenv install django-filter

添加到django_backend.settings:


INSTALLED_APPS = [
# confusing pluralization
'django-filters',
...
]
REST_FRAMEWORK = {
'DEFAULT_FILTER_BACKENDS': [
'django_filters.rest_framework.DjangoFilterBackend',
],
...
} 

和重构视图集:

from django_filters.rest_framework import DjangoFilterBackend # added

# Todo Card viewset now filterable via filterset_fields
class CardViewSet(viewsets.ModelViewSet):
queryset = Card.objects.all()
serializer_class = CardSerializer
filter_backends = [DjangoFilterBackend]    # added
filterset_fields = ['stage', 'title', 'id']  # added

现在在python manage.py runserver之后转到正确的url(http://localhost:8000/api/cards/?stage=1)你应该只看到第一阶段的牌。同样的url结构也有望从前端调用。但是django-rest框架UI返回一个过滤列表。成功

通过转到我的IDE的settings.json文件(碰巧是VSCode,尽管我正在考虑替代方案)并调整如下,可以很容易地解决pylint错误:

{
"python.PythonPath": "/user/local/bin", // added
...
}

导入错误消失。

最新更新