Django rest-framework creating a view without model - django

I am pretty new to Django rest-framework and trying to render a simple JSON view not based on the model. I could not figure out how to do this since all of the examples involves rendering JSON from the Model classes. Below is the simple example what I was trying to do.
class CommentSerializer(serializers.Serializer):
email = serializers.EmailField()
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()
class Comment(object):
def __init__(self, email, content, created=None):
self.email = email
self.content = content
self.created = created or datetime.now()
def comment_view(request):
comment = Comment(email='leila#example.com', content='foo bar')
serializer = CommentSerializer(comment)
json = JSONRenderer().render(serializer.data)
return json

You can use it like here:
from rest_framework.decorators import api_view
from rest_framework.response import Response
#api_view()
def comment_view(request):
comment = Comment(email='leila#example.com', content='foo bar')
serializer = CommentSerializer(comment)
return Response(serializer.data)
Finally don't forget to put it in the urls.py:
urlpatterns = [
path('comments/', comment_view, name='comment-view'),
]

Related

Django Rest Framework, request POST, update if exists, create if not exists from mass data of POST request

I am building an API for users info data
I want to make that when the POST request, execute function "create", "update"
if from POST request user exists:
update (full_name, function, department, logon, system, lic_type )
if from POST request user doesn't exist:
create (user, full_name, function, department, logon, system, lic_type )
models.py
from django.db import models
class Users(models.Model):
user = models.CharField(max_length=50,blank=True, null=True)
full_name = models.CharField(max_length=200, blank=True, null=True)
function = models.CharField(max_length=300,blank=True, null=True)
department = models.CharField(max_length=300,blank=True, null=True)
logon = models.DateTimeField(blank=True, null=True)
system = models.CharField(max_length=300,blank=True, null=True)
lic_type = models.CharField(max_length=300,blank=True, null=True)
serizlizers.py
from rest_framework import serializers
from .models import Users
class UsersSerializer(serializers.ModelSerializer):
logon = serializers.DateTimeField(input_formats=settings.DATE_INPUT_FORMATS)
class Meta:
model = Users
# fields = '__all__'
fields = ['user', 'full_name', 'function', 'department', 'logon', 'system', 'lic_type']
views.py
from django.http.response import JsonResponse
from rest_framework.parsers import JSONParser
from rest_framework import status
from .models import Users
from .serializers import UsersSerializer
from rest_framework.decorators import api_view, authentication_classes
from rest_framework.response import Response
from django.views.decorators.csrf import csrf_exempt
from rest_framework.authentication import BasicAuthentication
#csrf_exempt
#api_view(['GET', 'POST'])
#authentication_classes([BasicAuthentication])
def users_list(request):
if request.method == 'GET':
users = Users.objects.all()
user = request.GET.get('user', None)
if user is not None:
users = users.filter(user__icontains=user)
users_serializer = UsersSerializer(users, many=True)
return JsonResponse(users_serializer.data, safe=False)
elif request.method == 'POST':
users_data = JSONParser().parse(request)
users_serializer = UsersSerializer(data=users_data, many=True)
if users_serializer.is_valid():
users_serializer.save()
return Response(users_serializer.data, status=status.HTTP_201_CREATED)
return Response(users_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('users/', views.users_list),
]
I could do like this, when POST request delete all from database and create data from POST request
elif request.method == 'POST':
users = Users.objects.all()
users.delete()
users_data = JSONParser().parse(request)
users_serializer = UsersSerializer(data=users_data, many=True)
if users_serializer.is_valid():
users_serializer.save()
return Response(users_serializer.data, status=status.HTTP_201_CREATED)
return Response(users_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
but instead I want to make update_or_create()
I tried like so, but this only creates empty row in database
user_name = request.POST.get('user')
user, created = Users.objects.update_or_create(user = user_name)
user.full_name = request.POST.get('full_name')
user.function = request.POST.get('function')
user.department = request.POST.get('department')
user.logon = request.POST.get('logon')
user.system = request.POST.get('system')
user.lic_type = request.POST.get('lic_type')
user.save()
return Response(user, status=status.HTTP_201_CREATED)
thanks for any help
The best way is when a POST is there, you first retrieve the item from the database (using django's utility get_object_or_404) and have restframework update all fields you set as non-readonly in the serializer.
Example:
# on top import
from django.shortcuts import get_object_or_404
....
elif request.method == 'POST':
# add here the query you determine is user already exists, usually a unique ID or UUID
user_object = get_object_or_404(Users, id=request.data.get('id'))
users_data = JSONParser().parse(request)
users_serializer = UsersSerializer(user_object, data=users_data, many=True)
if users_serializer.is_valid():
users_serializer.save()
return Response(users_serializer.data, status=status.HTTP_201_CREATED)
return Response(users_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Something like this ought to work. You still need to tweak it a little the get object

How to retrieve data based on specific field in Django Rest Framework using RetrieveAPIView?

With the code below, I am able to retrieve data based on id, how can I update this code so I can retrieve data based on fileName instead?
My urls is
urlpatterns = [
path("items/<pk>", SingleUploadItem.as_view()),
]
My views is:
class SingleUploadItem(RetrieveAPIView):
queryset = fileUpload.objects.all()
serializer_class = fileUploadSerializer
My model is
class fileUpload(models.Model):
fileName = models.CharField(max_length=200, unique=True, blank=True)
First, in urls.py
urlpatterns = [
path("items/<str:file_name>", SingleUploadItem.as_view()),
]
And in views.py,
from rest_framework import status
from .models import fileUpload
from .serializers import FileUploadSerializer
class SingleUploadItem(RetrieveAPIView):
queryset = fileUpload.objects.all()
serializer_class = fileUploadSerializer
def get(self, request, file_name):
try:
fileupload_obj = fileUpload.objects.get(fileName = file_name)
return Response(FileUploadSerializer(fileupload_obj).data)
except fileUpload.DoesNotExist:
return Response(status = status.HTTP_400_BAD_REQUEST)

Django+React rest-auth

I am using the rest-auth module to enable user authentication on my web app. Though I am facing some difficulties in fetching details about the user. The Django-rest-framework return a key when I post my username and password, while that's enough for logging in I also want to fetch additional details like user.is_staff, user.username and user.email.
I tried to use Token serializer, but I am not sure if I am doing it right.
** settings.py **
REST_AUTH_SERIALIZERS = {
'TOKEN_SERIALIZER': '## How to define the path to my serializer ##',
}
** serializers.py **
from rest_framework import serializers
from lms.models.post_models import Post
from django.contrib.auth.models import User
from rest_auth.models import TokenModel
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('username', 'email')
class TokenSerializer(serializers.ModelSerializer):
user = UserSerializer()
class Meta:
model = TokenModel
fields = ('key', 'user')
Please tell what piece is missing or if any piece is incorrect. Also, please help me figure out the part between ## ##.
Thank you!
I think you are doing it right, in your custom TokenSerializer you need to fetch the user somehow. If I look at the code of the LoginView, I see that you can use request object from context within serializer, so your TokenSerializer should be like:
# serializers.py
class TokenSerializer(serializers.ModelSerializer):
user = serializers.SerializerMethodField()
class Meta:
model = TokenModel
fields = ('key', 'user')
def get_user(self, instance):
request = self.context.get('request')
return UserSerializer(request.user).data
and then settings.py
REST_AUTH_SERIALIZERS = {
'TOKEN_SERIALIZER': 'project.serializers.TokenSerializer',
}
EDITED:
This might break your register view because if you look at the source code, at line 60 it uses the same serializer but doesn't pass the request object in the context of serializer. You can make it work by overriding this method
# views.py
from django.conf import settings
from rest_auth.registeraion.views import RegisterView
from allauth.account import app_settings as allauth_settings
from rest_auth.app_settings import (TokenSerializer,
JWTSerializer)
class CustomRegisterView(RegisterView):
def get_response_data(self, user):
if allauth_settings.EMAIL_VERIFICATION == \
allauth_settings.EmailVerificationMethod.MANDATORY:
return {"detail": _("Verification e-mail sent.")}
if getattr(settings, 'REST_USE_JWT', False):
data = {
'user': user,
'token': self.token
}
return JWTSerializer(data).data
else:
return TokenSerializer(user.auth_token, context={"request": self.request}).data
and then use this view for registration in your urls
# urls.py
from views import CustomRegisterView
urlpatterns = [
...,
url(r'^rest-auth/', include('rest_auth.urls')),
url(r'^rest-auth/registration/', CustomRegisterView.as_view())
]

Django Restful API Design Validation Logic

Here I have an endpoint to create media content for users. The endpoint works, but I have a feeling my design implementation is incorrect.
Should validation logic be contained in serializers create? Is this bad practice? I attempted to move validation logic to models.py, but ran into issues with accessing the model, specifically this line - self.model(user=user, category=category).
view.py
from rest_framework import status
from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from .models import UserMedia
from .renderers import UserMediaSerializerJSONRenderer
from .serializers import UserMediaSerializer
class UserMediaCreateAPIView(APIView):
permission_classes = (IsAuthenticated,)
renderer_classes = (UserMediaSerializerJSONRenderer,)
serializer_class = UserMediaSerializer
def post(self, request):
userMedia = request.data.get('userMedia', {})
serializer = self.serializer_class(data=userMedia)
serializer.is_valid(raise_exception=True)
serializer.save(user=request.user, category=userMedia['category'])
return Response(serializer.data, status=status.HTTP_201_CREATED)
serializers.py
from rest_framework import serializers
from .models import UserMedia
class UserMediaSerializer(serializers.ModelSerializer):
category = serializers.CharField(allow_blank=False, required=True)
class Meta:
model = UserMedia
fields = ('category',)
read_only_fields = ('category',)
def get_category(self, obj):
if obj.category:
return obj.category
return 'N/A'
def create(self, validated_data):
if validated_data['user'] is None:
raise TypeError('User media must have a user')
if validated_data['category'] is None:
raise TypeError('User media must have a category.')
if validated_data['category'] not in dict(UserMedia.CATEGORY_CHOICES):
raise TypeError('User media category is not available.')
userMedia = UserMedia(**validated_data)
userMedia.save()
return userMedia
models.py
from django.db import models
class UserMedia(models.Model):
user = models.ForeignKey('authentication.User', on_delete=models.CASCADE, related_name='media')
MUSIC = 'M'
VIDEO = 'V'
CATEGORY_CHOICES = (
(MUSIC, 'Music'),
(VIDEO, 'Video'),
)
category = models.CharField(max_length=1, choices=CATEGORY_CHOICES, blank=False)
The validation should be done in your view. The serializers should just be for serializing data. The validation should be done in your view then the serializer is called from your view. As far as this line self.model(user=user, category=category) is concerned it does not appear that you ever import user any where.

What is the proper implementation of 'obj_get' in Django Tastypie?

I'm quite new to Django & Tastypie. I would like to return only one of the objects from the query. I've tried almost everything and cannot seem to find the solution. Here is my code below:
class ProfileResource(ModelResource):
person = fields.ForeignKey(UserResource, 'user', full=True)
class Meta:
queryset = Person.objects.all()
resource_name = 'profile'
authentication = BasicAuthentication()
authorization = DjangoAuthorization()
serializer = Serializer(formats=['json'])
Now the part I'm having trouble with is how can I return a single user object from a single resource using request.user.
If you only want to show one resource I would probably create new resource view (named as my_profile) that would call normal detail view with user in kwargs and removed other urls:
from django.conf.urls import url
from tastypie.utils import trailing_slash
class ProfileResource(ModelResource):
...
def base_urls(self):
return [
url(r"^(?P<resource_name>%s)%s$" % (self._meta.resource_name, trailing_slash()), self.wrap_view('dispatch_my_profile'), name="api_dispatch_my_profile")
]
def dispatch_my_profile(self, request, **kwargs):
kwargs['user'] = request.user
return super(ProfileResource, self).dispatch_detail(request, **kwargs)