如何在Django REST API框架中公开过滤的反向关系?

时间:2015-02-24 04:39:30

标签: python django django-rest-framework

我有两种模式:

class Task(models.Model):
    person = models.ForeignKey(Person, related_name='tasks')
    title = models.CharField(max_length=200)
    is_deleted = models.BooleanField(default=False)

class Person(models.Model):
    name = models.CharField(max_length=100)
    is_deleted = models.BooleanField(default=False)

两个序列化器:

class PersonSerializer(serializers.ModelSerializer):
    tasks = serializers.PrimaryKeyRelatedField(many=True, read_only=True)

    class Meta:
        model = Person
        fields = ('id', 'name', 'tasks')

class TaskSerializer(serializers.ModelSerializer):
    class Meta:
        model = Task
        fields = ('id', 'title')

我想构建一个API,它返回人员详细信息以及属于此人的未删除任务列表。

如:

{
    "id": 1,
    "name": "Alan",
    "tasks": [
        100,
        101,
        102
    ]
}

所以在view.py,我得到了:

@api_view(['GET'])
def api_person_detail(request, person_id):
    """
    Project details
    """
    if request.method == 'GET':
        try:
            person = Person.objects.get(is_deleted=False, pk=person_id)
        except Person.DoesNotExist:
            return Response(status=status.HTTP_404_NOT_FOUND)
        serializer = PersonSerializer(person)
        return Response(serializer.data)

除了任务101被删除(is_delete = True)外,所有工作都很好。我不想在回复中。在这种情况下,如何过滤掉所有已删除的任务?

1 个答案:

答案 0 :(得分:2)

有几种方法 - >从更多一般到更多特定

一般一:改变TaskManager始终使用Task返回is_deleted = False

class TaskManager(models.Manager):
    def get_queryset(self):
        return super(self.__class__, self).get_queryset().filter(is_deleted=False)


class Task(models.Model):
    # ...
    objects = TaskManager()

具体:使用prefetch_related与自定义Prefetch对象。

person = Person.objects.filter(is_deleted=False, pk=person_id) \
            .prefetch_related(
                Prefetch('task_set', queryset=Task.objects.filter(is_deleted=False))
            ) \
            .get()

当然,您可以通过将此方法移动到PersonManager类来创建更强大的中间解决方案,这样您就可以创建类似的内容:

person = Person.objects.get_person_without_deleted_tasks(pk=person_id)