Как создать ModelViewset, если модель имеет OneToOneField?

Идея состоит в том, чтобы иметь модель, подобную этой:

class Object(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    name = models.CharField(max_length=256)

    def __str__(self):
        return self.name

и затем создайте сериализатор и ModelViewSet, связанный с ним.

Проблема в том, что ModelViewSet должен возвращать кверисет, но я хочу работать с одиночными объектами из-за отношения один-к-одному.

Как мне следует действовать?

Как упоминается в документации:

Класс ModelViewSet наследуется от GenericAPIView и включает реализации для различных действий, смешивая поведение различных классов mixin.

Это означает, что ModelViewSet также позаботится о ситуации, когда необходимо вернуть конкретный Object. Вы можете даже переопределить def get_object(self), если вам нужно поведение более сложное, чем то, что реализовано (см. этот вопрос ).

Однако, чтобы действительно гарантировать, что возвращается только один Object, я бы посоветовал вам использовать поле в качестве уникального первичного ключа. Вы будете заполнять это поле при вставке (вручную или автоматически), а затем использовать его в качестве lookup_field.

Ниже я предположил, что у вас уже есть функция __str__(self) в вашей модели User, а также

Тогда ваша модель Object станет:

class Object(models.Model):
    id = models.BigAutoField(primary_key=True)  # or another unique primary_key field 
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    name = models.CharField(max_length=256)

    def __str__(self):
        return f"{self.name} ({self.id})"

Ваш сериализатор будет выглядеть так:

class ObjectSerializer(serializers.ModelSerializer):
    class Meta:
        model = Object
        fields = ("id", "name", "user")

    id = serializers.CharField(required=True)

Ваш ModelViewSet был бы чем-то вроде:

class ObjectViewSet(viewsets.ModelViewSet):
    http_method_names = ["get"]
    # parser_classes = [JSONParser] # Replace with your parser class
    queryset = Object.objects.all()
    serializer_class = ObjectSerializer
    lookup_field = "id"

Наконец, чтобы все это работало, вам также придется зарегистрировать ваш ModelViewSet в вашем urlpatterns.

Я использую явное связывание моих ViewSet классов в набор конкретных представлений, но это больше личный выбор, так что решать вам. Вы можете ознакомиться с соответствующей документацией для получения дополнительной информации.

urlpatterns = [
    ...
    path(
        r"objects/<str:id>",
        ObjectViewSet.as_view({"get": "retrieve"}),
    ),
    ...
]

При всем этом запрос к <BASE_URL>/objects/<YOUR_OBJECT_ID> должен возвращать только один Object результат.

Вернуться на верх