I have the following code that should return me all the Users that are registered in my site, but for some reason it just returned me the last signed user, I need all the users in my JSON.
from django.shortcuts import render, redirect
import json
from django.http import HttpResponse
from rest_framework.response import Response
from rest_framework.views import APIView
from profiles.serializers import ProfileSerializer
from django.contrib.auth.models import User
from rest_framework.decorators import api_view
class ProfilesAPI(APIView):
serializer = ProfileSerializer
def get(self, request, format=None):
users = User.objects.all()
response = self.serializer(users, many=True)
for j in range(0,len(response.data)):
dictionary = response.data[j]
myresponse = ""
for i, (val, v) in enumerate(dictionary.items()):
myresponse = [{"text":v} for v in dictionary.values()]
print(myresponse)
return HttpResponse(json.dumps({'messages': myresponse}), content_type='application/json')
and throws me this, even I have more than one user registered.
My JSON
This is where your problem lies:
dictionary = response.data[j]
You declare the dictionary and at the same time, you the existing value with the latest value in the loop. By the time the loop exits, The dictionary would contain only one result (The last one in the loop)
you should declare it outside the loop and then call dict.update something like this:
dictionary = {}
for j in range(0,len(response.data)):
dictionary.update(response.data[j])
That solves your problem.
But there's no point generating a this new dictionary. You can just iterate once on response.data if you need to customize the response.
since response.data is a list of users you can do this instead
dictionary = {'messages': []}
for user in response.data:
dictionary['messages'].append({'text': user['id']})
dictionary['messages'].append({'text': user['username']})
Also since you're using django rest framework and the APIView you don't need json.dumps
django framework has a Response class that takes care of that and it also sets the appropriate headers.
from rest_framework.response import Response
and then change your return statement to:
return Response(dictionary)
Related
The put request is working, but if i want to see the post updated i have to restart the server.
This is the view function:
from rest_framework import status
from rest_framework.response import Response
from rest_framework.decorators import api_view
from blog.models import Post
from .serializers import PostSerializer
from django.contrib.auth.models import User
#api_view(['PUT'])
def api_update_post_view(request, Slug):
try:
blog_post = Post.objects.get(slug=Slug)
except Post.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
serializer = PostSerializer(blog_post, data=request.data, partial=True)
data = {}
if serializer.is_valid():
serializer.save()
data['succes'] = 'update successful'
return Response(data=data)
return Response(serializer.errors, status.HTTP_400_BAD_REQUEST)
I didn't see any special features in your PUT method. So, I suggest you to use ModelViewSet instead of creating a basic PUT method yourself. ModelViewSet will generate basic CRUD operations for you automatically.
Here is the official docs. It should be no problem after you use the ModelViewSet.
I have a method in one of my viewsets:
Endpoint: /api/game/{id}/sessions:
from .serializers import GameSerializer
from .models import Game
from gamesessions.models import GameSession
from gamesessions.serializers import GameSessionSerializer
from gamesessions.viewsets import GameSessionViewSet
#action(methods=['get'], detail=True)
def sessions(self, request, **id):
game = self.get_object()
sessions = []
for session in GameSession.objects.filter(game=game.id):
sessions.append(session)
serializer = GameSessionViewSet.get_serializer(sessions, many=True)
return Response(serializer.data)
But I'm getting an error because I can't figure out where the get_serializer method comes from and/or how to implement it externally.
I need to get the serializer of the session model. I can generate the list of sessions just fine, but it says the object is not JSON serializable, which is what DRF is supposed to handle.
So I just need to know what do I import to get the seralizer from the other class?
Maybe you can try, to use the serializer directly with the name like this:
serializer = GameSessionSerializer(sessions, many=True)
I am using wagtail as a REST backend for a website. The website is built using react and fetches data via wagtails API v2.
The SPA website needs to be able to show previews of pages in wagtail. My thought was to override serve_preview on the page model and simply seralize the new page as JSON and write it to a cache which could be accessed by my frontend. But im having trouble serializing my page to json. All attempts made feel very "hackish"
I've made several attempts using extentions of wagtails built in serializers but without success:
Atempt 1:
def serve_preview(self, request, mode_name):
from wagtail.api.v2.endpoints import PagesAPIEndpoint
endpoint = PagesAPIEndpoint()
setattr(request, 'wagtailapi_router',
WagtailAPIRouter('wagtailapi_v2'))
endpoint.request = request
endpoint.action = None
endpoint.kwargs = {'slug': self.slug, 'pk': self.pk}
endpoint.lookup_field = 'pk'
serializer = endpoint.get_serializer(self)
Feels very ugly to use router here and set a bunch of attrs
Attempt 2:
def serve_preview(self, request, mode_name):
from wagtail.api.v2.endpoints import PagesAPIEndpoint
fields = PagesAPIEndpoint.get_available_fields(self)
if hasattr(self, 'api_fields'):
fields.extend(self.api_fields)
serializer_class = get_serializer_class(
type(self), fields, meta_fields=[PagesAPIEndpoint.meta_fields], base=PageSerializer)
serializer = serializer_class(self)
Better but i get context issues:
Traceback (most recent call last):
...
File "/usr/local/lib/python3.5/site-packages/wagtail/api/v2/serializers.py", line 92, in to_representation
self.context['view'].seen_types[name] = page.specific_class
KeyError: 'view'
Any toughts?
Solved it by diving through the source code.
First define an empty dummy view:
class DummyView(GenericViewSet):
def __init__(self, *args, **kwargs):
super(DummyView, self).__init__(*args, **kwargs)
# seen_types is a mapping of type name strings (format: "app_label.ModelName")
# to model classes. When an object is serialised in the API, its model
# is added to this mapping. This is used by the Admin API which appends a
# summary of the used types to the response.
self.seen_types = OrderedDict()
Then use this view and set the context of your serializer manually. Im also using the same router as in my api in my context. It has methods which are called by the PageSerializer to resolve some fields. Kinda strange it is so tightly coupled with the wagtail api but at least this works:
def serve_preview(self, request, mode_name):
import starrepublic.api as StarApi
fields = StarApi.PagesAPIEndpoint.get_available_fields(self)
if hasattr(self, 'api_fields'):
fields.extend(self.api_fields)
serializer_class = get_serializer_class(
type(self), fields, meta_fields=[StarApi.PagesAPIEndpoint.meta_fields], base=PageSerializer)
serializer = serializer_class(
self, context={'request': request, 'view': DummyView(), 'router': StarApi.api_router})
Dont forget to import:
from wagtail.api.v2.serializers import get_serializer_class
from rest_framework.viewsets import GenericViewSet
from rest_framework import status
from rest_framework.response import Response
from django.http import JsonResponse
from django.http import HttpResponse
Possibly a non-answer answer, but I too have had challenges in the area of DRF, Wagtail's layering on top of DRF, and the need to cache json results (DRF has no built-in caching as far as I can tell, so that's an additional challenge). In a recent project, I ended up just building a list of dictionaries in a view and sending them back out with HttpResponse(), bypassing DRF and Wagtail API altogether. The code ended up simple, readable, and was easy to cache:
import json
from django.http import HttpResponse
from django.core.cache import cache
data = cache.get('mydata')
if not data:
datalist = []
for foo in bar:
somedata = {}
# Populate somedata, "serializing" fields manually...
datalist.append(somedata)
# Cache for a week.
data = datalist
cache.set('mydata', datalist, 60 * 60 * 24 * 7)
return HttpResponse(json.dumps(data), content_type='application/json')
Not as elegant as using the pre-built REST framework, but sometimes the simpler approach is just more productive...
I would like to create a web api with Python and the Django Rest framework. The tutorials that I have read so far incorporate models and serializers to process and store data. I was wondering if there's a simpler way to process data that is post-ed to my api and then return a JSON response without storing any data.
Currently, this is my urls.py
from django.conf.urls import url
from rest_framework import routers
from core.views import StudentViewSet, UniversityViewSet, TestViewSet
router = routers.DefaultRouter()
router.register(r'students', StudentViewSet)
router.register(r'universities', UniversityViewSet)
router.register(r'other', TestViewSet,"other")
urlpatterns = router.urls
and this is my views.py
from rest_framework import viewsets
from rest_framework.decorators import api_view
from rest_framework.response import Response
from .models import University, Student
from .serializers import UniversitySerializer, StudentSerializer
import json
from django.http import HttpResponse
class StudentViewSet(viewsets.ModelViewSet):
queryset = Student.objects.all()
serializer_class = StudentSerializer
class UniversityViewSet(viewsets.ModelViewSet):
queryset = University.objects.all()
serializer_class = UniversitySerializer
class TestViewSet(viewsets.ModelViewSet):
def retrieve(self, request, *args, **kwargs):
return Response({'something': 'my custom JSON'})
The first two parts regarding Students and Universities were created after following a tutorial on Django setup. I don't need the functionality that it provides for creating, editing and removing objects. I tried playing around with the TestViewSet which I created.
I am currently stuck trying to receive JSON data that gets posted to the url ending with "other" and processing that JSON before responding with some custom JSON.
Edit
These two links were helpful in addition to the solution provided:
Django REST framework: non-model serializer
http://jsatt.com/blog/abusing-django-rest-framework-part-1-non-model-endpoints/
You can use their generic APIView class (which doesn't have any attachment to Models or Serializers) and then handle the request yourself based on the HTTP request type. For example:
class RetrieveMessages(APIView):
def post(self, request, *args, **kwargs):
posted_data = self.request.data
city = posted_data['city']
return_data = [
{"echo": city}
]
return Response(status=200, data=return_data)
def get....
I use Django rest framework and python3.5. Earlier I had another version of python and everything was going right. When I want to get some information from server with URL for example like:
"http://127.0.0.1:8000/api/companies"
I'm getting error:
"OrderedDict mutated during iteration"
.
In views.py I have:
from django.shortcuts import render
from companies.models import Companies
from companies.serializers import CompaniesSerializer
from rest_framework import generics
from rest_framework.response import Response
from rest_framework.renderers import JSONRenderer
from rest_framework import status
class CompaniesList(generics.ListCreateAPIView):
queryset = Companies.objects.all()
serializer_class = CompaniesSerializer
class CompaniesDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Companies.objects.all()
serializer_class = CompaniesSerializer
What should I do to make it working? Where is something mutating the dict?
I don't know why using ListCreateApiView is mutating dict, but I changed class into function like :
#api_view(['GET'])
def CompaniesList(request):
if request.method == 'GET':
companies = Companies.objects.all()
serializer = CompaniesSerializer(companies, many=True)
return Response(serializer.data)
and now it's working...