如何在 DRF 中查询相关对象 viewsets.ModelViewSet

How to query related object in DRF viewsets.ModelViewSet

我有一个与数据表一起使用的序列化模型(作业)。 “工作”模型与另一个模型(Board)相关,这就是我的问题所在。我按照文档 here 过滤了与当前正在查看的“Board”模型相关的作业,但我无法使其按预期工作。

models.py

class Board(models.Model):
    name = models.CharField(_('board name'), max_length=256)
    slug = models.SlugField(_('unique url'), null=True, blank=True)
...


class Job(models.Model):
    board = models.ForeignKey(Board, on_delete=models.CASCADE, verbose_name=_('board'))
...

views.py

 class JobDataTablesViewSet(viewsets.ModelViewSet):
        queryset = Job.objects.all().order_by('-date_posted')
        serializer_class = JobDatatablesSerializer
        filter_backends = (DatatablesFilterBackend,)
        filterset_class = JobGlobalFilter
    
        def get_queryset(self):
            slug = self.kwargs['slug']
            queryset = Job.objects.filter(board__slug=slug)
            return queryset

urls.py

path('<slug:slug>/', views.BoardPublicView.as_view(), name='public-board')

您必须为 ForeignKey 查找提供 __。所以,get_queryset 方法就像:

slug = models.SlugField(
    unique=True,
    default=self.slug, # This is not from the tutorial, it's a modification
    # to demonstrate here.
    max_length=13,
)

def get_queryset(self):
    slug = self.kwargs['slug']
    queryset = Job.objects.filter(board__slug=slug)
    return queryset

有类似问题的朋友请看一看alanjds/drf-nested-routers。这就是我使用的并且效果很好。

这是我所做的概述。

使用 pip install drf-nested-routers 安装软件包后。

根据文档,

It is not needed to add this library in your Django project's settings.py file, as it does not contain any app, signal or model.

在我的应用 urls.py 文件中,我创建了父路由器和子路由器

router = routers.SimpleRouter()
router.register(r'boards', views.BoardViewSet, basename="boards_api_list")

boards_router = routers.NestedSimpleRouter(router, r'boards', lookup='board')
boards_router.register(r'jobs', views.JobViewSet, basename='board_jobs_list')

urlpatterns = [
    path('api/', include(router.urls)),
    path('api/', include(boards_router.urls)),
]

然后在我的 serializers.py 中,我创建了一个 HyperlinkedModelSerializer

class BoardSerializer(serializers.HyperlinkedModelSerializer):
    owner = UserSerializer()
    jobs = NestedHyperlinkedRelatedField(
        many=True,
        read_only=True,
        view_name='jobs_view_name',
        parent_lookup_kwargs={'slug': 'board__slug'}
    )

    class Meta:
        model = Board
        fields = [...]
        extra_kwargs = {
            'url': {'view_name': 'my_custom_view_name', 'lookup_field': 'slug'},
            ...other desired kwargs...
        }

class JobViewSet(serializers.ModelSerializer):
    ...standard serializer settings...

我继续 views.py 创建我的视图集并添加了 get_queryset 参数

class JobViewSet(viewsets.ModelViewSet):
    queryset = Job.objects.all().order_by('-date_posted')
    serializer_class = JobSerializer
    filter_backends = (DatatablesFilterBackend,)
    filterset_class = JobGlobalFilter

    def get_queryset(self):
        return Job.objects.filter(board__slug=self.kwargs['board_slug'])

完成这些操作后,您应该能够通过

访问您的 API
/parent_url/{{parent_pk}}/child_list/{{child_pk}}

现在,由于我的特殊需要(我想在数据表上使用它来过滤相关对象),我将 API 的 URL 添加到 base.html 的头部,以便可以加载 URL动态,因为我无法在我的 javascript 文件

中加载此类
...
<head>
    <script>var boardListUrl= "{% url 'boards:boards_api_list-list' %}?format=datatables"</script>
    {% if board.slug %}
    <script>var jobListUrl= "{% url 'boards:board_jobs_list-list' board.slug %}?format=datatables"</script>
    {% endif %}
<head>
...

在我的 main.py 文件中,我执行了以下操作

 var table = $('#tableName').DataTable({
        ...
        "ajax": jobListUrl,
        ...
});