DJANGO REST FRAMEWORK IMAGE UPLOAD ["The submitted data was not a file. Check the encoding type on the form."] - django

I can't seem to upload an image to my project.
I always get this error when I try to submit the form from the frontend :
["The submitted data was not a file. Check the encoding type on the form."]
I've found some answers regarding the base64 encoding of the image but I can't seem to get it to work.
Any help would be much appreciated!!
thanks
here is the source code:
Models:
class Person(models.Model):
name = models.CharField(max_length=30)
age = models.IntegerField(default=0)
dob = models.CharField(max_length=10)
image = models.ImageField(upload_to='images/', null=True)
def __str__(self):
return self.name
class Details(models.Model):
party = models.ForeignKey(Person,on_delete=models.CASCADE,
related_name='party_details',null=True,blank=True)
adress = models.CharField(max_length=50)
date = models.CharField(max_length=20)
arrival= models.CharField(max_length=20)
def __str__(self):
return self.adress
Serializers:
class DetailsSerializer(serializers.ModelSerializer):
class Meta:
model = Details
# fields='__all__'
fields = ('id','party','adress','date','arrival')
class PersonSerializer(serializers.ModelSerializer):
party_details =DetailsSerializer(many=True)
class Meta:
model = Person
# fields='__all__'
fields = ('id','name','age','dob','image','party_details')
def create(self, validated_data):
named_details = validated_data.pop('party_details')
details = Person.objects.create(**validated_data)
for named_detail in named_details:
Details.objects.create(party=details, ** named_detail)
return details
def update(self,instance, validated_data):
named_details = validated_data.pop('party_details')
details = (instance.party_details).all()
details = list(details)
instance.name = validated_data.get('name', instance.name)
instance.age = validated_data.get('age', instance.age)
instance.dob = validated_data.get('dob', instance.dob)
instance.image = validated_data.get('image', instance.image)
instance.save()
for named_detail in named_details:
detail = details.pop(0)
detail.adress = named_detail.get('adress',detail.adress)
detail.date = named_detail.get('date',detail.date)
detail.arrival = named_detail.get('arrival', detail.arrival)
detail.save()
return instance
views:
class ListAllPerson (generics.ListCreateAPIView):
queryset=Person.objects.all()
serializer_class = PersonSerializer
class ListPerson (generics.RetrieveUpdateDestroyAPIView):
serializer_class = PersonSerializer
queryset= Person.objects.all()
class ListAllDetails(generics.ListCreateAPIView):
queryset=Details.objects.all()
serializer_class = DetailsSerializer
class ListDetail(generics.RetrieveUpdateDestroyAPIView):
serializer_class = DetailsSerializer
queryset=Details.objects.all()
class CreateDetail(generics.ListCreateAPIView):
queryset=Details.objects.all()
serializer_class = DetailsSerializer
HTML FORM and Axios:
const profileImage = async ()=>{
let formField = new FormData()
formField.append('image',addImages)
await axios({
method: 'patch',
url: url,
data: formField
}).then((response) => {
history.push('/')
}).catch((error) => {
console.log(error);
})
}
<div className="add-image-input">
<form action="" className="add-image-form">
<input className="image-input" value={addImages}
onChange={(e)=>{setAddImages(e.target.value)}} type="file"/>
<button className="" type="button" onClick={profileImage} >add</button>
</form>
</div>

Hopefully you are using React js, this should help. At the point of
saving and submitting your form data, your function should look like this:
const onSubmit = (data) => {
console.log(data)
let form_data = new FormData();
form_data.append('upload_image_photo', data.cover_image, data.cover_image.name);
form_data.append('title', data.title);
form_data.append('category', data.category);
form_data.append('price_per_night', data.price_per_night);
form_data.append('room_slug', data.room_slug);
form_data.append('capacity', data.capacity);
form_data.append('room_size', data.room_size);
let url = '/url to the end point you are saving with the expected image field / ';
const config = {
headers: {
"Content-Type": "multipart/form-data",
Authorization: `Bearer ${token}`,
},
};
axios.post(url, form_data, config)
.then(res => {
console.log(res.request.status);
console.log(res.data);
})
.catch(err => console.log(err))
};

Related

Change form input from text value to model instance in django

I want to create Aviz entry using AJAX form.
In the form the input material has a jquery ui function autocomplete, that gets all the material names from the Material Model.
When I submit the form I get this error in the console : ValueError: Cannot assign "'ADEZIV LIPIRE VATA MINERALA, CT 180, 25 KG CERESIT'": "Aviz.material" must be a "Material" instance.
I know that I need to get the input from the form, and turn it in a Material instance...but do not know how/did not find any info about this.
models.py:
class Material(models.Model):
name = models.CharField(max_length=255,default=None,verbose_name='Nume material')
class Aviz(models.Model):
material = models.ForeignKey(Material, on_delete=models.CASCADE,related_name="aviz")
quantity = models.FloatField(default=0,verbose_name="Cantitate")
views.py:
class AvizCreate(LoginRequiredMixin, AjaxCreateView):
model = Aviz
form_class = AvizForm
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['pk'] = self.kwargs.get('centrudecost')
return kwargs
#login_required
def autocomplete(request):
if 'term' in request.GET:
qs = Material.objects.filter(name__icontains=request.GET.get('term'))
name = list()
id = list()
cod_nexus = list()
name = [prod.name for prod in qs]
id = [prod.pk for prod in qs]
cod_nexus = [prod.cod_nexus for prod in qs]
return JsonResponse({"name": name, "id":id, "cod_nexus":cod_nexus}, safe=False)
templates.html
$('#id_material').autocomplete({
source: function(request, response) {
$.ajax({
url: "{% url 'materiale:autocomplete' %}",
dataType: "json",
data: {
term: request.term
},
success: function(data) {
response($.map(data.name, function(value, key) {
return {
label: data.name[key],
value: data.name[key],
id:data.id[key],
cod_nexus:data.cod_nexus[key]
}
}));
}
});
},
select: async function(event, ui) {
let resp = await fetch("{% url 'materiale:get_um' 1 %}".replace('1',ui.item.id));
let json = await resp.json()
$('#id_um').val(json);
}
})
}
forms.py:
class AvizForm(BootstrapHelperForm, forms.ModelForm):
material = forms.CharField()
um = forms.CharField()
class Meta:
model = Aviz
fields = ('centrudecost','data','aviz', 'material','um','quantity',)
widgets = {
'data': DateInput(),
'centrudecost': forms.HiddenInput(),
# 'material': forms.Select(attrs={'class': 'form-control'})
}
def __init__(self, *args, **kwargs):
pk = kwargs.pop('pk', None)
super(AvizForm, self).__init__(*args, **kwargs)
self.fields['um'].widget.attrs['readonly'] = True
I know that by deleting this material = forms.CharField() from the forms.py, the form works, and a Aviz instance is created referencing the material model, but i need to use the autocomplete function in the form

DRF updating data using AJAX call

When I try to send data via the frontend to the serializer I get a HTTP 400 error. If I do it directly via the DRF browsable API it works though:
model:
class Shipment(models.Model):
name = models.CharField("name", max_length = 128)
date = models.DateField()
class Product(models.Model):
serial = models.CharField("serial", max_length = 31, unique = True)
shipment = models.ForeignKey(Shipment, on_delete = models.CASCADE, blank = True, null = True)
serializer:
class ShipmentSerializer(serializers.ModelSerializer):
class Meta:
model = Shipment
fields = ["id", "name",]
class ProductSerializer(serializers.ModelSerializer):
shipment = ShipmentSerializer()
def update(self, instance, request):
product = Product.objects.get(serial = instance)
product.shipment = Shipment.objects.get(id = request["shipment"]["id"])
product.save()
return instance
class Meta:
model = Product
fields = ["serial", "shipment",]
lookup_field = "serial"
read_only_fields = ["serial",]
ViewSet:
class ProductViewSet(ModelViewSet):
serializer_class = ProductSerializer
lookup_field = "serial"
http_method_names = ["get", "patch", "put"]
def get_queryset(self):
return Product.objects.all()
AJAX call:
$.ajax({url: `api/products/${serial}/`,
dataType: "json",
contentType: "application/json",
type: "PUT",
data: {"shipment": shipment[0]},
headers: {"X-CSRFTOKEN": csrf_token },
success: function () {window.location = "?msg=ok";},
error: function () {window.location = "?msg=error";}
});
Browser output:
PUT
http://127.0.0.1:8000/api/products/d39f281f/
Status400
Bad Request
VersionHTTP/1.1
Transferred400 B (111 B size)
Referrer Policysame-origin
Request payload:
shipment=4
Response:
{"shipment":["This field is required."]}
or after some playing:
JSON parse error - Expecting value: line 1 column 1 (char 0)
why is the response field is required when there is a payload.
One way to approach this problem is to define two fields for shipment, one for writing and one for reading:
class ProductSerializer(serializers.ModelSerializer):
shipment_id = serializers.PrimaryKeyRelatedField(queryset=Shipment.objects.all(), write_only=True)
shipment = ShipmentSerializer(read_only=True)
class Meta:
model = Product
fields = ["serial", "shipment", "shipment_id"]
When you are updating, you can specify the id of the shipment using shipment_id:
{
"shipment_id": 10,
}
When you are retrieving or listing, the shipment details will come under shipment:
{
"serial": "",
"shipment": {
... # shipment details
}
}

Image upload error 'Check the encoding type on the form.'

In my project, i need to upload an image as an avatar for my players as shown in my models.py :
class Player(models.Model):
number = models.IntegerField()
photo = models.ImageField(upload_to=upload_path, null=True, blank=True)
firstname = models.CharField(max_length=24)
lastname = models.CharField(max_length=24)
tag = models.CharField(max_length=8, blank=True)
color = models.CharField(max_length=10, null=True, blank=True)
selected = models.BooleanField(null = False, blank=True)
post = models.ForeignKey(Post, on_delete=models.SET_NULL, null=True)
def __str__(self):
return "#{}".format(
self.number,
)
I'm using angular to send my image using :
<input
type="file"
(change)="onNewPlayerPhotoChanged($event)"
accept="image/jpeg, image/png, image/jpg"
/>
& in my typescript
onNewPlayerPhotoChanged(event) {
this.newPlayerPhoto = event.target.files[0];
}
then on my submit button i got
createPlayer() {
this.newPlayer.selected = false;
this.newPlayer.photo = this.newPlayerPhoto;
this.newPlayer.post_id = parseInt(this.newPlayerPost, 10);
this.playerService.create(this.newPlayer).subscribe(
res => {
this.getPlayerList();
this.openNewModal = false;
this.alertService.success('Joueur créé avec succès !');
setTimeout(() => this.alertService.clear(), 2000);
},
error => {
this.alertService.error(error);
setTimeout(() => this.alertService.clear(), 2000);
}
);
}
But i got the error : photo: ["The submitted data was not a file. Check the encoding type on the form."]
Here is my **views.py : **
class PlayerViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows Player to be viewed or edited.
"""
parser_classes = [JSONParser]
queryset = Player.objects.all()
serializer_class = PlayerSerializer
permission_classes = [IsAuthenticated, HasPermission, ]
def post(self, request, *args, **kwargs):
return HttpResponse({"message":request.FILES}, status=200)
print(request.FILES)
print(request.data)
photo = request.FILES['photo']
firstname = request.data['firstname']
lastname = request.data['lastname']
number = request.data['number']
tag = request.data['tag']
color = request.data['color']
selected = request.data['selected']
post = request.data['post']
Player.objects.create(photo=photo, firstname=firstname, lastname=lastname, number=number, tag=tag, color=color,
selected=selected, post=post)
return HttpResponse({'message':"Player created"}, status=200)
& my serializers.py :
class PlayerSerializer(serializers.ModelSerializer):
post = PostSerializer(many=False, read_only=True)
post_id = serializers.PrimaryKeyRelatedField(source='post', write_only=True, queryset=Post.objects.all(),)
class Meta:
model = Player
fields = '__all__'
I followed that tutorial https://www.youtube.com/watch?v=-36YauTh4Ts but he doesn't encouter that error,
if anyone could help, it would be much appreciated.
Thank you !
EDIT : I tried to use FileUploadParser & MultiPartParser as parser in my views but none of them would work either, FileUploadParser would return me an error saying the filename was needed and the MultiPartParser would return me an error syaing that he was receiving JSON.

object has no attribute in Django Rest Framework

I develop a mobile application with Django Rest Framework at behind, and React Native at front side.
I have to models and nested serializers. I need to insert record at same time to them. But I have 'Entity' object has no attribute 'automobile' error. When I check similar examples, I do not understand where I am wrong. There will be an entity inserted first, and after that an automobile will inserted with the connection of this entitiy.
Could you please help me?
class Entity(models.Model):
customer = models.CharField(max_length=100, null=True, blank=True)
seller = models.CharField(max_length=100, null=True, blank=True)
entity_name = models.CharField(max_length=50, blank=True, default='')
class Meta:
verbose_name_plural = u"Entities"
verbose_name = u"Entity"
def __str__(self):
return "%s %s" % (self.id, self.entity_name)
class Automobile(models.Model):
entity = models.ForeignKey(Entity, on_delete=models.CASCADE, blank=True)
entity_address = models.CharField(max_length = 250, blank = True, default = '')
used_km = models.IntegerField(default = 0)
manufactured_year = models.IntegerField(validators=[MinValueValidator(1900), MaxValueValidator(timezone.now().year)], blank = True, null = True)
def __str__(self):
return "%s" % (self.entity_id)
class Meta:
verbose_name_plural = u"OptionedAutomobiles"
verbose_name = u"OptionedAutomobile"
class AutomobileSerializer(serializers.ModelSerializer):
class Meta:
model = Automobile
fields = [ 'entity_address', 'used_km', 'manufactured_year']
class EntitySerializer(serializers.ModelSerializer):
automobile = AutomobileSerializer(many=False)
class Meta:
model = Entity
fields = ['id', 'customer', 'seller', 'entity_name',
'automobile']
def create(self, validated_data):
automobile_data = validated_data.pop('automobile')
entity = Entity.objects.create(**validated_data)
Automobile.objects.create(entity= entity, **automobile_data)
return entity
class EntityViewSet(viewsets.ModelViewSet):
serializer_class = EntitySerializer
queryset = Entity.objects.all()
permission_classes = (AllowAny,)
def perform_create(self, serializer):
serializer.save(customer=self.request.user)
class AutomobileViewSet(viewsets.ModelViewSet):
serializer_class = AutomobileSerializer
queryset = Automobile.objects.all()
permission_classes = (AllowAny,)
fetch(`http://127.0.0.1:8000/api/entities/`, {
method: 'POST',
headers: {
'Authorization': `Token ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({seller:seller,
entity_name:entity_name,
automobile:{used_km:10}})
})
.then((res) => res.json())
.then((data) => {
console.log(data)
})
.then(res =>{
Alert.alert("Yeni Entity eklendi.");
})
.catch(error=>console.log(error));
I could not understand what the problem was, but I solved the problem for now by changing location of create function. Now, my create function is under AutomobileSerializer, not EntitySerializer. Of course I also change something about that, and it solved for now as I said.

Problems with the response in API REST django

I try to link django API-REST with a form that has an associated model. Everything works well until I do the:
return response.Response (serializer.data, status = status.HTTP_201_CREATED)
JavaScript
// To Save the Suggestion
let ajax_suggestion_save = function (type, url, data, context) {
let name_dm = $('#name-db-saved').val();
$.ajax({
type: type,
url: url,
data: data,
context: context,
beforeSend: function (xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
},
success: function (response) {
$.niftyNoty({
type: "success",
container: 'floating',
title: 'Your information was saved successfully.',
message: 'We much appreciate your interest of contact us, part of the growth of this platform it is base on your collaboration through your ideas.',
closeBtn: true,
timer: 4000
});
},
error: function (response) {
if (Object.keys(response.responseJSON).length >= 1) {
$.each(response.responseJSON, function (key, value) {
$.niftyNoty({
type: 'danger',
container: 'floating',
title: 'Ups, apparently we have problems saving your information.',
message: 'Please check the following ' +
'Error in <strong> ' + key + ' </strong>, with the following error <strong> ' + value + ' </strong>.',
closeBtn: true,
timer: 4000
});
});
} else {
$.niftyNoty({
type: 'danger',
container: 'floating',
title: 'Ups, apparently we have problems saving your information.',
message: 'Ups, apparently we have problems saving your suggestion. ' +
'If the problem persists, notify the system administrator in the help section.' +
'You suggestion <strong> ' + name_dm + ' </strong> not will be saved.',
closeBtn: true,
timer: 4000
});
}
}
});
};
$('#contactus').on('click', function (type, url, data, context) {
ajax_suggestion_save('POST', '/miscellaneous/api/contactus/create/', $("#contactus_form").serializeArray(), this);
});
Model
class DimContactUs(Model):
class Meta:
order_with_respect_to = 'email'
verbose_name = 'Contact'
verbose_name_plural = 'Contact'
id_contact_us = UUIDField(primary_key=True, default=uuid.uuid4, editable=False,
help_text='Universally unique identifier of a Contact')
name = CharField(max_length=100, help_text='Name of the Contact')
email = EmailField(max_length=70, help_text='Email of these Contact')
# id_user = ForeignKey(User, on_delete=CASCADE, help_text='Foreign Key of the User that made this Contact')
title = CharField(max_length=100, help_text='Title of the Contact')
message = TextField(
help_text='Short description of this Contact, e.g. : We want to include ...!')
url = URLField(null=True, blank=True,
help_text='Please copy the url associated to this Contact')
active = BooleanField(default=True, help_text='Do you want to make public this Contact?')
time_create = DateTimeField(auto_now=True, auto_now_add=False, editable=False, help_text='Time it was created')
time_stamp = DateField(auto_now=True, auto_now_add=False, help_text='Time of last modification')
def __str__(self):
return self.title
Serializers
class DimContactUsSer(serializers.ModelSerializer):
class Meta:
model = DimContactUs
fields = '__all__'
View
class ContactUsCreate(CreateAPIView):
queryset = DimContactUs.objects.all()
serializer_class = DimContactUsSer
#csrf_exempt
def post(self, request, *args, **kwargs):
try:
if request.method == 'POST':
form = DimContactUsForm(request.POST, request.FILES)
serializer = DimSuggestionSer(data=request.data)
if form.is_valid() and serializer.is_valid():
serializer.save()
return response.Response(serializer.data, status=status.HTTP_201_CREATED)
else:
return response.Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
except Exception as exception:
return response.Response(exception.args, status=status.HTTP_400_BAD_REQUEST)
Here, the response sends me to the REST API page instead of staying in the current one.
I would expect your missing the import statement for the module, I cannot see your import statements.
from rest_framework import status