Django Rest Framework - проблема с полем для JSON Post Request ManyTomany - PullRequest
0 голосов
/ 28 октября 2018

TLDR;используя Django Rest Framework, как я могу сделать POST (контент приложения / json) для ресурса API, который имеет поле отношения «многие ко многим», используя только ID / PK для указанного поля M2M?

Я в настоящее времямоделирование приложения для проекта колледжа, который использовал Django Rest Framework.Следующая модель представляет собой Волонтера в приложении (я скрыл некоторые мелкие детали, чтобы избежать загрязнения кода)

class Volunteer(models.Model):

first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
state = models.CharField(max_length=2, choices=STATE_CHOICES)
city = models.CharField(max_length=255)
gender = models.CharField(max_length=2, choices=GENDER_CHOICES, blank=True, null=True)
phone = models.CharField(max_length=13) 
email = models.EmailField(max_length=100)
description = models.TextField(max_length=500)  
photo = models.ImageField(null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
interest_areas = models.ManyToManyField(VolunteeringArea, blank=True)

class Meta:
    verbose_name_plural = "Volunteers"
    ordering = ("first_name", "last_name")

def __str__(self):
    return self.first_name + ' ' + self.last_name

def get_absolute_url(self):
    return reverse('volunteers:volunteer-detail', kwargs={'pk': self.id})

И соответствующий сериализатор выглядит следующим образом:

class VolunteerSerializer(serializers.ModelSerializer):

    interest_areas = VolunteeringAreaSerializer(many=True)

    class Meta:
        model = Volunteer
        fields = ('id', 'first_name', 'last_name', 'phone', 'email', 'state', 'gender', 'interest_areas', 'city', 'description', 'photo')
        read_only_fields = ('created_at', )


    def to_representation(self, instance):
        representation = super(VolunteerSerializer, self).to_representation(instance)
        representation['interest_areas'] = VolunteeringAreaSerializer(instance.interest_areas.all(), many=True).data
        return representation 

Каквы можете заметить, что каждому волонтеру может быть приписано много областей интереса (поле «многие к многим»).Его представляет следующая модель:

class VolunteeringArea(models.Model):

    title = models.CharField(max_length=100)
    description = models.TextField(max_length=512)
    created_at = models.DateTimeField(auto_now_add=True)
    is_active = models.BooleanField(default=False)

    class Meta:
        verbose_name_plural = "VolunteeringAreas"

    def __str__(self):
        return self.title

    def slug(self):
        return slugify(self.title

)    

И соответствующий сериализатор:

class VolunteeringAreaSerializer(serializers.ModelSerializer):

    class Meta:

        model = VolunteeringArea
        fields = ('id', 'title', 'description')
        read_only_fields = ('created_at', 'is_active') 

Моя проблема заключается в том, что при попытке создать нового добровольца с помощью POST (application / json), предоставляющегоидентификатор заинтересованных_объектов, я получаю ответ о том, что я должен был указать слово, но вместо этого приложение получило int.Я понимаю, что приложение ожидало полного изменения со всеми полями из интереса_области, но я хотел предоставить только ID / PK и создать объект.

Я искал несколько часов наИнтернет, и кажется, что я должен сначала создать объект без интереса_области, а затем добавить их к объекту.Я попытался определить метод create в views.py модуля (так же, как и оригинальный метод create, определенный платформой), но, похоже, он застрял в serializer.is_valid (), что, скорее всего, указывает на предоставленные значенияв поле интереса не действительны.

def post(self, request, format=None):
    return self.create(request)


def create(self, request, *args, **kwargs):

    serializer = self.get_serializer(data=request.data)
    serializer.is_valid(raise_exception=True)
    self.perform_create(serializer)
    headers = self.get_success_headers(serializer.data)
    return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

def get_serializer(self, *args, **kwargs):

    serializer_class = self.get_serializer_class()
    kwargs['context'] = self.get_serializer_context()
    return serializer_class(*args, **kwargs)

В чем моя ошибка и как я могу заставить эту работу работать?

Ради информации, это содержание тела запроса с использованием Почтальона:

{
    "interest_areas": [0,1],
    "first_name":"NameOfThePerson",
    "last_name":"LastNameOfThePerson",
    "phone":"RandomCellphoneNumber",
    "email":"randomemail@randomemail.com",
    "gender":"Gender",
    "state":"State",
    "city":"City",
    "description":"randomDescription"
}

Заранее спасибо за помощь!

1 Ответ

0 голосов
/ 29 октября 2018

Вы получаете ошибку, потому что вы включили VolunteeringAreaSerializer в качестве NestedSerialiser.Чтобы использовать только идентификаторы для вашей VolunteeringArea, используйте PrimaryKeyRelatedField и bulk_create следующим образом.

class VolunteerSerializer(serializers.ModelSerializer):

    interest_areas = serializers.PrimaryKeyRelatedField(many=True, 
                     queryset=models.VolunteeringArea.objects.all())


    class Meta:
        model = Volunteer
        fields = ('id', 'first_name', 'last_name', 'phone', 'email', 'state', 
              'gender', 'interest_areas', 'city', 'description', 'photo')

    def create(self, validated_data):
        areas = validated_data.pop('interest_areas', [])
        # create your volunteer here..
        #......
        ThroughModel = Volunteer.interest_areas.through
        # bulk-create through model instance fields
        ThroughModel.objects.bulk_create([
                ThroughModel(volunteer_id=<freshly_created_volunteer_id>, 
                         interest_area_id=area_id)
                        for area_id in areas
                      ])

        return volunteer
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...