#python-3.x #django #django-models #django-serializer #manytomanyfield
Вопрос:
Когда я пытаюсь опубликовать с помощью get_or_create и доступных для записи вложенных сериализаторов, я могу это сделать, но поля со многими отношениями каким-то образом, даже если они представляют собой массив идентификаторов при публикации, я получаю сообщение об ошибке:
Ошибка типа в /Albums/ Field ‘id’ ожидала число, но получила [<Порядок: 2B>] .
структура: Треки имеют заказы (где orders — это поле manytomany класса Orders)
В альбоме есть треки
Я могу публиковать в треках и указывать заказы в виде массива «заказы»: [2,4]
Когда я пытаюсь опубликовать в альбоме вместе с дорожками, я могу опубликовать дорожки с полями, которые НЕ ЯВЛЯЮТСЯ полями manytomany, но если я попытаюсь использовать поля manytomany, я получаю ошибку типа, упомянутую выше.
2B — это значение другого поля, а не идентификатор заказа, это значение поля, возвращаемого в
def __str__(self) -> str:
return (self.name)
Модели:
class Orders(models.Model):
name = models.CharField(max_length=100, unique=True)
def __str__(self) -> str:
return self.name
class Album(models.Model):
title = models.CharField(max_length=150)
description = models.TextField(blank=True)
def __str__(self) -> str:
return self.title
class Tracks(models.Model):
name = models.CharField(default="Period Relationship",
max_length=100, blank=True)
orders = models.ManyToManyField(Orders, blank=True)
album = models.ForeignKey(
Album, related_name="tracks", default=None, on_delete=CASCADE)
def __str__(self) -> str:
return (self.name)
Сериализаторы:
class TracksSerializer(serializers.ModelSerializer):
class Meta:
model = Tracks
fields = "__all__"
class Album(serializers.ModelSerializer):
tracks = TracksSerializar(
many=True)
class Meta:
model = ALbum
fields = '__all__'
def create(self, validated_data):
tracks = validated_data.pop(
'tracks')
album = Album.objects.create(
**validated_data)
for tracks in tracks:
Tracks.objects.get_or_create(
album=album, **tracks)
album.tracks.add(
tracks)
return album
class OrdersSerializer(serializers.ModelSerializer):
class Meta:
model = Orders
fields = '__all__'
Число просмотров:
class OrdersViewSet(viewsets.ViewSet):
def list(self, request):
orders = Orders.objects.all()
serializer = OrdersSerializer(
orders, many=True)
return Response(serializer.data)
def create(self, request):
serializer = OrdersSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def retrieve(self, request, pk=None):
queryset = Orders.objects.all()
orders = get_object_or_404(queryset, pk=pk)
serializer = OrdersSerializer(
orders)
return Response(serializer.data)
def update(self, request, pk=None, **kwargs):
partial = kwargs.pop('partial', False)
orders = Orders.objects.get(pk=pk)
serializer = OrdersSerializer(
orders, data=request.data, partial=partial)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def partial_update(self, request, *args, **kwargs):
kwargs['partial'] = True
return self.update(request, *args, **kwargs)
def destroy(self, request, pk=None):
orders = Orders.objects.get(pk=pk)
orders.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
class AlbumViewSet(viewsets.ViewSet):
def list(self, request):
album = Album.objects.all()
serializer = AlbumSerializer(album, many=True)
return Response(serializer.data)
def create(self, request):
serializer = AlbumSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def retrieve(self, request, pk=None):
queryset = Album.objects.all()
album = get_object_or_404(queryset, pk=pk)
serializer = AlbumSerializer(album)
return Response(serializer.data)
def update(self, request, pk=None, **kwargs):
partial = kwargs.pop('partial', False)
album = Album.objects.get(pk=pk)
serializer = AlbumSerializer(
album, data=request.data, partial=partial)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def partial_update(self, request, *args, **kwargs):
kwargs['partial'] = True
return self.update(request, *args, **kwargs)
def destroy(self, request, pk=None):
album = Album.objects.get(pk=pk)
album.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
class TracksViewSet(viewsets.ViewSet):
def list(self, request):
tracks = Tracks.objects.all()
serializer = TracksSerializaer(
tracks, many=True)
return Response(serializer.data)
def create(self, request):
serializer = TracksSerializaer(
data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def retrieve(self, request, pk=None):
queryset = Tracks.objects.all()
tracks = get_object_or_404(queryset, pk=pk)
serializer = TracksSerializaer(
tracks)
return Response(serializer.data)
def update(self, request, pk=None):
tracks = Tracks.objects.get(
pk=pk)
serializer = TracksSerializaer(
tracks, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def destroy(self, request, pk=None):
tracks = Tracks.objects.get(
pk=pk)
tracks.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
Комментарии:
1. Возможно, вы захотите добавить код моделей, а не просто общее описание. Похоже, вы назначаете объект, когда он ожидает идентификатор. Вы можете сделать
instance.pk
, чтобы вернуть толькоid
.2. @Bobort отредактировал код, я использовал код в качестве упрощенного примера, поскольку у меня задействовано больше полей, но решение будет тем же
3. Ну, я вижу проблемы с вашим
create
методом в вашемAlbum
сериализаторе. Вы перебираетеtracks
переменную, имяtracks
которой перезаписывает все, что вы ввели в нее ранее. И вам не нужно выполнятьadd
включениеalbum
, поскольку вы уже указали егоget_or_create
. Выньте операторfor
andadd
. Я не думаю, что это решение, но оно приблизит вас. Кроме того, почему бы не использовать Django Rest Framework для всей этой сериализации?4. @Bobort удаление добавления работает нормально. но удаление for просто вызывает у меня больше проблем, например, не использовать прямое назначение orders.set() и некоторые ограничения not null. Я новичок в Django, но я думал, что использую фреймворк Django Rest, что я делаю не так? Если я удалю for, каким должен быть второй аргумент в get_or_create?
5. Попробуйте создать экземпляр заказа -> Экземпляр альбома -> треки без manytomanyfield. Затем добавьте экземпляр Order во вновь созданные треки. Согласно документу django, поле «порядок» модели «Трек» должно получить значение после сохранения экземпляра трека. Я не уверен, решит ли это вашу проблему, но вы можете обратиться к нижеприведенному документу и попробовать в консоли, прежде чем изменять сериализаторы. docs.djangoproject.com/en/3.2/topics/db/examples/many_to_many