Как создать 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
результат.