I'm currently uploading images through an API created by with Django REST framework with angularJS.
However, the problem is that it is stored as a media file but not stored in a database.
Here is my ViewSet code.
# views.py
import time
from rest_framework import viewsets
from rest_framework.permissions import IsAdminUser
from django.contrib.auth import get_user_model
from .serializers import UserSerializer
class UserViewSet(viewsets.ModelViewSet):
permission_classes = (IsAdminUser,)
serializer_class = UserSerializer
queryset = get_user_model()
def perform_update(self, serializer):
serializer.save(profile_image=self.request.data.get('file'))
But, when I added the code time.sleep(1) before serializer.save() function, it was mysteriously saved to the database successfully.
def perform_update(self, serializer):
time.sleep(1) # Delay 1s
serializer.save(profile_image=self.request.data.get('file'))
Why does this happen? And please give me a wise solution.
I don't know if it would help, so I attached the angularjs code.
.service('fileUpload', ['$http', function ($http) {
this.uploadFileToUrl = function(file, uploadUrl){
var fd = new FormData();
fd.append('file', file);
return $http.patch(uploadUrl, fd, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
})
}
}])
This is my User model I was requested to share. I omitted the code that are not related to the error.
I confirmed that the image was saved in the path I specified. But not saved in database.
# models.py
import datetime
import os
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
from django.db import models
def set_filename_format(now, instance, filename):
return "{username}-{date}-{microsecond}{extension}".format(
username=instance.username,
date=now.date().strftime("%Y-%m-%d"),
microsecond=now.microsecond,
extension=os.path.splitext(filename)[1],
)
def profile_image_path(instance, filename):
now = datetime.datetime.now()
path = "profile_images/{username}/{year}/{month}/{day}/{filename}".format(
username=instance.username,
year=now.year,
month=now.month,
day=now.day,
filename=set_filename_format(now, instance, filename),
)
return path
class User(AbstractBaseUser, PermissionsMixin):
# ...
profile_image = models.ImageField(
upload_to=profile_image_path,
blank=True,
)
# ...
Related
views.py
from . import models, serializers
from rest_framework import viewsets, status
from rest_framework.response import Response
from rest_framework.views import APIView
class getSongData(APIView):
serializer_class=serializers.SongSerializer
def get(self, request, id, format=None):
serializer = serializers.SongSerializer(models.Song.objects.get(id=id))
file_loc = serializer.data['audio_file'] # go below to see the data
# read the mp3 file
return Response(file_data)
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('songs/audio/<int:id>', views.getSongData.as_view(), name='audio')
]
serializers.py
from rest_framework import serializers
from . import models
class SongSerializer(serializers.ModelSerializer):
class Meta:
model = models.Song
fields = '__all__'
models.py
from django.db import models
from datetime import datetime
class Song(models.Model):
title = models.CharField(max_length=64)
audio_file = models.FileField()
genre = models.CharField(max_length=64)
created_at = models.DateTimeField(default=datetime.utcnow)
The data
[
{
"id": 1,
"title": "Kubbi | Cascade",
"audio_file": "/media/Kubbi__Cascade.mp3",
"genre": "Instrumental",
"created_at": "2021-07-24T10:21:48Z"
}
]
When the user clicks on a song (lets say the song's id=1), a request gets sent to 'http://localhost:8000/api/songs/audio/1' then in views.py I extract the song's location via serializer.data['audio_file'] which is = "/media/Kubbi__Cascade.mp3", all i want to do is to read this audio file and send the data as a Response back to the frontend, I tried many solutions but they were throwing errors...
if you want to do it using pure django this would work
from django.http import FileResponse
class getSongData(APIView):
serializer_class=serializers.SongSerializer
def get(self, request, id, *args, **kwargs):
song = models.Song.objects.get(id=id)
return FileResponse(song.audio_file.open())
but preferably you should serve files through a reverse proxy for better performance.
I am using Django 3.0 djangorestframework==3.11.0. I have created a task update view and passing the pk to url. The problem is - Although I have set the serializer instance to the model object I want to update. The serializer instance is not showing up.
models.py
from django.db import models
# Create your models here.
class Task(models.Model):
title = models.CharField(max_length=200)
completed = models.BooleanField(default=False, blank=True, null=True)
def __str__(self):
return self.title
serializers.py
from rest_framework import serializers
from .models import Task
class TaskSerializer(serializers.ModelSerializer):
class Meta:
model = Task
fields = '__all__'
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.apiOverview, name='api-overview'),
path('task-list/', views.taskList, name='task-list'),
path('task-detail/<str:pk>/', views.taskDetail, name='task-detail'),
path('task-create/', views.taskCreate, name='task-create'),
path('task-update/<str:pk>/', views.taskUpdate, name='task-update'),
]
views.py
from django.shortcuts import render
from rest_framework.decorators import api_view
from rest_framework.response import Response
from .models import Task
from .serializers import TaskSerializer
#api_view(['POST'])
def taskUpdate(request, pk):
task = Task.objects.get(id=pk)
serializer = TaskSerializer(instance=task, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
expected behavior on url http://localhost:8000/api/task-update/4/
actual behaviour on http://localhost:8000/api/task-update/4/
as you can see the content field is empty but I want the already associated json to be shown there with pk = 4.
I am trying to create a Restful Api for following methods to run jenkins jobs to run on saucelabs. I wanna queue jobs using restful API. I am using Django Restful Framework.
CreateMethod :
Accepts two fileds: ProjectName and URL
and returns a Token ID.
VerifyStatus:
Accepts Token ID and returns three fields. TokenID, running:True/False and
no_of_jobs: integervalue (0 if Not specified)
relseaseMethod:
Accepts release token call and returns true if success.
I am new to Restful API with, I am trying to run Jenkins job on sauce lab and queue them using a restful api on python Djano restframework. Guide me through.
Views.py
class RegisterTestMethodView(APIView):
authentication_classes = [SessionAuthentication, TokenAuthentication, BasicAuthentication]
permission_classes = [IsAuthenticated] #No access (not even read if not authorized)
def post(self, request, format=None):
serializer = RegisterTestMethodSerializers(data=request.data)
if serializer.is_valid():
serializer.save()
return Response({'tokenid':serializer.data['id']}, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class CheckStatusView(APIView):
def get_object(self, pk):
try:
return Jobs.objects.get(pk=pk)
except Jobs.DoesNotExist:
raise Http404
def get(self, request, pk, format=None):
snippet = self.get_object(pk)
serializer = RegisterTestMethodSerializers(snippet)
return Response({"tokenid":serializer.data["id"], "Runtestnow" : False, "VMcount" : 0 })
class ReleaseTokenView(APIView):
def get_object(self, pk):
try:
return Jobs.objects.get(pk=pk)
except Jobs.DoesNotExist:
raise Http404
def delete(self, request, pk, format=None):
snippet = self.get_object(pk)
snippet.delete()
return Response(data={'Deleted':True}, status=status.HTTP_204_NO_CONTENT)
Serailizers.py
rom rest_framework import serializers
from .models import Jobs
from random import random
RegisterTestMethodSerializers(serializers.HyperlinkedModelSerializer):
class Meta:
model = Jobs
fields = ('id','name','url')
Models.py
from django.db import models
# Create your models here.
class Jobs(models.Model):
name = models.CharField(max_length=100)
url = models.URLField()
def __str__(self):
return self.name
Urls.py
from django.urls import path, include
from . import views
from .views import (RegisterTestMethodView,
RegisterTestMethodViewDetail,
CheckStatusView,
ReleaseTokenView
)
from rest_framework import routers
from rest_framework.authtoken.views import obtain_auth_token
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
urlpatterns = [
path('', include(router.urls)),
path('registertestmethod/',RegisterTestMethodView.as_view()),
path('registertestmethod/<int:pk>/',
RegisterTestMethodViewDetail.as_view()),
path('checkstatus/<int:pk>', CheckStatusView.as_view()),
path('releasetoken/<int:pk>', ReleaseTokenView.as_view()),
]
I have addded my Code here. I have other classes and function in my project as well.I tried to delete all of those. You might see extra import as a result of that. My code does following things.
POST --> http://localhost:8000/registertestmethod/
{
"name": "Name",
"url": "https://www.google.com"
}
returns
{
"tokenid": 32 #unique token ID return
}
This tokenid should be long I am using id as of now.
GET --> http://localhost:8000/checkstatus/32
is returning
{
"tokenid": 32, #unique tokenid refering to register info
"Runtestnow": false, #if job is running
"VMcount": 0 # number of VM used in sauce lab by the Jobs
}
DELETE --> http://localhost:8000/releasetoken/32 #should delete the jobs after done.
is deleting and returning
{
"Deleted": true
}
I want it to be dynamic and store info in database. Token should return everything on checkstatus.
You can use the ModelViewSet approach for this, this here is a very simple example for an API endpoint.
views.py
from rest_framework.viewsets import ModelViewSet
from api.serializers import SaucelabsSerializer
from rest_framework.response import Response
class SaucelabModelViewSet(ModelViewSet):
serializer_class = SaucelabSerializer
queryset = Sauselab.objects.all()
http_method_names = ['get', 'head', 'options', 'post']
def create(self, request):
pnam = request.data.get('project_name', None)
url = request.data.get('url', None)
if pnam and url:
# do something here
return Response({'success': 'Your success message'}, status=status.HTTP_200_OK)
else:
return Response({"error": "Your error message"}, status=status.HTTP_400_BAD_REQUEST)
serializers.py
from rest_framework.serializer import ModelSerializer
from appname.models import Saucelab
class SaucelabSerializer(ModelSerializer):
class Meta:
model = Saucelab
fields = '__all__'
appname/models.py
from django.db import models
class Saucelab(models.Model)
project_name = models.CharField(max_length=255)
url = models.URLField()
urls.py
from rest_framework.routers import DefaultRouter
from api import views
router = DefaultRouter()
router.register('your-endpoint-name', views.SaucelabModelViewSet, basename='your-url-name')
urlpatterns = []
urlpatterns += router.urls
This is a very basic example, where you create a model called saucelab which has the two fields you require, ie.project_name and url.
We create a app called api with two files inside it that aren't auto generated, serializers.py and urls.py. We create the most basic model serializer and ask it to serialize all fields of model Saucelab. Then we create a simple modelviewset which out of the box gives you a CRUD functionality. You can override the create method if you need to run some specific conditions otherwise dont override any methods and just make request to the endpoint with appropriate HTTP methods.
Here are a few links you can read
https://www.django-rest-framework.org/api-guide/viewsets/#modelviewset
https://www.django-rest-framework.org/api-guide/serializers/#modelserializer
To generate a random token
from django.utils.crypto import get_random_string
print(get_random_string(length=25))
output
u'rRXVe68NO7m3mHoBS488KdHaqQPD6Ofv'
In fact, I need your help to limit my API to upload
I only need Jason and excel formats(csv,xls,xlsl) on the server-side, but I did not find any code for that.
The second question is, what methods should I use to authenticate the user?
Here's a link that I use its code in my API
in fact, I need fix this part:
from django.shortcuts import render
# Create your views here.
from rest_framework.views import APIView
from rest_framework.parsers import MultiPartParser, FormParser, JSONParser
from rest_framework.response import Response
from rest_framework import status
from .serializers import FileSerializer
class FileView(APIView):
parser_classes = (MultiPartParser, FormParser)
def post(self, request, *args, **kwargs):
file_serializer = FileSerializer(data=request.data)
if file_serializer.is_valid():
file_serializer.save()
return Response(file_serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(file_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def get():
pass
def update():
pass
my model :
from django.db import models
class File(models.Model):
file = models.FileField(blank=False, null=False)
remark = models.CharField(max_length=20)
timestamp = models.DateTimeField(auto_now_add=True)
and my serializers :
from rest_framework import serializers
from .models import File
class FileSerializer(serializers.ModelSerializer):
class Meta():
model = File
fields = ('file', 'remark', 'timestamp')
but I didn't know how most make it limit
my Django version is 2 AND my python version is 3
I will thank you if you help me :)
have to go coding time
I'm trying to create an user and his profile through DRF, but I don't find the correct way to do it.
Here's my models.py
from __future__ import unicode_literals
from django.contrib.auth.models import User
from rest_framework.authtoken.models import Token
from django.db import models
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, blank=True, null=True)
language = models.CharField(max_length=4, default='es')
def __unicode__(self):
return "%s - %s" % (self.user, self.language)
my serializers.py
from rest_framework import serializers
from models import Profile
from django.contrib.auth.models import User
from django.contrib.auth import get_user_model
class ProfileCreateSerializer(serializers.ModelSerializer):
username = serializers.CharField(source='user.username')
class Meta:
model = Profile
fields = [
'username',
'language',
]
def create (self, validated_data):
user = get_user_model().objects.create(username=validated_data['username'])
user.set_password(User.objects.make_random_password())
user.save()
profile = Profile.objects.create(user = user)
return profile
my views.py
from rest_framework.response import Response
from rest_framework.generics import CreateAPIView
from serializers import ProfileCreateSerializer
from models import Profile
class ProfileCreateAPIView(CreateAPIView):
model = Profile
serializer_class = ProfileCreateSerializer
My urls.py
from django.conf.urls import patterns, include, url
import views
from django.contrib import admin
urlpatterns = [
url(r'^', views.ProfileCreateAPIView.as_view(), name='crear perfil'),
]
if I try to create it shows me this error:
Cannot assign "{u'username': u'test'}": "Profile.user" must be a "User" instance.
if i create an user and his profile via admin panel doesn't show me any error.
my admin.py:
from django.contrib import admin
from models import Profile
from django.contrib.auth.admin import UserAdmin
class ProfileInline(admin.StackedInline):
model = Profile
can_delete = False
verbose_name_plural = 'Perfil'
fk_name = 'user'
class UserAdmin(UserAdmin):
inlines = (ProfileInline,)
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
I'm using django 1.9.1 and django rest framework 3.3.2
Why do you need UserSerializer at first place? Change your ProfileCreateSerializer to following. It should work
class ProfileCreateSerializer(serializers.ModelSerializer):
username = serializers.CharField(source='user.username')
class Meta:
model = Profile
fields = [
'username',
'language',
]
def create (self, validated_data):
user = get_user_model().objects.create(username=validated_data['username'])
user.set_password(User.objects.make_random_password())
user.save()
profile = Profile.objects.create(user = user)
return profile
Since the create method is override at your serializer, you need to send the data as a format the serializer process. So, you need to override the POST request at the views and create data as follows :
from rest_framework import status
from rest_framework.response import Response
class ProfileCreateAPIView(CreateAPIView):
model = Profile
serializer_class = ProfileCreateSerializer
def post(self, request, *args, **kwargs):
data = {
'username': request.data.get('username', None),
'language': request.data.get('language', None),
}
serializer = ProfileCreateSerializer(data=data)
if serializer.is_valid():
serializer.save()
return Response(
serializer.data, status=status.HTTP_201_CREATED)
else:
return Response( serializer.errors, status=status.HTTP_400_BAD_REQUEST)