I am trying to update the database using a PUT request. Currently, I am able to update the database from the Django Admin successfully but I want to do same using a PUT request.
When ever I make a PUT request, I get a 200 OK response with no errors but the data is not updating in the database. I dont know why. I am confused. Someone please help me. Thank you.
models.py
class User_Order(models.Model):
order = models.OneToOneField(Orders, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
id = models.IntegerField(primary_key=True)
shirts = models.IntegerField(default=0)
shorts = models.IntegerField(default=0)
trousers = models.IntegerField(default=0)
total_units = models.CharField(max_length=2000, blank=True)
shirts_amount = models.CharField(max_length=2000, blank=True)
shorts_amount = models.CharField(max_length=2000, blank=True)
trousers_amount = models.CharField(max_length=2000, blank=True)
total = models.CharField(max_length=200,blank=True)
verified = models.BooleanField(null=True)
doing_laundry = models.BooleanField(null=True)
delivery_underway = models.BooleanField(null=True)
delivered = models.BooleanField(null=True)
address = models.TextField(default='')
time = models.DateTimeField(auto_now=True)
def save(self, *args, **kwargs):
self.user = self.order.user
self.id = self.order.id
self.shirts = self.order.shirts
self.shorts = self.order.shorts
self.trousers = self.order.trousers
self.total_units = self.order.total_units
self.shirts_amount = self.order.shirts_amount
self.shorts_amount = self.order.shorts_amount
self.trousers_amount = self.order.trousers_amount
self.total = self.order.total
self.verified = self.order.verified
self.doing_laundry = self.order.doing_laundry
self.delivery_underway = self.order.delivery_underway
self.delivered = self.order.delivered
self.address = self.order.address
super().save(*args, **kwargs)
def __str__(self):
return f'{self.order.user.username} Order'
serializers.py
class UserUser_OrderSerializer(serializers.ModelSerializer):
class Meta:
model = User_Order
fields = '__all__'
views.py
#api_view(['PUT'])
def UserOrdersUpdate(request, pk):
permission_classes = [IsAuthenticated]
user_order = User_Order.objects.get(id=pk)
if request.method == 'PUT':
serializer = UserUser_OrderSerializer(instance=user_order, data=request.data, many = False, partial=True)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
Maybe it's because in User_Order.save() method you replace all fields from User_Order where all the data from serializer is stored with Order instance values.
Also you can use class based view UpdateAPIView to simplify it:
class UserOrdersUpdateView(generics.ListCreateAPIView):
queryset = User_Order.objects.all()
serializer_class = UserUser_OrderSerializer
permission_classes = [IsAuthenticated]
Docs:
UpdateAPIView
Used for update-only endpoints for a single model instance.
Provides put and patch method handlers.
Extends: GenericAPIView, UpdateModelMixin.
Related
my views.py
#login_required
#api_view(['GET'])
def ChapterNames(request, id):
liveclass_id = models.LiveClass_details.objects.filter(id=id).first()
chapter_names = liveclass_id.chapter_ids.all()
serializer = serializers.chapterNames_serializer(chapter_names, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
models.py
class ChapterNames(models.Model):
chapter_names = models.CharField(max_length=100, unique=True)
def __str__(self):
return self.chapter_names
class LiveClass_details(models.Model):
standard = models.ForeignKey(LiveClass, on_delete=models.CASCADE)
chapter_ids = models.ManyToManyField(ChapterNames)
chapter_details = models.TextField(default='')
mentor_id = models.ForeignKey(Mentor, max_length=30, on_delete=models.CASCADE)
start_time = models.DateTimeField()
end_time = models.DateTimeField(default=timezone.now())
doubtClass = models.OneToOneField(DoubtClasses, on_delete=models.PROTECT, null=True, blank=True)
isDraft = models.BooleanField(default=True)
ratings = models.IntegerField(default=0)
no_of_students_registered = models.IntegerField(default=0)
no_of_students_attended = models.IntegerField(default=0)
class Meta:
verbose_name_plural = 'LiveClass_details'
def __str__(self):
return self.chapter_details
here chapternames are added as many to many field in Django, user authentication and all the apis are working fine and only this one is causing error
urls.py
path('liveclass/', views.LiveClassView.as_view(), name='liveclass'),
path('liveclass/<int:id>', views.LiveClassViewId.as_view()),
path('liveclass/<int:id>/chapter-names', views.ChapterNames),
I am trying to hit liveclass/id/chapter-names but it is redirecting me to /accounts/login/?next=/liveclass/1/chapter-names when i tried to access it in postman but it is giving me fine results in rest framework api view
You put decorator #login_required in front of your view so it will try to login befor accessing the view if you are not yet logged in
Trying to allow users to create an object and save it in my model. My front-end POST requests are getting a 201 confirmation response, so no traceback error from the backend. The data seems to be getting serialized but not saved in my model.
Here is my code...
model.py:
class Bucket(models.Model):
category_options = (
('personal', 'Personal'),
('social', 'Social'),
)
class BucketObjects(models.Manager):
def get_queryset(self):
return super().get_queryset()
owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='buckets')
admin_user = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='admin_user')
guest_user = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='guest_user', blank=True)
category = models.CharField(max_length=30, choices=category_options)
name = models.CharField(max_length=35)
created = models.DateTimeField(default=timezone.now, blank=True)
slug = AutoSlugField(populate_from = "random_string", blank=True)
stock_count = models.IntegerField(blank=True, null=True)
stock_list = ArrayField(models.CharField(max_length=6,null=True),size=30,null=True, blank=True)
about = models.CharField(max_length=200)
objects = models.Manager()
bucketobjects = BucketObjects()
class Meta:
ordering = ('-created',)
def save(self, *args, **kwargs):
if self.stock_list:
self.stock_count = len(self.stock_list)
super().save(*args, **kwargs)
serializer.py:
class BucketCreateSerializer(serializers.ModelSerializer):
class Meta:
model = Bucket
fields = ('owner','category','name','about')
read_only_fields = ['owner']
def create(self, validated_data):
user = self.context['request'].user
bucket = Bucket.objects.create(
owner=user,
**validated_data
)
bucket.save()
return bucket
view.py:
class CreateBucket(generics.CreateAPIView):
permission_classes = [IsAuthenticated]
serializer_class = BucketCreateSerializer
queryset = Bucket.objects.all()
How can I go about solving this?
I'm trying to upload multiple images with django rest api. I followed the following approach. But when I select one or more files and try to send them to the server as form data, I get the following error message:
AttributeError at /api/photo/ 'bytes' object has no attribute 'name'
Model:
class Photo(models.Model):
image = models.ImageField(upload_to='audio_stories/')
Serializer:
class FileListSerializer ( serializers.Serializer ) :
image = serializers.ListField(
child=serializers.FileField( max_length=100000,
allow_empty_file=False,
use_url=False )
)
def create(self, validated_data):
image=validated_data.pop('image')
for img in image:
photo=Photo.objects.create(image=img,**validated_data)
return photo
View:
class PhotoViewSet(viewsets.ModelViewSet):
serializer_class = FileListSerializer
parser_classes = (MultiPartParser, FormParser,)
queryset=Photo.objects.all()
URL
router.register('api/photo', PhotoViewSet, 'photocreate')
I dont know how to approach the error, as i have nothing in my code that relates to "name"?
The error seemed to be in the serializer. I had to set the use_url=True.
Serializer:
class FileListSerializer ( serializers.Serializer ) :
image = serializers.ListField(
child=serializers.FileField( max_length=100000,
allow_empty_file=False,
use_url=True )
)
def create(self, validated_data):
image=validated_data.pop('image')
for img in image:
photo=Photo.objects.create(image=img,**validated_data)
return photo
Extended Answer
The above answer works but produces an large null array.
In order to make the code work I had to seperate my two models in Story and Story_Media. Each instance of Story Media contains a single image and provides a FK to the Story.
class Story (models.Model):
title = models.CharField(max_length=100, blank=True)
description = models.TextField(blank=True)
date_posted = models.DateTimeField(default=timezone.now)
def __str__(self):
return f'{self.id} Story'
class Story_Media (models.Model):
story = models.ForeignKey(Story,on_delete=models.CASCADE, null=True, related_name = 'story_media', related_query_name = 'story_media')
file = models.FileField(upload_to='story_media/', null=True, validators=[validate_file_extension_image])
isTitlePicture = models.BooleanField(blank=False, null=True)
def __str__(self):
return f'{self.id} Media'
In my serializer, a new Sotry_Media instance is created for each image included in the incoming data. In my case, it was necessary to create a story even if no images were uploaded, so the two conditions are included.
# Story Serializer_Media_Serializer
class Story_Media_Serializer (serializers.ModelSerializer):
class Meta:
model = Story_Media
fields = ('id','isTitlePicture', 'file',)
# Story Serializer
class StoryCreateUpdateSerializer (serializers.ModelSerializer):
story_media = Story_Media_Serializer(many=True, required = False)
class Meta:
model = Story
fields = ('title','description', )
def create(self, validated_data):
current_user = self.context["request"].user
# Story contains images
if 'story_media' in validated_data:
story_media = validated_data.pop('story_media')
story_instance = Story.objects.create(author=current_user, **validated_data)
for img in story_media:
Story_Media.objects.create(**img, story=story_instance)
return story_instance
# Story is not containing images
if 'story_media'not in validated_data:
story_instance = Story.objects.create(author=current_user, **validated_data)
return story_instance
class StoryCreateUpdateViewSet(viewsets.ModelViewSet):
serializer_class = StoryCreateUpdateSerializer
http_method_names = ['post','delete','put','patch', 'head']
queryset = Story.objects.all()
permission_classes = [
permissions.IsAuthenticated, PostOwnerPermssion
]
Maybe you should consider implementing like i did which is working for me
Model
class Photo(models.Model):
title = models.CharField(max_length=255, blank=True)
image = models.ImageField(upload_to='hotel_photos')
hotel = models.ForeignKey(
Hotels, on_delete=models.CASCADE, null=True, blank=True,)
class Meta:
verbose_name_plural = 'Photos'
def __str__(self):
"""Prints the name of the Photo"""
return f'{self.hotel} photos'
Serializer
class PhotoSerializer(ModelSerializer):
class Meta:
model = Photo
fields = (
"image",
"hotel",
)
Helper function
def modify_input_for_multiple_files(hotel, image):
dict = {}
dict['hotel'] = hotel
dict['image'] = image
return dict
Views.py
class PhotoUploadView(ListCreateAPIView):
"""
This API view handles multiple images upload form
It will also display images for specific hotel
"""
parser_classes = (MultiPartParser, FormParser)
# http_method_names = ['get', 'post', 'head']
def get(self, request):
all_images = Photo.objects.all()
permission_classes = (IsAdminOrOwner,)
serializer_class = PhotoSerializer(all_images, many=True)
return JsonResponse(serializer.data, safe=False)
def post(self, request, *args, **kwargs):
hotel = request.data.get('hotel')
images = dict((request.data).lists())['image']
flag = 1
arr = []
for img_name in images:
modified_data = modify_input_for_multiple_files(hotel, img_name)
file_serializer = PhotoSerializer(data=modified_data)
if file_serializer.is_valid():
file_serializer.save()
arr.append(file_serializer.data)
else:
flag = 0
if flag == 1:
return Response(arr, status=status.HTTP_201_CREATED)
else:
return Response(arr, status=status.HTTP_400_BAD_REQUEST)
Hope this can help you or anyone stuck. In case of any question shoot it please
I have 2 models in 1 form. in this form data can be changed.
For 1 model (Sloep_core) the content only have to update, this is working.
for the other model (Sloep_gegevens) the content normaly will update.
Only if the value 'sloepnaam' changed in the form for model 'Sloep_gegevens', the record for the model 'Sloep_gegevens' must enter a new record and not update the old one.
The save() must change from update to insert, but how??
I have tried to put soms code together (with some search actions). I come to the code below but now it is always a insert the code. Is someone have a idea to get it right?
model.py:
class Sloep_core(models.Model):
FSN_nummer = models.IntegerField(unique=True)
HT_nummer = models.IntegerField(unique=True, blank=True, null=True)
SRNL_nummer = models.IntegerField(blank=True, null=True)
sloep_type = models.CharField(max_length=128, blank=True)
werf = models.CharField(max_length=255, blank=True)
info = models.TextField(blank=True)
objects = SloepManager()
def __str__(self):
return str(self.FSN_nummer)
class Sloep_gegevens(models.Model):
sloep = models.ForeignKey(Sloep_core, on_delete=models.CASCADE, default='')
sloepnaam = models.CharField(max_length=128)
thuishaven = models.CharField(max_length=128, blank=True)
date = models.DateField(auto_now=True)
__original_sloepnaam = None
def __init__(self, *args, **kwargs):
super(Sloep_gegevens, self).__init__(*args, **kwargs)
self.__original_sloepnaam = self.sloepnaam
def save(self, force_insert=False, force_update=False, *args, **kwargs):
if self.sloepnaam != self.__original_sloepnaam:
# then do this
force_insert = True
else:
# do that
force_update = True
super(Sloep_gegevens, self).save(force_insert, force_update, *args, **kwargs)
self.__original_sloepnaam = self.sloepnaam
class Meta:
ordering = ["date"]
def __str__(self):
return self.sloepnaam
form.py:
class SloepGegevensForm(forms.ModelForm):
class Meta:
model = Sloep_gegevens
exclude = ['pk', 'sloep']
class SloepCoreForm(forms.ModelForm):
class Meta:
model = Sloep_core
exclude = ['pk', 'SRNL_nummer']
views.py:
def sloep_edit(request, pk):
sloep = Sloep_core.objects.get(pk=pk)
sloep_sg = Sloep_gegevens.objects.filter(sloep=pk).order_by('-date')[0]
if request.method == "POST":
formSG = SloepGegevensForm(request.POST)
formSC = SloepCoreForm(request.POST, instance=sloep)
if all([formSG.is_valid(), formSC.is_valid()]):
sloep = formSC.save()
SG = formSG.save(commit=False)
SG.sloep = sloep
SG.save()
return redirect('sloep_detail', pk=sloep.pk)
else:
formSG = SloepGegevensForm(instance=sloep_sg)
formSC = SloepCoreForm(instance=sloep)
return render(
request,
'sloepen/sloep_edit.html',
{'formSG': formSG, 'formSC': formSC,})
I found the answer for my problem. In the view I didn't give a pk with the SloepGegevensForm in the POST request.model.
I changed: formSG = SloepGegevensForm(request.POST)into formSG = SloepGegevensForm(request.POST, instance=sloep_sg)
This makes the save() working.
Im trying to make a friends feed that lists all "Beat" objects that i am currently friends with. How can i access user inside of my viewset to return the correct objects?
MODELS:
class Beat(models.Model):
created_at = models.DateTimeField( default=datetime.now)
title = models.CharField(max_length=255)
description = models.TextField(blank=True, null=True)
likes = models.IntegerField(default=0)
artist = models.ForeignKey(UserProfile, null=True, blank=True)
audio = models.FileField(upload_to="media_files/audio/",null=True, blank=True)
beat_cover = models.ImageField(upload_to="media_files/img/",null=True, blank=True);
admin_name = models.CharField(max_length=255, blank=True, null=True)
class Meta:
ordering = ['-created_at']
def __unicode__(self):
return unicode(self.admin_name)
class UserProfile(models.Model):
user = models.OneToOneField(User, blank=True, null=True)
admin_name = models.CharField(default="beat",max_length=255,blank=True, null=True)
profile_pic = models.ImageField(upload_to="media_files/users/")
def __unicode__(self):
return unicode(self.admin_name)
SERIALIZERS:
class AllBeatStreamSerializer(serializers.ModelSerializer):
class Meta:
model = Beat
fields = ('created_at', 'title', 'audio', 'artist' )
depth = 1
VIEWSET:
class FriendsBeatStreamViewSet(viewsets.ModelViewSet):
user = self.request.user
my_battles = Battle.objects.filter(challenging_beat__artist=user)
obj = {}
my_beats = Beat.objects.filter(artist=user)
related_users = Relationship.objects.filter(from_user=user).values_list('to_user', flat=True).distinct()
stream = Beat.objects.filter(artist__in=related_users)
stream = list(my_beats) + list(stream) + list(my_battles)
queryset = stream
serializer_class = AllBeatStreamSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
The direct answer to your question is simple: Override get_queryset instead of defining queryset as an attribute, and you'll be able to access the current user on self.request.user.
But your code sample is more complex. 1) You can't mix Battle object with Beat objects. 2) Your serializer is a Beat serializer, so your queryset must be of Beat instances.
But you can mix many sources of Beat using a filter with or causes in SQL, so you get all beats that are my_beats OR related_to_me. Django has a Q object that allow complex lookups. So you can join two Q objects using the OR operator |. Each Q with a filter that represents a Beat source, like my beats or beats related to me.
Your code will be something like this:
from django.db.models import Q
class FriendsBeatStreamViewSet(viewsets.ModelViewSet):
serializer_class = AllBeatStreamSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
def get_queryset(self):
user = self.request.user
my_beats = Q(artist=user)
related_users = Relationship.objects \
.filter(from_user=user).values_list('to_user', flat=True).distinct()
stream = Q(artist__in=related_users)
return Beat.objects.filter(my_beats | stream)
You should override the queryset attribute in serializer (where the logic belongs) like this:
class AllBeatStreamSerializer(serializers.ModelSerializer):
# ...
def __init__(self, *args, **kwargs):
user = kwargs['context']['request'].user
super(AllBeatStreamSerializer, self).__init__(*args, **kwargs)
self.fields['parent'].queryset = self.get_request(user)
def get_request(self, user):
my_battles = Battle.objects.filter(challenging_beat__artist=user)
obj = {}
my_beats = Beat.objects.filter(artist=user)
related_users = Relationship.objects.filter(from_user=user)\
.values_list('to_user', flat=True)\
.distinct()
stream = Beat.objects.filter(artist__in=related_users)
stream = list(my_beats) + list(stream) + list(my_battles)
queryset = stream
return queryset