Is it possible to perform raw queries in django rest framework like django. https://docs.djangoproject.com/en/dev/topics/db/sql/#performing-raw-queries
Yes you should be able to, since you can customize the queryset that backs your view, e.g.
class MyModelViewSet(viewsets.ModelViewSet):
# The usual stuff here
model = MyModel
def list(self, request):
queryset = MyModel.objects.raw('... your SQL here...')
serializer = MyModelSerializer(queryset, many=True)
return Response(serializer.data)
Manager.raw() returns RawQuerySet which is a QuerySet, so you can see how it all fits
Related
I have been using Django for some time, but running into some issues with trying something new.
I have built API's with Django-Rest-Framework using Class Based Views, and I have also built API's using Function based views returning a JsonResponse
Now what I am tasked to do is use CBV's to return a JsonResponse without using DRF. I am trying to produce a simple get request
class BusinessDetailView(DetailView):
model = BusinessDetail
def get_queryset(self):
business = BusinessDetail.objects.get(id=self.kwargs.get('pk'))
return JsonResponse({'business': list(business)})
Using the models pk I keep running into issues with this simple request. I am getting a TypeError 'BusinessDetail' object is not iterable and if I make some small changes and override get_object I'll get the same error, or I'll even get a 'BusinessDetail' object is not callable
Does anybody have any tips with using CBVs to return Json, without using DRF?
Thank you all in advance!
i would try something like this:
class BusinessDetailView(DetailView):
model = BusinessDetail
def get_queryset(self):
business = BusinessDetail.objects.get(id=self.kwargs.get('pk'))
return business
def get(self, request, *args, **kwargs):
queryset = self.get_queryset()
data = serializers.serialize("json", queryset)
return JsonResponse(data, status=200, safe=False)
Here is my code. I get no errors, and I can see the search button that was added to the browsable API. The problem though is the search does not work. No matter what I type into the search, it just returns every objects.
from rest_framework import status, filters
class JobView(GenericAPIView):
serializer_class = JobSerializer
filter_backends = [filters.SearchFilter]
search_fields = ['name']
def get_queryset(self):
return Job.manager.all()
def get(self, request, format=None):
queryset = self.get_queryset()
if queryset.exists():
serializer = JobSerializer(queryset, many=True)
return Response(serializer.data)
else:
return Response({"Returned empty queryset"}, status=status.HTTP_404_NOT_FOUND)
endpoint
http://localhost:8000/jobs/?search=something
returns the same as
http://localhost:8000/jobs/
No matter what I put in the search string, it returns jobs.
This basically doesn't work because you're trying to do too much. You've written your own get method which bypasses all the magic of the DRF views. In particular, by not calling GenericAPIView.get_object, you avoid a line that looks like
queryset = self.filter_queryset(self.get_queryset())
which is where the QuerySet is filtered. This simpler version, practically identical to the one in the SearchFilter docs, should work
from rest_framework import status, filters, generics
class JobView(generics.LisaAPIView):
queryset = Job.manager.all()
serializer_class = JobSerializer
filter_backends = [filters.SearchFilter]
search_fields = ['name']
NOTE based on your question, I am assuming:
that your Job model has a name field
that for some reason you've renamed the Job manager to manager via a call to models.Manager()
I think you should filter your queryset based on the parameter you're sending via GET, because it wont happen automatically. use request.query_params.get('search') to access your parameter.
I have started using GenericAPIView instead of APIView and I am confused about the use of queryset and serializer_class being defined at the top of the class.
I understand these have to be defined, but I now have a query at the top of my class and another query inside GET. My question is can I use the queryset inside of my GET method so I am not making 2 unnecessary queries.
class demo(GenericAPIView):
queryset = Demo.objects.all()
serializer_class = DemoSerializer
def get(self, request, num, format=None):
query = Demo.objects.filter(name=test, number=num)
In other words, queryset = Demo.objects.all() is defined because it is required - but I am not really utilizing it so seems like an extra query...
queryset required only in case you not defined get_queryset method. In your case instead of define additional queryset in get, just implement get_queryset. If you are using url's kwargs, you can get it inside this method with self.kwargs attribute:
class demo(GenericAPIView):
serializer_class = DemoSerializer
def get_queryset(self):
return Demo.objects.filter(name=test, number=self.kwargs['num'])
I'm building a social app which has a "like" feature, I'm using django-redis to store "like" numbers from every post like this:
from django_redis import get_redis_connection
con = get_redis_connection("default")
con.incr("post" + ":" + id)
From the doc Raw client access
It works great, and I also use django-rest-framework to provide api, ListCreateAPIView to list all posts.Usually it will display any fields you want in the database. The problem here is now I wanna display "like" count from django-redis in this API which means the json return are from my database and django-redis.
I had look around the source code about django-rest-framework
class ListCreateAPIView(mixins.ListModelMixin,mixins.CreateModelMixin,
GenericAPIView):
"""
Concrete view for listing a queryset or creating a model instance.
"""
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
and the list method:
class ListModelMixin(object):
"""
List a queryset.
"""
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)
return Response(serializer.data)
It seems like I can only get data from the database queryset(which I use Mysql). Any possible way to return data from django-redis with django-rest-framework?
Solved:
Thanks answer from #Rahul Gupta, I do a little hack to work better:
def get_likes(self, obj):
post_id = obj.id
post_like = get_redis_connection("default")
likes = post_like.get("post"+":"+str(post_id))
if likes == None:
return 0
else:
likes = likes.decode('utf-8')
return likes
You can add a 'likes' SerializerMethodField in your PostSerializer to add likes in the serialized representation of the object.
class SocialPostSerializer(serializers.ModelSerializer):
likes = serializers.SerializerMethodField() # define field
class Meta:
model = SocialPost
def get_likes(self, obj):
social_post_id = obj.id
# here write the logic to get the no. of likes
# for a social post using the 'social_post_id' from redis
return likes
Now, the serialized data returned by DRF in list requests will contain a parameter likes along with other parameters.
Maybe this is not the kind of answer you're looking for, but my suggestion would be to take a look at Cacheops.
It provides an automatic caching/invalidation mechanism for your django models, so you will not have to handle different lookups for redis and db in your code, just use the default django orm and in the background it will handle the memory caching for you. If you anyway store the likes both in db and redis, this is a better solution in my opinion.
I am attempting to do a search using Django Haystack and then upon retrieving results I need to pass these results to my Django Rest Framework serializer.
The Django Rest Framework serializers.ModelSerializer requires that a queryset of objects gets sent for the serializer to be able to serialize these objects along with their database fields.
When I create my API view and use search to get results haystack returns a searchqueryset.
How could I get this searchqueryset into a django queryset without doing something like:
article_queryset = Article.objects.filter(id__in=[i.object for i in searchqueryset])
As you could imagine, sometimes search can return excess of 1000 search results which means that the above would be very inefficient.
Right now the Django rest framework allows me to paginate my returned objects. I am paginating by 30 objects on each page. How would it be possible for me to do the same with my Haystack searchqueryset?
Any advice or ideas on how to use Haystack along with Django Rest Framework would be great. Examples of how others have done a similar thing would be cool too :)
You could use Haystack's SearchView (instead of a DRF view) which exposes the page object for pagination. Then you can just pass that to your serializer.
E.G. Awhile back I was working on something that required the json object of the rendered results on the current HTML page, so I wrote a filter tag to do this (we were using FacetedSearchView for the UI, and DRF for a more general purpose RESTful API). Called like so in the template:
var articlesJson = {{ page.object_list|article_jsonify }}
Actual filter tag:
import collections
from django.template import Library
from django.utils.safestring import mark_safe
from rest_framework.renderers import JSONRenderer
register = Library()
def article_jsonify(object):
if isinstance(object, collections.Iterable):
many = True
ids = [obj.object.id for obj in object]
else:
many = False
ids = [object.id]
articles = Article.objects.filter(pk__in=ids)
serializer = ArticleSerializer(articles, many=many)
content = JSONRenderer().render(serializer.data)
return mark_safe(content)
register.filter('article_jsonify', article_jsonify)
You could also write a view inherited from generics.ListAPIView and override the get_queryset method, where you would pass the request's query parameter to a SearchQuerySet, then output it using the Serializer. More info here:
http://www.django-rest-framework.org/api-guide/filtering
Of course you might not be able to use the ModelSerializer this way, unless you do something like you mentioned. However DRF has an example on using the paginator on a queryset like so:
http://www.django-rest-framework.org/api-guide/pagination#paginating-querysets
UPDATE
I ended up eventually using a DRF view that uses a Haystack SearchQuerySet as the queryset, and then passing it to a Paginator. Here is a simplified example (I'm sure it can be streamlined some), but I hope it helps someone gets started.
class ArticleList(ListCreateAPIView):
"""
List, Create files
"""
model = Article
def get(self, request, *args, **kwargs):
# simplified filtering of an SQS
q = request.get('q', '')
sqs = SearchQuerySet().filter(content=Clean(q))
paginator = Paginator(sqs, 20)
page = request.QUERY_PARAMS.get('page')
try:
articles = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer, deliver first page
articles = paginator.page(1)
except PageNotAnInteger:
# If page is out of range, deliver last page
articles = paginator.page(paginator.num_pages)
serializer_context = {'request': request}
serializer = PaginatedArticleSerializer(articles, context=serializer_context)
return Response(serializer.data)
class ArticleSerializer(serializers.ModelSerializer):
"""
Base Article Serializer
"""
class Meta:
model = Article
class PaginatedArticleSerializer(pagination.PaginationSerializer):
"""
Serializes page objects of article querysets.
"""
start_index = serializers.SerializerMethodField('get_start_index')
end_index = serializers.SerializerMethodField('get_end_index')
num_pages = serializers.Field(source='paginator.num_pages')
class Meta:
object_serializer_class = ArticleSerializer
def get_start_index(self, page):
return page.start_index()
def get_end_index(self, page):
return page.end_index()
def get_curr_page(self, page):
return page.number