React POST request to Django Rest ManyToMany field - reactjs

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

Related

KeyError at 'body' when i send a request with fecth. Django and ReactJs project

i´m doing a project with django (django rest framework) as backend and React js as Front for some reason the 'body' isn´t send to the backend.
here the django view:
#api_view(['POST'])
def crearTarea(request):
data = request.data
print(data['body'])
tarea = Tarea.objects.create(
body=data['body']
)
serializer = TareaSerializer(tarea, many=False)
return Response(serializer.data)
the request in react with fetch:
let crear = () =>{
let tarea_json = {
"titulo": document.getElementById("titulo").value ,
"descripcion": tarea.descripcion,
"tiempo_tarea": 1,
"fk_idUsuario": 1
}
fetch('/api/tareas/create', {
method: "POST",
body: JSON.stringify(tarea_json),
headers: {
'Content-Type': 'application/json'
}
})
}
the model:
class Tarea(models.Model):
titulo = models.CharField(max_length=50)
descripcion = models.CharField(max_length=150)
tiempo_tarea = models.ForeignKey(Tiempo_tarea, on_delete = models.CASCADE)
fk_idUsuario = models.ForeignKey(User, on_delete = models.CASCADE)
created = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ["created"]
db_table = "Tarea"
verbose_name_plural = "Tareas"
verbose_name = "Tarea"
def __str__(self) -> str:
return self.titulo
and the error:
enter image description here
i´m traying to create a new instance with the method POST and fecth but it doesn´t run.
I would be grateful if you could help me

How to insert data and update data in One to One Relation in DRF and React Js

I have two models User and Profile which is related by One to One relation. I have registered users who can login and if profile is not created for user, then user can create one profile (using POST) and if profile is created then user can update their profile (using PATCH).
Models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True, related_name='profile')
locality = models.CharField(max_length=70, null=True, blank=True)
city = models.CharField(max_length=70, null=True, blank=True)
address = models.TextField(max_length=300, null=True, blank=True)
pin = models.IntegerField(null=True, blank=True)
state = models.CharField(max_length=70, null=True, blank=True)
profile_image = models.ImageField(upload_to='user_profile_image', blank=True, null=True)
Serializer.py
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model= Profile
fields = ['user', 'locality','city','address','pin','state','profile_image']
Views.py
class UserProfileDataView(APIView):
renderer_classes = [UserRenderer]
permission_classes = [IsAuthenticated]
def get(self, request, format=None):
serializer = ProfileSerializer(request.user.profile, context={'request': request})
return Response(serializer.data, status=status.HTTP_200_OK)
def post(self, request, format=None):
serializer = ProfileSerializer(data= request.data, context={'user': request.user})
serializer.is_valid(raise_exception=True)
serializer.save()
return Response ({ 'msg':'Data Updated Successfully'},status=status.HTTP_201_CREATED
)
def patch(self, request, format=None):
item = Profile.objects.get(user = request.user)
serializer = ProfileSerializer(item ,data = request.data, partial=True, context={'user': request.user.profile})
serializer.is_valid(raise_exception=True)
serializer.save()
return Response({'msg':'Profile Updated Successfull'}, status = status.HTTP_200_OK)
API using Redux Toolkit
editProfile: builder.mutation({
query: (access_token, actualData ) => {
return {
url:'editprofile/',
method:'PATCH',
body:actualData,
headers:{'authorization' : `Bearer ${access_token}`, 'Content-type':'application/json'}
}
}
}),
createProfile: builder.mutation({
query: (access_token, actualData ) => {
return {
url:'createprofile/',
method:'POST',
body:actualData,
headers:{'authorization' : `Bearer ${access_token}`, 'Content-type':'application/json'}
}
}
}),
})
})
When I create profile from django admin for a user and tries to update its data, then I only get {"msg": "Profile Updated Successfull"} in network console but data is not reflected in database. and also when I try to create profile of user from Fronend using React, it gives error msg {"errors": {"user": ["This field is required."]}}
I think you missed setting the user_id field in the request payload. In the ProfileSerializer, you need to change the user field into user_id.
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model= Profile
fields = ['user_id', 'locality','city','address','pin','state','profile_image']
extra_kwargs = {
'user_id': {'source': 'user'}
}
And in the frontend, you need to set the user_id attribute in the actual_data object.
Or in the backend, you can add that field manually in the post method of the UserProfileDataView class.
class UserProfileDataView(APIView):
...
def post(self, request, format=None):
input_data = request.data
input_data['user_id'] = request.user.id
serializer = ProfileSerializer(data= input_data, context={'user': request.user})
serializer.is_valid(raise_exception=True)
serializer.save()
return Response ({ 'msg':'Data Updated Successfully'},status=status.HTTP_201_CREATED
)

How to insert data in child table from react to django rest framework models

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
...

Django-3.1/DRF/React: Unable to save nested images (linked through GenericRelation)

I am building a Django+DRF/React app (simple blog app) and i am facing difficulties saving nested images
Model Structure
Model:
Post
Children:
details: ContentType Model ( DRF: save is successfull )
images: ContentType Model ( DRF : save is not successfull )
Process
Send images from <input type="file" multiple />
Process data through FormData
Catch request.data and process it
class PostFormView(generics.RetrieveUpdateDestroyAPIView):
queryset = Post._objects.is_active()
serializer_class = PostModelSerializer
permission_classes = (IsOwnerOr401,)
parser_classes = (parsers.MultiPartParser,parsers.JSONParser,
parsers.FormParser, parsers.FileUploadParser)
lookup_field = 'slug'
lookup_url_kwarg = 'slug'
def get_queryset(self):
return super().get_queryset().annotate(**sharedAnnotations(request=self.request))
def update(self, request, *args, **kwargs):
data = request.data
_images = data.getlist('images')
images = []
for _ in _images:
if isinstance(_, dict):
images.append(images)
continue
images.append({'image': _, 'object_id': self.get_object().pk, 'content_type': self.get_object().get_content_type().pk})
data['images'] = images
print(data)
partial = kwargs.pop('partial', False)
instance = self.get_object()
serializer = self.get_serializer(instance, data=data, partial=partial)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
if getattr(instance, '_prefetched_objects_cache', None):
instance._prefetched_objects_cache = {}
return Response(serializer.data)
Save images (FAIL):
class MediaModelSerializer(ContentTypeModelSerializer):
# inherits object_id & content_type fields just to avoid writing them over and over alongside (create & update fns)
class Meta:
model = Media
fields='__all__'
class PostModelSerializer(WritableNestedModelSerializer):
is_active = serializers.BooleanField(default=True)
path = serializers.HyperlinkedIdentityField(
view_name="api:post-detail", lookup_field='slug')
images = MediaModelSerializer(many=True)
details = DetailModelSerializer(required=False, many=True)
# annotated fields
is_author = serializers.BooleanField(read_only=True, default=False)
class Meta:
model = Post
fields = '__all__'
read_only_fields = ['is_locked', 'slug', 'user', 'is_author']
def create(self, validated_data):
return super().create(validated_data)
def update(self, instance, validated_data):
return super().update(instance, validated_data)
The print(data) statement from PostFormView.update(self, request, *args, **kwargs) (after manipulation) returns this:
<QueryDict: {'id': ['8'], ..., 'images': [[{'image': <InMemoryUploadedFile: bmw_3.jpeg (image/jpeg)>, 'object_id': 8, 'content_type': 20}, {'image': <InMemoryUploadedFile: bmw_2.jpeg (image/jpeg)>, 'object_id': 8, 'content_type': 20}, {'image': <InMemoryUploadedFile: bmw_1.jpeg (image/jpeg)>, 'object_id': 8, 'content_type': 20}]]}>
Server returns 400_BAD_REQUEST because images were not passed to PostModelSerializer
{"images":["This field is required."]}
i've been facing this issue for 3 days and i can't wrap my head around the root cause.
Thank you for your help.
i have been looking all over the internet but i could not find any anwsers so i had to go this way
I have removed the processing part from PostFormView.update(...) and accessed the images directly in the create & update methods of the ModelSerializer. I'll figure out later on how to handle removing these images
Here's the code:
class PostModelSerializer(WritableNestedModelSerializer):
is_active = serializers.BooleanField(default=True)
path = serializers.HyperlinkedIdentityField(
view_name="api:post-detail", lookup_field='slug')
images = MediaModelSerializer(read_only=True, many=True)
details = DetailModelSerializer(required=False, many=True)
# annotated fields
is_author = serializers.BooleanField(read_only=True, default=False)
class Meta:
model = Post
fields = '__all__'
read_only_fields = ['is_locked', 'slug', 'user', 'is_author']
def create(self, validated_data):
instance = super().create(validated_data)
request = self.context.get('request', None)
if request:
try:
images = request.data.getlist('images')
for image in images:
self.instance.images.create(image=image)
except Exception as e:
pass
return instance
def update(self, instance, validated_data):
instance = super().update(instance, validated_data)
request = self.context.get('request', None)
if request:
try:
images = request.data.getlist('images')
for image in images:
self.instance.images.create(image=image)
except Exception as e:
pass
return instance
If anyone has faced this issue before and managed to resolve it, please post your answer below.
Thank you !

Why does AngularJS read integer `3` returned by DRF API as `%203`?

This is my DRF view which gets called at /posts/{id}:
class PostViewSet(mixins.CreateModelMixin, mixins.ListModelMixin, mixins.RetrieveModelMixin, mixins.DestroyModelMixin, GenericViewSet):
serializer_class = PostSerializer
permission_classes = (IsAuthenticated, IsActualOwnerDelete,)
def get_queryset(self):
# new posts from location.
return Post.objects.filter(location=self.request.user.userextended.location).order_by('-createdAt')
def perform_create(self, serializer):
serializer.save(actualOwner=self.request.user)
#list_route(permission_classes=[IsAuthenticated])
def mymostrecent(self, request):
me = request.user
try:
# this gets the most recent post's ID
post = me.post_mine_set.latest('id')
did = post.id
except Post.DoesNotExist:
did = 0
return Response(did)
Now with Angular, when I do to the URL /posts/mymostrecent:
return $http.get("/api/posts/mymostrecent")
.then(function(response) {
console.log(response);
$location.url('/posts/ ' + response.data);
})
What gets logged is this:
Object {data: 3, status: 200, config: Object, statusText: "OK"}
But the URL becomes this:
/posts/%203
It still works and shows the correct html page, but how do I get rid of the %20 in the URL?
This is my models.py (probably not needed):
class Post(models.Model):
owner = models.ForeignKey(User)
usersVoted = models.ManyToManyField(User, blank=True, related_name="%(class)s_voted_set")
post = models.CharField(max_length=400)
createdAt = models.DateTimeField(auto_now_add=True, blank=True)
actualOwner = models.ForeignKey(User, related_name="%(class)s_mine_set")
The problem is with this part of code, You are adding a extra space in this line $location.url('/posts/ ' + response.data);
return $http.get("/api/posts/mymostrecent")
.then(function(response) {
console.log(response);
$location.url('/posts/' + response.data); #Removed the space after '/posts/ ' ie. change '/posts/ ' to '/posts/'
})

Resources