Django update ViewSet - django

Currently I am developing a image gallery django project. The user can upload images, and later upload a 'result' to each of the images.
I know that I have to override the update(...) function, but I think I need help here with the Base64ImageFiled.
Step by step:
User uploads image (result = null)
Image gets stored in cloud
User uploads result to a specified image (need help here)
Here is my current structure:
class Image(models.Model):
project = models.ForeignKey(Project)
image = models.ImageField(upload_to='images')
result = models.ImageField(upload_to='results')
class ImageSerializer(serializers.ModelSerializer):
project = ProjectSerializer(read_only=True, required=False)
image = Base64ImageField(max_length=None, use_url=False)
result = Base64ImageField(max_length=None, use_url=False, required=False)
class ProjectImagesViewSet(viewsets.ViewSet):
queryset = Image.objects.select_related('project').all()
serializer_class = ImageSerializer
def list(self, request, project_pk=None):
queryset = self.queryset.filter( project__name = project_pk)
serializer = self.serializer_class(queryset, many=True)
return Response(serializer.data)
def update(self, request, pk=None, project_pk=None):
print(request.data['result'])
???

Django Rest Framework convention is to use partial_update instead of update (PATCH request method). If you will send PATCH request with image to the same url as for retrieve url is should get updated. if you require additional features on update then you can define:
class ProjectImagesViewSet(viewsets.ViewSet):
#.....
def partial_update(self, request, *args, **kwargs):
instance = self.get_object()
serializer = self.serialize(instance, data=request.data, partial=True)
serializer.is_valid(raise_exception=True)
#.... Your code ....
serializer.save()
return Response(serializer.data)
EDIT:
Try those changes:
class ImageSerializer(serializers.ModelSerializer):
project = ProjectSerializer(read_only=True, required=False)
image = Base64ImageField(max_length=None, use_url=False)
result = Base64ImageField(max_length=None, use_url=False, required=False)
class Meta:
model = Image
class ProjectImagesViewSet(viewsets.ViewSet):
queryset = Image.objects.select_related('project').all()
serializer_class = ImageSerializer
def list(self, request, project_pk=None):
queryset = self.queryset.filter(project__name=project_pk)
serializer = self.serializer_class(queryset, many=True)
return Response(serializer.data)
def update(self, request, pk=None, project_pk=None):
print(request.data['result'])
def partial_update(self, request, *args, **kwargs):
instance = self.queryset.get(pk=kwargs.get('pk'))
serializer = self.serializer_class(instance, data=request.data, partial=True)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data)

Related

Convert the Image to base64 and upload the base64 file in S3 and get the same file using django

I need to get a image from django imagefield and convert it to base64 file and upload that converted file in private s3 bucket. And while I getting the image from the s3 bucket I need to get that base64 file and send it to the forntend(reactjs).
Basically I need to convert the image to base64 file, I checked on the internet and Iam not sure where to use that code correctly. Can anyone please suggest me to do that or is any clear documentation available to use as step by step.
Here is my model, views and seriailizers
class Organisation(models.Model):
"""
Organisation model
"""
org_id = models.AutoField(unique=True, primary_key=True)
org_name = models.CharField(max_length=100)
org_code = models.CharField(max_length=20)
org_mail_id = models.EmailField(max_length=100)
org_phone_number = models.CharField(max_length=20)
org_address = models.JSONField(max_length=500, null=True)
product = models.ManyToManyField(Product, related_name='products')
org_logo = models.ImageField(upload_to=upload_org_logo, null=True, blank=True,)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def remove_on_image_update(self):
try:
# is the object in the database yet?
obj = Organisation.objects.get(org_id=self.org_id)
except Organisation.DoesNotExist:
# object is not in db, nothing to worry about
return
# is the save due to an update of the actual image file?
if obj.org_logo and self.org_logo and obj.org_logo != self.org_logo:
# delete the old image file from the storage in favor of the new file
obj.org_logo.delete()
class Orglist(APIView):
renderer_classes = (CustomRenderer,)
parser_classes = [parsers.MultiPartParser, parsers.FormParser]
"""
List all snippets, or create a new snippet.
"""
def get(self, request, format=None):
orgs = models.Organisation.objects.all()
serializer = serializers.Organisation_Serializers(orgs, many=True)
return Response(serializer.data)
def post(self, request, format=None):
serializer = serializers.Organisationpost_Serializers(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class OrgDetail(APIView):
renderer_classes = (CustomRenderer,)
parser_classes = [parsers.MultiPartParser, parsers.FormParser]
def get_object(self, pk):
try:
return models.Organisation.objects.get(pk=pk)
except models.Organisation.DoesNotExist:
raise Http404
def get(self, request, pk, format=None):
org = self.get_object(pk)
serializer = serializers.Organisation_Serializers(org)
return Response(serializer.data)
def put(self, request, pk, format=None):
org = self.get_object(pk)
serializer = serializers.Organisationpost_Serializers(org, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, pk, format=None):
org = self.get_object(pk)
org.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
class Organisation_Serializers(serializers.ModelSerializer):
product = Product_Serializers(read_only=True,many=True)
class Meta:
model = Organisation
fields = ('org_id', 'org_name','org_address', 'org_phone_number', 'org_mail_id','org_logo','org_code','product',)
class Organisationpost_Serializers(serializers.ModelSerializer):
class Meta:
model = Organisation
fields = ('org_id', 'org_name','org_address', 'org_phone_number', 'org_mail_id','org_logo','org_code','product',)
I have configure the AWS credentials in the settings file. So kindly please suggest me a way to convert the image file and upload.

How to get number of records in a model in django rest framework?

I am using GenericAPIView and in model serializer to get data from tables. Now I can't understand how can I get the number of records from table in my rest api.
below is my sample code where I am getting records
urls.py
urlpatterns = [
path('ContactList/<int:user>/',views.ContactList.as_view()),
]
views.py
class ContactList(GenericAPIView, ListModelMixin):
def get_queryset(self):
username = self.kwargs['user']
return Contacts.objects.filter(user=username).order_by('-last_message')
serializer_class = ContactSerializer
permission_classes = (AllowAny,)
def get(self, request , *args, **kwargs):
return self.list(request, *args, **kwargs)
Serializers.py
class ContactSerializer(serializers.ModelSerializer):
class Meta:
model = Contacts
fields = ['id','user','Contact_id','last_message']
in above code I am getting all the contacts of some specific user. now How can I get number of records(contacts) related to this user.
for example if I send user 11 in URL I should get the number of records where user=11
if I correctly understand you need to return # of records besides the contacts
you can override the list method and do the following
class ContactList(GenericAPIView, ListModelMixin):
serializer_class = ContactSerializer
permission_classes = (AllowAny,)
def get_queryset(self):
username = self.kwargs['user']
return Contacts.objects.filter(user=username).order_by('-
last_message')
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
count = queryset.count()
return Response({"count":count, "data":serializer.data})
also you can add pagination will solve it

Django with Postgresql update object, prevent order re-ordering

in django production mode with postgreSQL, When I got an still existing object/row from the database, edit/update it and store it back, the row is moved to the end of the table.
object 1
object 2
object 3
after done editing object 1
object 2
object 3
object 1
models.py
class itemModels(models.Model):
name = models.CharField(max_length=50)
photo = models.ImageField(max_length=200, blank=True, default="default.png")
photo2 = models.ImageField(max_length=200, blank=True, default="default2.png")
price = models.DecimalField(max_digits=6, decimal_places=2)
sku = models.CharField(max_length=50, unique=True)
description = models.CharField(max_length=255)
def __self__(self):
return self.name
views.py
class itemViewSet(viewsets.ModelViewSet):
queryset = itemModels.objects.all()
serializer = itemSerializers()
renderer_classes = [TemplateHTMLRenderer]
template_name = 'product-list.html'
lookup_field = 'pk'
# list all item
def list(self, request):
queryset = itemModels.objects.all()
context = {'posts': queryset}
return Response(context)
# serializer form
def serializer_list(self, request):
serializer = itemSerializers()
return Response({'serializer': serializer}, template_name='product-create.html')
def retrieve(self, request, pk):
profile = get_object_or_404(itemModels, pk=pk)
serializer = itemSerializers(profile)
return Response({'serializer': serializer}, template_name='product-edit.html')
def update(self, request, pk):
profile = get_object_or_404(itemModels, pk=pk)
serializer = itemSerializers(profile, data=request.data)
if serializer.is_valid():
serializer.save()
print('status: status.Item Update')
return redirect('item')
else:
print('status: status.Item Bad Update')
i want to prevent this re-ordering happen, is there something i miss out ? thanks guys
Note:
if i am using development mode and switch the to django dummie database, this wont happen.
def list(self, request):
queryset = itemModels.objects.all()
context = {'posts': queryset}
return Response(context)
to
def list(self, request):
queryset = itemModels.objects.order_by('id').all()
context = {'posts': queryset}
return Response(context)
credit for #snakecharmerb thanks

Django Rest FrameWork Add Model With User Foreign Key

I'm using Django version 3 and the Rest Framework, i have a model with a user foreignkey.
so every time a model is saved the user also need to be saved.
To be able to add or to edit a model via rest you need to be authenticated using token authentication.
I'm using ClassBasedViews, the problem is that i can't find a way to add a model because in my serializer the field user is excluded because i don't want it to be editable.
models.py:
class Chambre(models.Model):
local_id=models.PositiveIntegerField(unique=True)
nom=models.CharField(max_length=255)
user=models.ForeignKey(User,on_delete=models.CASCADE,blank='true')
class Meta:
unique_together = ('local_id', 'user',)
serializers.py:
class ChambreSerializer(serializers.ModelSerializer):
class Meta:
model = Chambre
exclude =['user',]
views.py:
class ChambreListApi(APIView):
"""
List all chambres, or create a new chambre.
"""
authentication_classes=(TokenAuthentication,)
permission_classes=(IsAuthenticated,)
def get(self, request, format=None):
chambres = Chambre.objects.filter(user=request.user)
serializer = ChambreSerializer(chambres, many=True)
return Response(serializer.data)
def post(self, request, format=None):
serializer = ChambreSerializer(data=request.data)
if serializer.is_valid():
serializer.save(commit=False)
serializer.user=request.user
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Try moving the logic that sets the user to the serializer. By default GenericAPIView will pass the request to the serializer via the context.
class ChambreSerializer(serializers.ModelSerializer):
class Meta:
model = Chambre
exclude =['user',]
def create(self, validated_data):
validated_data["user"] = self.context["request"].user
return super().create(validated_data)
When I followed the accepted solution posted by schillingt, I had to add context={'request': request} when I instantiated the serializer. The Django REST Framework docs mention adding context to a serializer here.
serializers.py
class NoteCreateSerializer(serializer.ModelSerializer):
class Meta:
model = Note
exclude = ['owner',]
def create(self, validated_data):
validated_data['owner'] = self.context['request'].user
return super().create(validated_data)
views.py
#api_view['POST']
def create_note(request):
note_serializer = NoteCreateSerializer(
data = request.data,
context = {'request': request} # this will populate 'self.context'
# in the serializer instance
)
# ...
Thanks so much for this solution, though! It ended an hours-long struggle.
thanks for the reply that was very useful, i've solved it by adding method to serializer.py like this :
class ChambreSerializer(serializers.ModelSerializer):
class Meta:
model = Chambre
exclude =['user',]
def set_the_user(self,request):
self.user=request.user
def create(self, validated_data):
validated_data["user"] = self.user
return super().create(validated_data)
and in the views.py :
def post(self, request, format=None):
serializer = ChambreSerializer(data=request.data)
serializer.set_the_user(request)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

How I can pass over a field validation in a serializer in Django Rest Framework

I have a Location model and I need to create a Location without specifying a user, if user in empty then the user will be placed in request.user in the viewset.
This is my model:
class Location(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=100)
serializer:
class LocationSerializer(serializers.ModelSerializer):
def is_valid(self):
if not 'user' in self.init_data:
# avoid this validation.. I manage this in the viewset
pass
return not self.errors
class Meta:
model = Location
and viewset
class LocationViewSet(ModelViewSet):
"""
API endpoint that allows location to be created or viewed.
"""
model = Location
serializer_class = LocationSerializer
renderer_classes = (JSONRenderer, JSONPRenderer)
def get_queryset(self):
return self.request.user.locations.filter(deleted=False)
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.DATA, files=request.FILES)
if serializer.is_valid():
self.pre_save(serializer.object)
if not self.object.user:
self.object.user = request.user
self.object = serializer.save(force_insert=True)
self.post_save(self.object, created=True)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED,
headers=headers)
Thanks for any suggestion
You can use required=False in serializer:
class LocationSerializer(serializers.ModelSerializer):
user = serializers.RelatedField(required=False)
EDIT
Also you can simplify your viewset with:
class LocationViewSet(ModelViewSet):
def pre_save(self, obj):
if obj.user_id is None:
obj.user = self.request.user
This avoid copying code from DRF core.