【问题标题】:What is the best method for retrieving all objects associated with a foreign key using Django rest_framework?使用 Django rest_framework 检索与外键关联的所有对象的最佳方法是什么?
【发布时间】:2021-07-08 01:14:07
【问题描述】:

我有一个 React 应用程序,我在其中使用 Django+REST 作为 API 和后端。在前端,我发送一个 POST 请求来创建一个 Job 模型并运行该作业。在响应中,我检索了新 Job 对象的 ID。

axios.post('http://127.0.0.1:8000/api/jobs/', query)
 .then((resp) => {
   setActiveJobs([...activeJobs, resp.data.id])
 }, (error) => {
   console.log(error)
 })   

当作业完成运行时,它会创建多个通过 ForeignKey 关联的 Result 对象。这是我的两个模型:

class Job(models.Model):
    query = models.CharField(max_length=255, blank=True, null=True)
    status = models.CharField(max_length=10, blank=True, null=True)

class Result(models.Model):
    job = models.ForeignKey(Job, blank=False, null=False, on_delete=models.CASCADE)
    result_no = models.IntegerField(blank=False, null=False)
    ... more fields

我在 Django 中使用 rest_framework 使用Job 的 ID 发送 GET 请求以获取与其关联的所有 Result 的列表时遇到问题。我尝试为retrieve(self, request, pk=None)get_queryset(self) 提供自定义实现,但到目前为止我的方法还没有奏效。理想情况下,我想调用诸如localhost:8000/api/results/15 之类的url,其中15 将是创建的Job 的对象ID。如果有 5 个 Result 对象将 job ForeignKey 字段设置为 ID 为 15Job 对象,则响应中将返回这 5 个 Results 的列表。

我解析的views.py和urls.py如下:

views.py

class ResultsView(viewsets.ModelViewSet):
    serializer_class = ResultSerializer
    queryset = Result.objects.all()

    # one potential solution could be along the lines of this? Does not work tho
    def get_queryset(self):
        job_id = self.kwargs['pk']
        queryset = self.queryset.filter(job = job_id)
        return queryset

urls.py

router = routers.DefaultRouter()                   
router.register(r'results', views.ResultsView, 'my_project')

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include(router.urls)),
    # re_path('^api/results/(?P<job>.+)/$', views.ResultsView),
]

我认为尝试将整数 ID 与作为对象的 ForeignKey 字段匹配可能存在问题,但是当我查看 localhost:8000/api/results/ 时,我能够看到 ForeignKey 字段 job 被列为的对象一个普通的整数。

这样的任务有合适的模式吗?

【问题讨论】:

标签: django rest django-rest-framework django-views


【解决方案1】:

我相信您需要在 get_queryset 中使用除 pk 以外的 queryparam 或 kwarg,因为基于 pk 的基本检索方法过滤器

def get_queryset(self):
  queryset = Result.objects.all()
  job_id = self.request.query_params.get('job_id')
  if job_id is not None:
      queryset = queryset.filter(job=job_id)
  return queryset
 #OR
def get_queryset(self):
  job_id = self.kwargs['job_id']
  queryset = self.queryset.filter(job = job_id)
  return queryset

如果你没有使用查询参数,urls.py中的路由器需要更改为

router.register('results/(?P<job_id>.+)', ResultsView)

但是,更好的方法是使用相关名称来检索具有特定工作 ID 的所有结果。你可以在 JobView 中做这样的事情

@action(detail="False")
def result_list(self,request, pk):
  job = Job.objects.get(id=pk)
  result_qs = job.result_set.all()
  serializer = ResultSerializer(result_qs, many=True)
  return Response(serializer.data)

这个网址是 /api/jobs/1/result_list/。此处未定义相关名称,因此默认为 result_set。但是我们可以在 Result 模型中定义它。

【讨论】:

    【解决方案2】:
    class ResultsView(viewsets.ModelViewSet):
        serializer_class = ResultSerializer
        queryset = Result.objects.all()
    
        # one potential solution could be along the lines of this? Does not work tho
        def get_queryset(self):
            job_id = self.kwargs['pk']
            queryset = self.queryset.filter(job = job_id)
            return queryset
    

    这里的问题是self.kwargs['pk'] 是 Result 的 id,而不是 Job。

    这里有两种可能的解决方案:

    1. 接受带有您的视图的查询参数,以便请求可以指定带有http://localhost:8000/api/results/?job_id=1 之类的作业ID。我建议使用django-filter 以最少的代码量和高度的灵活性来做到这一点。

    2. @action 添加到您的JobsView,这样您就可以像http://localhost:8000/api/jobs/1/results/ 这样的请求来获取给定工作的所有请求。

    【讨论】:

      猜你喜欢
      • 2013-09-03
      • 1970-01-01
      • 1970-01-01
      • 2018-05-23
      • 2012-09-14
      • 2011-06-22
      • 1970-01-01
      • 2010-12-02
      • 2012-12-03
      相关资源
      最近更新 更多