Return serialized JSON from DRF Serializer - json

I have a custom serializer that is returning a string representation of JSON. This serializer uses django.contrib.gis.serializers.geojson.Serializer which is much faster than the DRF serializer. The downside of this serializer is that it returns everything already serialized into a string, rather than as a JSON serializiable object.
Is there a way to shortcut the DRF obj>json string process and just pass the string as the json response?
Currently I am doing the following, but the obj>string>dict>string process is not ideal:
from django.contrib.gis.serializers.geojson import Serializer
from json import loads
class GeoJSONFastSerializer(Serializer):
def __init__(self, *args, **kwargs):
self.instances = args[0]
super().__init__()
#property
def data(self):
# The use of json.loads here to deserialize the string,
# only for it to be reserialized by DRF is inefficient.
return loads(self.serialize(self.instances))
Which is implemented (simplified version) in the view:
from rest_framework.mixins import ListModelMixin
from rest_framework.viewsets import GenericViewSet
class GeoJSONPlaceViewSet(ListModelMixin, GenericViewSet):
serializer_class = GeoJSONFastSerializer
queryset = Places.objects.all()

I think that you could define a custom renderer and just pass the data, something like this,
from django.utils.encoding import smart_unicode
from rest_framework import renderers
class AlreadyJSONRenderer(renderers.BaseRenderer):
media_type = 'application/json'
format = 'json'
def render(self, data, media_type=None, renderer_context=None):
return data
and in the view just add
renderer_classes = [AlreadyJSONRenderer]

Related

Serializing Django FilterSet

I'm using django-filter (https://django-filter.readthedocs.io/en/stable/guide/install.html).
How can I serialize the Filterset in order to send it back to my angular Frontend?
views.py:
#api_view(['GET'])
def materialien_search(request):
filter = MaterialFilter(request.GET, queryset=Materialien.objects.all())
materialien_serializer = MaterialienSerializer(filter, many=True)
return JsonResponse(materialien_serializer.data, safe=False)
serializers.py:
class MaterialienSerializer(serializers.ModelSerializer):
class Meta:
model = Materialien
fields = [field.name for field in Materialien._meta.get_fields()]
filter.py:
class MaterialFilter(django_filters.FilterSet):
class Meta:
model = Materialien
fields = '__all__'
I'd be thankful for every help.
The Filterset should be a GET QueryDict, but all my attemps of serializing or converting it to JSON failed because Materialfilter is neither iterable nor serializable. So json.dumps and json.load and
serializers.serialize("json", filter) did not work.
TypeError: 'MaterialFilter' object is not iterable
TypeError: Object of type MaterialFilter is not JSON serializable

Convert model objects in OrderedDict to Json django

In [32]: obj
OrderedDict([('code', 'COO21'),
('name', 'sai'),
('country', <Country: INDIA>)])
Error:-
TypeError: Object of type Country is not JSON serializable
Not able to convert model objects in ordered dict to json
Override the to_representation() method in your serializer to customize the response when sending back to the view/controller.
instance is the object of the serializing model.
def to_representation(self, instance):
ret = super().to_representation(instance)
ret["country"] = instance.country.name if country else None
return ret

Access Json object name

I want to get data with request.data.columns in frontend.I can do it with ViewSet with list method but how to do it with generics.APIView.
Below is my viewsets and generics code:
class TestList(viewsets.ViewSet):
queryset = Test.objects.all()
def list(self,request):
serializer = TestSerializer(self.queryset, many = True)
return Response({'columns': serializer.data})
class TestList(generics.RetriveAPIView):
queryset = Test.objects.all()
serializer_class = TestSerializer
class TestList(APIView):
queryset = Test.objects.all()
def list(self,request):
serializer = TestSerializer(self.queryset, many = True)
return Response({'columns': serializer.data})
change your urls.py like this.
path(r"url", TestList.as_view({"get": "list"}))
Correct code:
class TestList(APIView):
queryset = Test.objects.all()
def list(self,request):
queryset = self.get_queryset()
serializer = TestSerializer(queryset, many = True)
return Response({'columns': serializer.data})
Details about why i had to add queryset = self.get_queryset() instead of directly access self.queryset.From official drf documentation:
queryset - The queryset that should be used for returning objects from this view. Typically, you must either set this attribute, or override the get_queryset() method. If you are overriding a view method, it is important that you call get_queryset() instead of accessing this property directly, as queryset will get evaluated once, and those results will be cached for all subsequent requests.

django rest framework + mariaDB: custom JSONField

Django: v2.1.5
DRF: v3.9.1
mariaDB: v10.3
Hi, I am a DRF newbie and I have been struggling with json field.
DRF does not support official json field type working with mariaDB and even though there is a 3rd-party package for mysql(django-mysql) but not compatible with mariaDB.
So I searched and started implementing custom jsonfield and it looks like:
model.py:
class JSONField(models.TextField):
def to_dict(self, value):
""" convert json string to python dictionary """
return json.loads(value)
def to_json(self, value):
""" convert python dictionary to json string """
return json.dumps(value)
def from_db_value(self, value, expression, connection):
""" convert string from db to python dictionary """
if value is None:
return value
return self.to_dict(value)
def to_python(self, value):
""" convert model input value to python dictionary """
if isinstance(value, dict):
return value
if value is None:
return value
return self.to_dict(value)
def get_prep_value(self, value):
""" convert python dictionary to string before writing to db """
return self.to_json(value)
class Project(models.Model):
objects = models.Manager()
project_user = JSONField(null=True)....
serializers.py:
class ProjectSerializer(serializers.ModelSerializer):
class Meta:
model = Project
fields = ('project_code'...)
def create(self, validated_data):
"""
Create and return a new `Project` instance, given the validated data.
"""
return Project.objects.create(**validated_data)
views.py:
class ListCreateProjectView(APIView):
"""
POST admin/_proj_/
: create a project
"""
def post(self, request, format=None):
serializer = ProjectSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(data=serializer.data)
else:
return Response(data=serializer.errors)
please let me know what I am doing wrong here or a way to use 3rd party package rather than custom jsonfield
Thanks a lot and have a great day guys!
For people who suffer from this kind of problem, I actually solved this problem, but in an informal way. I set JSONfield as a textfield in DB, and handle (str->json),(json->str) in the view. But again, this is an informal way (I think) and you will need another solution than this. If you find one, please share it for me and other people :)

Get a Json format for a Seq of a generic type

I have an abstract class with a generic type which gets a Json format for that generic type from its subclass. But the abstract class also needs a Json format of a sequence of that type. Is there any way in Scala to get a Json format of a sequence of things based only on the format of those things?
I'm using the Play Json framework.
Here's an example that doesn't follow my case exactly but provides a good indication of what I want to achieve:
package scalatest
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Await
import scala.concurrent.duration.Duration
import java.util.UUID
import scala.util.control.NonFatal
import play.api.libs.json.Format
import play.api.libs.json.Json
object Banana {
def main(args: Array[String]): Unit = {
val f: Format[Seq[Banana]] = getSeqFormat(Json.format[Banana])
}
def getSeqFormat[T](format: Format[T]): Format[Seq[T]] = {
??? // TODO implement
}
}
case class Banana(color: String)
If you're just trying to serialize bananas into JSON objects then the only thing you need to do is define the Banana implicit json format, the others (like Seq format for example) are built-in within play:
import play.api.libs.json.Json
case class Banana(color: String)
object Banana {
implicit val jsonFormat = Json.writes[Banana]
}
object PlayJsonTest extends App {
val bananas = Seq(Banana("yellow"), Banana("green"))
println(Json.toJson(bananas)) // [{"color":"yellow"},{"color":"green"}]
}
This also works for other types because the Json#toJson method is defined as follows:
// Give me an implicit `Writes[T]` and I know how to serialize it
def toJson[T](o: T)(implicit tjs: Writes[T]): JsValue = tjs.writes(o)
The defaults are implicitly used and those include a format for most of the collections. You can find them here.
I hope that helps you.