'Django KeyError and MultiValueDictKeyError when trying to POST
I am trying to do a POST request to Django through Vue JS, this POST request is a review to a city,
When I try to POST through Vue JS I get no response so I tried using the Django API directly and each time I get the same error MultiValueDictKeyError
The way I'm trying to POST this request is that each Review is connected to a specific City so I have to attach the city ID to it so I can pass to that City through the API.
This is my views.py file:
from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import City, Review
from .serializers import CitySerializer, ReviewSerializer
from rest_framework.parsers import FormParser, MultiPartParser, JSONParser
from django.http import HttpResponse
class LatestCityList(APIView):
parser_classes = (FormParser, MultiPartParser)
def get(self, request, format=None):
cities = City.objects.all()
serializer = CitySerializer(cities, many=True)
return Response(serializer.data)
def post(self, request, format=None):
Name = request.data['Name']
Picture = request.data['Picture']
Description = request.data['Description']
slug = Name.lower().replace(' ', '_')
City.objects.create(Name=Name, Picture=Picture, Description=Description, slug=slug)
return HttpResponse({'message': 'City created successfully'}, status=201)
class CityDetail(APIView):
parser_classes = (FormParser, MultiPartParser)
def get(self, request, slug, format=None):
city = City.objects.get(slug=slug)
serializer = CitySerializer(city)
return Response(serializer.data)
class CityReviewList(APIView):
parser_classes = (FormParser, MultiPartParser)
def get(self, request, slug, format=None):
city = City.objects.get(slug=slug)
reviews = Review.objects.filter(City=city)
serializer = ReviewSerializer(reviews, many=True)
return Response(serializer.data)
def post(self, request, slug, format=None):
city = City.objects.get(slug=slug)
id = City.objects.get(slug=slug).id
Review = request.data['Review']
TravelerName = request.data['TravelerName']
Picture = request.data['Picture']
slug = TravelerName.lower().replace(' ', '_')
Review.objects.create(City=city, Review=Review, TravelerName=TravelerName, Picture=Picture, slug=slug)
return HttpResponse({'message': 'Review created successfully'}, status=201)
You can see that I have POST for LastestCityList and that works perfectly both from the API and from Vue JS I tried applying the same concept for the Review and I couldn't figure it out, I know that the problem is related to City but I tried everything to debug it but still getting an error each time.
This is my serializers.py file:
from rest_framework import serializers
from .models import City, Review
class CitySerializer(serializers.ModelSerializer):
class Meta:
model = City
fields = ('id', 'Name', 'Picture', 'Description',
'get_absolute_url', 'get_image', 'slug')
class ReviewSerializer(serializers.ModelSerializer):
class Meta:
model = Review
fields = ('id', 'City', 'Review', 'TravelerName', 'slug',
'Picture', 'get_absolute_url', 'get_image')
Models.py:
from PIL import Image
from django.core.files.uploadedfile import InMemoryUploadedFile
import sys
from django.core.files import File
from django.db import models
class City(models.Model):
Name = models.CharField(max_length=50, blank=False, null=False)
Picture = models.ImageField(upload_to='uploads/', blank=False, null=False)
Description = models.TextField(blank=False, null=False)
slug = models.SlugField(max_length=50, blank=True, null=True, unique=True)
class Meta:
"""Meta definition for City."""
ordering = (['Name'])
def __str__(self):
return self.Name
def get_absolute_url(self):
""" Returns the url to access a particular instance of the model. """
return f'/{self.slug}/'
def get_image(self):
if self.Picture:
return 'http://127.0.0.1:12222' + self.Picture.url
return ''
class Review(models.Model):
City = models.ForeignKey(City, on_delete=models.CASCADE, related_name='reviews')
Review = models.TextField(blank=False, null=True)
TravelerName = models.CharField(max_length=50, blank=True, null=True)
Picture = models.ImageField(upload_to='uploads/', blank=True, null=True)
slug = models.SlugField(max_length=50, blank=True, null=True, unique=True)
class Meta:
ordering = (['TravelerName'])
def __str__(self):
return self.TravelerName
def get_absolute_url(self):
return f'/{self.City.slug}{self.slug}/'
def get_image(self):
if self.Picture:
return 'http://127.0.0.1:12222' + self.Picture.url
return ''
Vue JS Component for the POST data:
<script>
import axios from 'axios';
export default {
name: 'ReviewPost',
data() {
return {
review: {
id: null,
city: '',
Review: '',
TravelerName: '',
Picture: null,
slug: ''
},
myimg: null,
};
},
methods: {
onFileChange(e) {
this.myimg = e.target.files[0];
console.log(this.myimg)},
uploadImageToServer() {
let formData = new FormData();
formData.append('id', null)
formData.append('Picture', this.myimg, this.myimg.name);
formData.append('City', this.review.city);
formData.append('Review', this.review.Review);
formData.append('TravelerName', this.review.TravelerName);
formData.append('slug', this.review.slug);
axios.post('http://127.0.0.1:12222/api/v1/cities/' + this.review.city + '/reviews/', formData)
.then(res => {
console.log(res)
})
.catch(err => {
console.log(err)
})
}
},
components: {
Headers
},
}
</script>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
