[英]In Django-Rest-Framework POST call which updates manytomany field works with JSON but not with form-data
[英]Django Rest Framework - JSON Post Request ManyTomany field issue
TLDR; 使用Django Rest Framework,如何僅使用所述M2M字段的ID / PK對具有多對多關系字段的API資源進行POST(應用程序/ json內容)?
我目前正在為使用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')
我的問題是,當嘗試通過提供有興趣的區域ID的POST(application / json)創建一個新的Volunteer時,我得到一個響應,說我應該提供一個dict,但是該應用程序卻接收到一個int。 我意識到該應用程序期望有一個來自dicted_area的所有字段的完整字典,但是我只想提供ID / PK,它將創建該對象。
我一直在互聯網上尋找時間,看來我應該先創建沒有interest_areas的對象,然后將其添加到該對象中。 我試圖在模塊的views.py上定義一個create方法(與框架定義的原始create方法相同),但是它似乎卡在serializer.is_valid()上,最有可能表明所提供的值在interested_area字段中無效。
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)
我的錯誤是什么,我該如何做?
為了提供信息,這是使用Postman的請求的正文內容:
{
"interest_areas": [0,1],
"first_name":"NameOfThePerson",
"last_name":"LastNameOfThePerson",
"phone":"RandomCellphoneNumber",
"email":"randomemail@randomemail.com",
"gender":"Gender",
"state":"State",
"city":"City",
"description":"randomDescription"
}
我在這里先向您的幫助表示感謝!
由於將VolunteeringAreaSerializer
作為NestedSerialiser包括在內,因此出現了錯誤。 要僅對您的VolunteeringArea使用ID,請使用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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.