I am trying to send image from react to django rest framework,this is what I tried so far,it gives Unsupported media type error, I am not sure if the problem is in the backend or frontend part. What else should I do in order to make it work?
backend
views.py
class ImageView(APIView):
permission_classes=[permissions.IsAuthenticated]
parser_classes=[MultiPartParser,FormParser]
def post(self,request,format=None):
print(request.data)
serializer=ImageSerializer(data=request.data)
if serializer.is_valid():
serializer.save();
return Response(status=200)
serializer.py
class ImageSerializer(serializers.ModelSerializer) :
class Meta:
model=Images;
fields=['image']
models.py
def upload_to(instance,filename):
return 'images/{filename}'.format(filename=filename)
class Images(models.Model):
image=models.ImageField(upload_to=upload_to)
settings.py
MEDIA_ROOT=BASE_DIR.joinpath('media')
MEDIA_URL='/media/'
frontend
Send_file.js
const Send_file=()=>{
const send_data=(e)=>{
e.preventDefault();
let data={
'image':e.target[0].files[0]
}
axios.post(`${BASE_URL}/upload_image/`,data,config)
}
return <>
<form enctype='multipart/form-data' onSubmit = {send_data}>
<input type='file'/>
<button type='submit'>SEND FILE</button>
</form>
</>
}
I think you need to set FileField in the ImageSerializer.
class ImageSerializer(serializers.ModelSerializer):
upload_image = serializers.FileField(max_length = 10000000, allow_empty_file = False, use_url = False, write_only = True)
class Meta:
model = Images
fields = ('upload_image', 'image')
def create(self, validated_data):
image_source = validated_data.pop('upload_image')
new_image = Images.objects.create(image = image_source)
return new_image
And please change the image key in the data object in Send_file.js into upload_image.
const Send_file=()=>{
const send_data=(e)=>{
e.preventDefault();
let data={
'upload_image':e.target[0].files[0] # here
}
axios.post(`${BASE_URL}/upload_image/`,data,config)
}
...
}
Related
I'm new to React and Django rest framework. I want to insert profile data into the Django model using fetch API in react. I'm continuously getting response header as:
{"user":["Incorrect type. Expected pk value, received str."]}
I've checked by printing response on console, and it gives status code '200 OK'. But it didn't update the database as well.
My submit form function in react is:
const handleSubmit = (e) => {
e.preventDefault();
const profile = profileObj(selectedProfileImg, contact, city, country, address);
localStorage.setItem('profile', JSON.stringify(profile))
let form_data = new FormData()
// *************************
// this is the foreign key in the model and it gives the problem.
// *************************
form_data.append('user',JSON.parse(localStorage.getItem('data')).id) // (foriegn key value) User added by signing up
form_data.append('profile_img', profile.prof_img)
form_data.append('contact',profile.contact)
form_data.append('city',profile.city)
form_data.append('country',profile.country)
form_data.append('address',profile.address)
form_data.append('store_title','storename') // (foriegn key value) Data with this key exists in database
form_data.append('cus_status',profile.cus_status)
// *********************************
// Also I want to know what the boundary means in content
// type. As I see it on google so I used it but removing it
// gives another boundary error.
// *********************************
fetch('http://localhost:8000/customer_apis/addCustomer/', {
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW'
},
body: form_data
})
.then(res => {
console.log(res)
console.log(res.status)
if (res.status !== 200)
document.getElementById('text-error').innerHTML = res.statusText
else {
navigate('/create_store')
}
})
}
My Django model is:
class CustomerData(models.Model):
CUS_STATUS=(
('A','Active'),
('B','Blocked'),
('X','Blacklist')
)
# I imported the user as (from django.contrib.auth.models import User)
user=models.ForeignKey(User, on_delete=models.CASCADE)
store_title=models.ForeignKey(StoreData, on_delete=models.CASCADE, null=True, default='')
city=models.CharField(max_length=50, default="")
country=models.CharField(max_length=50, default="")
address=models.CharField(max_length=200, default="")
phone=models.IntegerField(default=00)
profile_img=models.ImageField(upload_to=user_directory_path, blank=True,null=True)
cus_status=models.CharField(max_length=20,choices=CUS_STATUS, default='A')
def __str__(self):
return str(self.store_title)
And Django API view is:
#api_view(['POST','GET'])
def addCustomer(request):
serializer = CustomerSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response("Success")
else:
return Response(serializer.errors)
CustomerSerializer is:
class CustomerSerializer(serializers.ModelSerializer):
class Meta:
model = CustomerData
fields='__all__'
How could I add data to the child table having foreign keys from React Apis to Django rest Framework?
Any help will be really appreciated.
I think you need to use some other field for uploading user and store_title data.
class CustomerSerializer(serializers.ModelSerializer):
user_id = serializers.IntegerField(write_only = True)
store_title_id = serializers.IntegerField(write_only = True)
user = UserSerializer(read_only = True)
store_title = StoreTitleSerializer(read_only = True)
class Meta:
model = CustomerData
fields=("user", "store_title", "city", "country", "address", "phone", "profile_img", "cus_status", "user_id", "store_title_id", )
And in frontend, you can upload user_id and store_title_id as the integer value.
const handleSubmit = (e) => {
...
form_data.append('user_id', parseInt(JSON.parse(localStorage.getItem('data')).id, 10))
...
form_data.append('store_title_id', 1) # for example
...
What I want to do is post a ListLink object, which contains Link objects, to the database.
The Link objects are added by input field by the user and stored in the state until a request is sent for them to be saved in the database.
I am trying to make a post request to DRF, but I am getting the following response:
"Invalid data. Expected a dictionary, but got list."
I am using axios to make the request:
Home.jsx
handleSave = event => {
event.preventDefault();
return axios({
method: 'post',
url: 'http://localhost:8000/api/lists/',
headers: {
'Authorization': 'Token ' + localStorage.getItem('token')
},
data: {
links: this.state.links,
name: this.state.listName
}})
.then(res => {
console.log(res);
});
}
This is the state I am using to save the lists in:
this.state = {
listName: 'Link List',
listDescription: 'Add description here',
listURL: '',
currentLink: 'https://www.example.com',
links: []
};
Here are my models and serializers:
LinkList
class LinkList(models.Model):
owner = models.ForeignKey(
User,
related_name='lists',
on_delete=models.CASCADE)
name = models.CharField(max_length=100)
description = models.CharField(max_length=250)
public = models.BooleanField(default=False)
links = models.ManyToManyField(
Link,
related_name='linklists')
def __str__(self):
return "%s - %s" % (self.owner, self.name)
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
Serializer:
class LinkListSerializer(serializers.ModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name="lists-detail")
owner = serializers.ReadOnlyField(source='owner.username')
links = LinkSerializer()
class Meta:
model = LinkList
fields = ['url', 'owner', 'name', 'public', 'links']
Link
class Link(models.Model):
link = models.URLField(max_length=200)
def __str__(self):
return "%s" % (self.link)
Serializer:
class LinkSerializer(serializers.ModelSerializer):
class Meta:
model = Link
fields = ['url', 'link']
You can try to add many=True parameter to LinkSerializer but you will need to handle this list yourself (pop links attribute and manually create every link object).
class LinkListSerializer(serializers.ModelSerializer):
...
def create(self, validated_data):
with transaction.atomic(): # optional - ensure that changes will be rolled back on error
links = validated_data.pop('links', [])
instance = super().create(validated_data)
for l in links:
instance.links.create(link=l)
return instance
Update 2, 13th Jan: After doing some bug searching and trying to post the object directly in the root API using json, I've come to the realisation that the image is what's giving me the posting error.
I used the HTML form to post an object and it gave me this error:
TypeError at /rats/
'Image' object is not callable
For context, I uploaded an image. Here are my serialisers for creating the object (rat) and for images:
class ImageSerializer(FlexFieldsModelSerializer):
image = VersatileImageFieldSerializer(
sizes='rat_headshot'
)
class Meta:
model = Image
fields = ['name', 'image']
class RatSerializer(FlexFieldsModelSerializer):
user = serializers.CharField(source='user.username', required=False)
userid = serializers.CharField(source='user.id', required=False)
body_colour = BodyColourSerializer()
eye_colour = EyeColourSerializer()
image = ImageSerializer(required=False)
class Meta:
model = rat
exclude = ['bio']
def create(self, data):
request = self.context.get("request")
print("I was here", data, request)
return rat.objects.create(
name = data["name"],
body_colour = BodyColour(name=data["body_colour"]["name"]),
eye_colour = EyeColour(name=data["eye_colour"]["name"]),
# bio = data["bio"],
image = Image(name=data["image"]["name"])(required=False),
user = request.user,
)
I've updated the title. Original title was "Can't manage to post an object via axios to django - possibly due to AnonymousUser object?", now it's " "'Image' object is not callable" when posting API object "
Update 8th Jan: I fixed the AnonymousUser error. Django wanted an ID but was instead getting the user class, I fixed it by changing user = request.user into user = request.user.id
However, I'm still unable to post the object. I'm getting the same res.data error as below. So now I'm not sure what's causing the error.
I'm trying to add a button in React which posts an object to django via axios when a user clicks on it. However, it seems like something's wrong backend.
Here's the button:
<button
id="add-rat"
type="button"
className="btn homeButton"
onClick={
(e) => submit(e)
}
>
Add rat
</button>
And here's the axios, in the same page:
const submit = (e) => {
const name = "namee";
const eyeColour = "Red";
const bodyColour = "White";
const bio = "hfff";
const image = "lineart.PNG";
const data = {
name: name,
eye_colour: eyeColour,
body_colour: bodyColour,
bio: bio,
image: image,
};
e.preventDefault();
console.log(data);
const token = localStorage.getItem("token");
axios
.post("http://127.0.0.1:8000/api/addObject", data, {
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
})
.then((res) => {
console.log(res.data);
})
.catch((err) => console.log(err));
};
This is my console output:
{name: 'namee',
eye_colour: 'Red', body_colour: 'White', bio: 'hfff', image: 'lineart.PNG'}
myRats.js:86 {res: 'Error Accured'}
(myRats.js:86 btw, is console.log(res.data); )
Here's my view for the object:
class AddRat(APIView):
def post(self,request):
data = request.data
user = request.user
print(data)
try:
user = rat( name = data['name'] , body_colour = data['bodyColour'] , eye_colour = data['eyeColour'],user= user, bio = data['bio'] , image = data['image'])
user.save()
return Response({'res':"Rat Saved Successfully"})
except:
return Response({'res':"Error Accured"})
def get(self,request):
user = request.user
data = rat.objects.filter(user = user)
data = RatSerializer(data, many = True)
return Response({'data':data.data})
When I go to the url it's posting to, I get this error:
TypeError at /api/addObject
Field 'id' expected a number but got <django.contrib.auth.models.AnonymousUser object at 0x0000014641FD85B0>.
Could it possibly be due to that? What could be wrong?
The Anonymous User issue was solved by changing user = request.user into user = request.user.id
And my second issue, "'Image' object is not callable" was due to me putting (required=False) in another set of parenthesis, as if I was calling an Image as a function.
So I changed
image = Image(name=data["image"]["name"])(required=False)
into
image = Image(name=data["image"]["name"], required=False)
I am new to Django and have trouble making django-rest-framework API for post, inheriting APIView. I'm using a serializer, that inherits djangos ModelSerializer. I face NOT NULL constraint failed: accounts_personalcolor.user_id error whenever I try saving the serializer or model object.
color.js posts image using Django rest framework as follows.
function PersonalColorScreen({navigation,route}) {
const {image} = route.params;
console.log('uri is', image.uri);
const [userToken, setUserToken] = React.useState(route.params?.userToken);
const requestHeaders = {
headers: {
"Content-Type": "multipart/form-data"
}
}
// helper function: generate a new file from base64 String
//convert base64 image data to file object to pass it onto imagefield of serializer.
//otherwise, serializer outputs 500 Internal server error code
const dataURLtoFile = (dataurl, filename) => {
const arr = dataurl.split(',')
const mime = arr[0].match(/:(.*?);/)[1]
const bstr = atob(arr[1])
let n = bstr.length
const u8arr = new Uint8Array(n)
while (n) {
u8arr[n - 1] = bstr.charCodeAt(n - 1)
n -= 1 // to make eslint happy
}
return new File([u8arr], filename, { type: mime })
}
//random number between 0-9
function getRandomInt(max) {
return Math.floor(Math.random() * max);
}
// generate file from base64 string
const file = dataURLtoFile(image.uri, `${getRandomInt(10)}.png`)
const formData= new FormData();
formData.append('img',file,file.name);
console.log(file.name);
//axios post request to send data
// axios.post('http://localhost:8000/accounts/personalcolor/', formData,requestHeaders)
//multipartparser
axios.post('http://localhost:8000/accounts/personalcolor/', formData, requestHeaders)
.then(res => {
console.log(res);
if (res.data === 'upload another image') {
setimageError('upload another image');
} else {
// signUp(userToken);
let color;
switch (res.data){
case ('spring'):
color = 'spring';
break;
case ('summer'):
color = 'summer';
break;
case ('fall'):
color = 'fall';
break;
case ('winter'):
color = 'winter';
break;
}
}
})
.catch(err => {
console.error(err.response.data)
})
view.py handles the image posted. I tried #1 but it did not work. So I tried #2, or #3 instead and they return the same error saying NOT NULL constraint failed: accounts_personalcolor.user_id. I thought saving the serializer or model object creates id(Autofield)automatically and I don't understand why I face this error.
views.py
#api_view(['POST'])
def personalcolor(request):
# 1
image=request.FILES['img']
personal_color=Personalcolor()
personal_color.img=image
personal_color.save()
# 2
image=request.FILES['img']
personal_color=Personalcolor.objects.create(img=image)
personal_color.save()
# 3
serializer = ColorSerializer(data=request.data)
# validation of input data
if serializer.is_valid():
serializer.save()
else:
return Response(serializer.errors, status = status.HTTP_400_BAD_REQUEST)
model.py
class Personalcolor(models.Model):
objects = models.Manager()
img = models.ImageField('personal_img',upload_to="personalcolor/", blank=True)
serializer.py
class ColorSerializer(serializers.ModelSerializer):
class Meta:
model = Personalcolor
fields = ['img']
As mentioned above, executing the code returns django.db.utils.IntegrityError: NOT NULL constraint failed: accounts_personalcolor.user_id. Any help would be greatly appreciated.
Set null to true in your img field like:
img = models.ImageField('personal_img',upload_to="personalcolor/", blank=True, null=True)
Then in your migrations folder within the app where the Personalcolor model is located, delete all of the files that look like 000*_initial.py
Then run makemigrations and migrate
I'm use flask-marshmallow.
In response I get next simillary json:
data = {
'id': '1.0.1',
'name': 'test',
'applicaion_id': 'google',
}
How can I get application.name from Application?
react
class VersionDetail extends Component {
state = {
app: {
id: '',
name: '',
application_id: '',
}
}
componentDidMount() {
axios.get('/apps/'+this.props.match.params.id)
.then(response => this.setState({ app: response.data }))
.catch(function (error) {
})
}
render() {
return ()
}
}
routes
class ApplicationDetailSchema(ma.ModelSchema):
class Meta:
model = Application
fields = ('id', 'name', 'versions')
class VersionDetailSchema(ma.ModelSchema):
class Meta:
model = Version
fields = ('id', 'file', 'application_id')
version_schema = VersionDetailSchema()
#app.route("/<application_id>/<version_id>")
def version_detail(id):
application = Application.get(application_id)
version = Version.get(version_id)
return version_schema.dump(version)
models
class Application(db.Model):
__tablename__ = 'applications'
id = db.Column(db.String(), primary_key=True)
name = db.Column(db.String())
versions = db.relationship('Version', backref='application', lazy=True)
def __repr__(self):
return '<application {}>'.format(self.name)
class Version(db.Model):
__tablename__ = 'versions'
id = db.Column(db.String(), primary_key=True)
file = db.Column(db.String(80), nullable=True)
application_id = db.Column(db.Integer, db.ForeignKey('applications.id'))
def __repr__(self):
return '<version {}>'.format(self.id)
I think you'll need to add a ma.Nested schema into your VersionDetailSchema, as outlined in this answer - something like;
class VersionDetailSchema(ma.ModelSchema):
application = ma.Nested(ApplicationDetailsSchema, only=['name'])
class Meta:
model = Version
fields = ('id', 'file', 'application_id', 'application')
I'm only guessing at the only=['name'] based off the marshmallow docs
There is unfortunately not much in the way of documentation on this for flask-marshmallow - I personally find the benefit of using that add on is actually less than the more well documented marshmallow by itself - the setup is hardly very difficult.