I was searching through stackoverflow for example of working fileupload APIView (using DRF of latest versions), I've already tried with many different code samples but none worked (some of them are deprecated, some - isn't what i want)
I have these models:
class Attachment(models.Model):
type = models.CharField(max_length=15, null=False)
attachment_id = models.CharField(max_length=50, primary_key=True)
doc = models.FileField(upload_to="docs/", blank=True)
I don't wanna use forms and anything else but rest parsers
I want to get POST'ed fields (for example name) in future
I believe the solution is easy but this doesnt work
class FileUploadView(APIView):
parser_classes = (FileUploadParser,)
def post(self, request):
file_obj = request.FILES
doc = Attachment.objects.create(type="doc", attachment_id=time.time())
doc.doc = file_obj
doc.save()
return Response({'file_id': doc.attachment_id}, status=204)
removing parser_class will solve almost all problems here. Try the following snippet
class FileUploadView(APIView):
def post(self, request):
file = request.FILES['filename']
attachment = Attachment.objects.create(type="doc", attachment_id=time.time(), doc=file)
return Response({'file_id': attachment.attachment_id}, status=204)
Screenshot of POSTMAN console
Related
I was remaking a social media site as a revision of Django and the rest framework, I didn't want to use the django default linear id count and didn't like how long the uuid library's ids was, so I used the shortuuid library. I've used them on the posts and the comments just to keep the anonymity of the count of both posts and comments. On the posts side everything works for the CRUD stuff (which should be proof that the issue isn't from the shortuuid library, as far as I know), although with the comments the Create Retrieve works perfectly but the Update Destroy doesn't. so here is the code we are working with:
starting with the models to know what kind of data we are working with (models.py):
from shortuuid.django_fields import ShortUUIDField
... # posts likes etc
class Comment(models.Model):
id = ShortUUIDField(primary_key=True, length=8, max_length=10)
user = models.ForeignKey(User, on_delete=models.CASCADE)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
body = models.TextField(max_length=350)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
active = models.BooleanField(default=True)
class Meta:
ordering = ['created']
def __str__(self):
return f'on {self.post} by {self.user}'
objects = models.Manager()
serializers.py:
class CommentSerializer(ModelSerializer):
username = SerializerMethodField()
def get_username(self, comment):
return str(comment.user)
class Meta:
model = Comment
fields = ['id', 'user', 'post', 'username', 'body', 'created', 'updated']
read_only_fields = ['id', 'post', 'user', 'username']
now with the routing (urls.py):
from django.urls import path
from .views import *
urlpatterns = [
...
path('<str:pk>/comments/' , Comments),
path('<str:pk>/comments/create/', CreateComment),
path('<str:pk>/comments/<str:cm>/', ModifyComment),
# pk = post ID
# cm = comment ID
]
views.py:
class ModifyComment(generics.RetrieveUpdateDestroyAPIView):
serializer_class = CommentSerializer
permission_classes = [permissions.AllowAny]
def get_queryset(self):
post = Post.objects.get(pk=self.kwargs['pk'])
comment = Comment.objects.get(post=post, pk=self.kwargs['cm'])
return comment
def perform_update(self, serializer):
print(Post.objects.all())
post = Post.objects.get(pk=self.kwargs['pk'])
comment = Comment.objects.filter(pk=self.kwargs['cm'], post=post)
if self.request.user != comment.user:
raise ValidationError('you can\'t edit another user\'s post')
if comment.exists():
serializer.save(user=self.request.user, comment=comment)
else:
raise ValidationError('the comment doesnt exist lol')
def delete(self, request, *args, **kwargs):
comment = Comment.objects.filter(user=self.request.user, pk=self.kwargs['cm'])
if comment.exists():
return self.destroy(request, *args, **kwargs)
else:
raise ValidationError("you can\'t delete another user\'s post")
ModifyComment = ModifyComment.as_view()
and the response to going to the url '<str:pk>/comments/<str:cm>/' comment of some post we get this:
side note, the perform_update function doesn't seem to be called ever, even putting a print statement at the beginning of the function doesn't get printed so the issue may have to do with the get_queryset even though I've tried using the normal queryset=Comment.object.all() and making the get_queryset function return the comment with the correct params but I couldn't make it work
For individual objects you need to overwrite the get_object method.
You are performing the request GET /str:pk/comments/str:cm/, this calls the retrieve method on the view, which in turn calls get_object. The default behaviour is trying to find a Comment object with id equal to pk since it's the first argument, since you need to filter through a different model you need to overwrite it.
classy drf is a good website for seing how the internals of the clases work.
I'm trying to create a REST API with django-rest-framework which will be handling a few things, the one being sending and receiving images from the frontend. I found this article which tries to explain the idea, but it uses class-based approach in its' views.py and ideally I'd like to stick to a function-based one as I've already done some work that way (not including JWT authorization) and I'd prefer it to stay. I have no clue how to make my backend legible of receiving and sending images, could you please try to provide me with some code snippets (or better yet, articles) on how to do so? Thanks in advance!
One thing to mention is that ideally I want to have an endpoint which will handle creating a new object which will come with an image (a plant to be specific) and an endpoint which would handle updating (changing) the object's image.
My models.py:
class Plant(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
name = models.CharField(max_length=150)
date_added = models.DateField(auto_now_add=True)
description = models.TextField()
img = models.ImageField(blank=True, null=True, upload_to=upload_path)
plant_species = models.CharField(max_length=150)
last_watered = models.IntegerField(default=0)
how_often = models.IntegerField(default=0)
tracked=models.BooleanField(default=True)
My views.py:
class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
#classmethod
def get_token(cls, user):
token = super().get_token(user)
token['username'] = user.username
return token
class MyTokenObtainPairView(TokenObtainPairView):
serializer_class = MyTokenObtainPairSerializer
#api_view(['GET'])
def getRoutes(request):
routes = [
'/api/token',
'/api/token/refresh',
'/api/plants_data',
'/api/update_plant/<str:pk>'
]
return Response(routes)
#api_view(['GET'])
#permission_classes([IsAuthenticated])
def getPlants(request):
user = request.user
plants = user.plant_set.all()
serializer = PlantSerializer(plants, many=True)
return Response(serializer.data)
#api_view(['POST'])
#permission_classes([IsAuthenticated])
def updatePlantTracking(request, pk):
plant = Plant.objects.get(id=pk)
serializer = PlantSerializer(instance=plant, data=request.data, partial=True)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=400)
send images or any media files in json string from frontend and make a serializer field to handle the json string.
import base64
import uuid
from rest_framework.fields import Field
from rest_framework import serializers
class Base64ContentField(Field):
"""
For image, send base64 string as json
"""
def to_internal_value(self, data):
try:
format, datastr = data.split(';base64,')
ext = format.split('/')[-1]
file = ContentFile(base64.b64decode(datastr), name=str(uuid.uuid4())+'.'+ext)
except:
raise serializers.ValidationError('Error in decoding base64 data')
return file
def to_representation(self, value):
if not value:
return None
return value.url
Your PlantSerializer looks like
class PlantSerializer(serializers.ModelSerializer):
img = Base64ContentField(required=False)
class Meta:
model = Plant
fields = '__all__'
Your post data with img field will look like this
{
"name": "some name",
"img": "data:image/png;base64,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",
# ... other fields
}
You can convert images to base64 from this link; In the frontend like reactJS they have packages to convert image to base64 string
First of all, I'm pretty new to Django and equally new to backend development so please go easy on me.
I'm setting up a backend for a mobile application in which a user should be able to post an advert with an image attached to it over Http Requests. Right now, this works like it should, a user sends a POST request containing all the needed information and gets a response back containing all the relevant information, except for the image which is null. I know that the image successfully gets uploaded to the server, however I can't figure out how to return the URL of the image back into the response.
The following is my code:
models.py
class Advert(models.Model):
owner=models.ForeignKey(User, on_delete=models.CASCADE, related_name="adverts")
book_title = models.CharField(max_length=250)
price = models.PositiveSmallIntegerField()
created_at = models.DateTimeField(default=now())
def __str__(self):
return self.book_title + ' - ' + self.contact_info
class AdvertImage(models.Model):
advert = models.ForeignKey(Advert, on_delete=models.CASCADE, related_name="image", null=True)
image = models.ImageField(upload_to = 'ad_images', null=True)
def __str__(self):
return self.image.name
My serializers looks as following:
serializers.py
from rest_framework import serializers
from .models import Advert, AdvertImage
from drf_extra_fields.fields import Base64ImageField
from django.contrib.auth.models import User
class AdvertPostSerializer(serializers.ModelSerializer):
image = Base64ImageField(max_length=None, use_url=True, required=False)
class Meta:
model = Advert
fields = (
'id',
'price',
'book_title',
'image')
def create(self, validated_data):
try:
image_data = validated_data.pop('image')
except:
image_data = None
advert = Advert.objects.create(**validated_data)
if image_data is not None:
image = AdvertImage.objects.create(advert=advert, image=image_data)
return advert
And this is my view:
views.py
class AdvertViewSet(viewsets.ModelViewSet):
queryset = Advert.objects.all()
permission_classes = (AllowAny,)
def get_serializer_class(self):
if self.action == 'create':
return AdvertPostSerializer
return AdvertSerializer
#action(methods=['get'], detail=False)
def newest(self,request):
newest = self.get_queryset().order_by('created_at').last()
serializer = self.get_serializer_class()(newest)
return Response(serializer.data)
def perform_create(self, serializer):
return serializer.save(owner=self.request.user)
To illustrate what happens, here is a POST request:
POST http://localhost:8000/post-advert/
"Authorization: Token 980436128332ce3"
book_title=my book
price=1000
image=data:image/png;base64,iVBORHJvZmlsZSB0e//+egAAAAASUVORK5CYII=
And this is the response:
{
"book_title": "my book",
"id": 45,
"image": null,
"price": 1000,
}
Looking in the database and sending a second GET-request to another view shows that everything is uploaded as it should and the foreign keys and whatnot works like they should, it's just that I have a really hard time figuring out how to send back the URL of the image as a response to a successful POST.
Alright so I managed to come up with a (hacky?) solution.
In serializers.py i put my Base64Field as read_only=True:
class AdvertPostSerializer(serializers.ModelSerializer):
image = Base64ImageField(max_length=None, use_url=True, required=False, read_only=True)
...
Then, in my views.py for my AdvertViewSet, I've overwritten my create() method as such:
def create(self, request, format='json'):
serializer = PostAdvertSerializer(data=request.data)
if serializer.is_valid():
advert = serializer.save()
if advert:
json = serializer.data
advertImageURL = AdvertImage.objects.get(advert=advert).image.url
json['img_link'] = request.build_absolute_uri(advertImageURL)
return Response(json, status=status.HTTP_201_CREATED)
And this returns the full path to my image!
Because your get_queryset() method in
newest = self.get_queryset().order_by('created_at').last()
returns Advert model object:
class AdvertViewSet(viewsets.ModelViewSet):
queryset = Advert.objects.all()
which do not have image field. Then you are creating AdvertPostSerializer object and initializing it with newest queryset which is queryset of Advert model without your image.
serializer = self.get_serializer_class()(newest)
You can somehow obtain AdvertImage object inside #newest action and try to add it to response, but think you can create only one model Advert with your image field and one serializer for it, where you will define Base64ImageField.
I'm developing a social platform and currently coding the like functionality for user posts. However, I can't seem to make it work. These are my Models.py:
class Post(models.Model):
user = models.ForeignKey(User)
posted = models.DateTimeField(auto_now_add=True)
content = models.CharField(max_length=150)
picturefile = models.ImageField(upload_to="post_content", blank=True)
class Like(models.Model):
user = models.ForeignKey(User, null=True)
post = models.ForeignKey(Post, null=True)
I pass the post ID through my url as 'post_id', and then in my views:
def liking(request, post_id):
newlike = Like.objects.create()
newlike.post = post_id
newlike.user = request.user
newlike.save()
return redirect(reverse('dashboard'))
However, it returns the following error:
Cannot assign "'47'": "Like.post" must be a "Post" instance.
Does anyone knows what I'm missing or doing wrong?
You are passing newlike.post a number (integer field) while it is expecting a Post instance.
This sould work:
from django.http.shortcuts import get_object_or_404
def liking(request, post_id):
post = get_object_or_404(Post, id=post_id)
newlike = Like.objects.create(user=request.user, post=post)
return redirect(reverse('dashboard'))
Note 1: Better use the handy shortcut get_object_or_404 in order to raise a 404 error when the specific Post does not exist.
Note 2: By calling objects.create will automatically save into the db and return an instance!
newlike.post should be a Post object, not an int.
You need to find post by id first:
post = Post.objects.get(pk=post_id)
newlike.post = post
or, if you don't want to do this lookup:
newlike.post_id = post_id
I have this code:
#api model
class VideoResource(ModelResource):
class Meta:
queryset = Video.objects.all()
include_resource_uri = False
resource_name = 'video'
authorization = DjangoAuthorization()
class QuestionResource(ModelResource):
user = fields.ToOneField(UserResource,'user',full=True)
video = fields.ForeignKey(VideoResource,'video',full=True)
class Meta:
queryset = Question.objects.all()
resource_name = 'question'
include_resource_uri = False
authorization = DjangoAuthorization()
def obj_create(self, bundle, request=None, **kwargs):
import json
temp = json.loads(request.body, object_hook=_decode_dict)
video = Video.objects.get(pk=temp['video'])
return super(QuestionResource, self).obj_create(bundle, request, user=request.user, video=video)
#model
class Question(models.Model):
text = models.CharField('Question',max_length=120)
created = models.DateTimeField(auto_now_add=True)
enabled = models.BooleanField(default=True)
flag = models.BooleanField(default=False)
allow_comments = models.BooleanField(default=True)
thumbnail_url = models.CharField(default='video.jpg',blank=True, null=True,max_length=200)
user = models.ForeignKey(User)
video = models.ForeignKey(Video)
def __unicode__(self):
return self.text;
class Video(models.Model):
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now_add=True)
url = models.URLField(default="")
user = models.ForeignKey(User)
def __unicode__(self):
return str(self.pk) + ' > ' + self.status
The problem is that I am getting this error when sending this object:
{"video":21,"text":"sadasds"}
The 'video' field has was given data that was not a URI, not a
dictionary-alike and does not have a 'pk' attribute: 21.
If I comment this line:
video = fields.ForeignKey(VideoResource,'video',full=True)
Everything works fine, but then I cannot get this information (video)
when asking to /api/v1/questions/
My question is:
Should I create to resources, one to post and another to retrieve
information <- this seems not a really good solution.
or
How can I create Nested Resources ? I tried to follow the example on
the web http://django-tastypie.readthedocs.org/en/latest/cookbook.html#nested-resources
but as you can see for some reason is not working.
maybe your eyes can help me find the error :)
Thanks!
The 'video' field has was given data that was not a URI, not a dictionary-alike and does not have a 'pk' attribute: 21.
So, this means that the integer 21 does't meet the requirements for that field, it also give a vague hint of what will meet the requirements.
first, you can send in the URI for the record, this is probably the most correct way as URIs are really unique while pk's are not.
{"video":"/api/v1/video/21","text":"sadasds"}
or, you can send in an dictionary-alike object with the pk field set.
{"video":{'pk':21},"text":"sadasds"}
The reason it works when you comment out the ForeignKey field is because then tastypie treats it as a IntegerField, which can be referenced by a plain integer.
This had me stunted for a while to, hope it helps!