Return valid GeoJSON with Flask + GeoAlchemy2 app - json

Since few days I am wondering how to make my Flask app return valid GeoJSON, here is what I got so far:
models.py
class Building(base):
__tablename__ = 'buildings'
id = Column(Integer, primary_key=True)
district = Column(Unicode)
address = Column(Unicode)
name = Column(Unicode)
building_type = Column(Unicode)
mpoly = Column(Geometry('MULTIPOLYGON'))
building = relationship("User")
# this part is done as answered here: https://stackoverflow.com/questions/41684512/cant-transform-geometry-to-geojson
def building_to_dict(self):
return mapping(shapely.wkb.loads(str(self.mpoly), True))
def __str__(self):
d = dict()
d["id"] = self.id
d["district"] = self.district
d["address"] = self.address
d["name"] = self.name
d["building_type"] = self.building_type
d["mpoly"] = self.building_to_dict()
return shapely.dumps(d)
Now at main file I have following routing:
app.py
#app.route('/geojson')
def get_json():
features = session.query(Building.mpoly.ST_AsGeoJSON()).all()
return jsonify(features)
And here are my two problems:
1)
Returned JSON-like response that looks like following:
"{\"type\":\"MultiPolygon\",\"coordinates\":[[[[16.8933137,52.471446],...,]]]}"
Is not proper GeoJSON.
Features variable before jsonify looks this way:
[('{"type":"MultiPolygon","coordinates":[[[[16.914159616,52.473822807],...,]]]}',)]
2)
How my GeoAlchemy query should look like, to return not just geometry field, but others as well?
Any kind of hints or helps highly appreciated, thanks in advance!

You may use marshmallow-sqlalchemy for creating json like responses.
create
schemas.py
#!schemas.py
from marshmallow import fields
from marshmallow_sqlalchemy import ModelSchema
from app.models import Building
from geoalchemy.shape import to_shape
class BuildingSchema(ModelSchema):
id = fields.Integer()
district = fileds.Unicode()
address = fileds.Unicode()
name = fields.Unicode()
building_type = fields.Unicode()
mpoly = fileds.Method("geom_to_json")
#staticmethod
def geom_to_json(obj):
mpoly = to_shape(obj.mpoly)
return {
lat: mpoly.y,
lon: mpoly.x,
#and so on ...
}
class Meta:
model = Building
exclude = ("mpoly")
bulding_schema = BuildingSchema(many=True)
after this you can use it in your views(routes)
from app.schemas import building_schema
#app.route('/geojson')
def json():
buildings = Buildings.query.all()
response = building_schema.dumps(buildings)
return response

Related

In Django, how do I render JSON given an OrderedDict?

I'm using Django and Python 3.7. I'm having trouble returning JSON from one of my views. I have this view code ...
def get_hints(request):
article_id = request.GET.get('article_id', None)
article = Article.objects.get(pk=article_id)
s = ArticlesService()
objects = s.get_hints(article)
data = ArticleSerializer(objects, many=True).data
print("data: ", data)
return HttpResponse(data, content_type="application/json")
The service method referenced returns the following data ...
def get_hints(self, article):
...
sorted_articles_map = OrderedDict(sorted(rank_map.items(), key=operator.itemgetter(1), reverse=True))
return list(sorted_articles_map.keys())
The data returned from the serializer looks like this, definitely not json ...
[OrderedDict([('id', 10777935), ('created_on_ms', 1577985486000.0), ('label', 'World'), ('title', "Outrage and Disgust After 'Serial Killer' ...,
How do I render proper JSON?
Edit: Adding Article serializer ...
class ArticleSerializer(serializers.ModelSerializer):
class Meta:
model = Article
fields = ['id', 'created_on_ms', 'label', 'title', 'mobile_path', 'path', 'url', 'is_media', 'checked_for_dup', 'original_path', 'is_spiked']
Option 1
Use the #api_view()--(drf doc) decorator of DRF along with Response--(drf doc) class
from rest_framework.decorators import api_view
from rest_framework.response import Response
#api_view(['GET'])
def get_hints(request):
article_id = request.GET.get('article_id', None)
article = Article.objects.get(pk=article_id)
s = ArticlesService()
objects = s.get_hints(article)
data = ArticleSerializer(objects, many=True).data
return Response(data)
Option 2
You will get similar response by using JsonResponse--(django doc)
from django.http.response import JsonResponse
def get_hints(request):
article_id = request.GET.get('article_id', None)
article = Article.objects.get(pk=article_id)
s = ArticlesService()
objects = s.get_hints(article)
data = ArticleSerializer(objects, many=True).data
return JsonResponse(data, safe=False)

How do I make my model's depdent fields appear in my JSON using Django serializers?

I'm using Django 2.0 and Python 3.7. I have the following models ...
from django.db import models
from address.models import AddressField
from phonenumber_field.modelfields import PhoneNumberField
from address.models import State
from address.models import Country
class CoopTypeManager(models.Manager):
def get_by_natural_key(self, name):
return self.get_or_create(name=name)[0]
class CoopType(models.Model):
name = models.CharField(max_length=200, null=False)
objects = CoopTypeManager()
class Meta:
unique_together = ("name",)
class Coop(models.Model):
name = models.CharField(max_length=250, null=False)
type = models.ForeignKey(CoopType, on_delete=None)
address = AddressField(on_delete=models.CASCADE)
enabled = models.BooleanField(default=True, null=False)
phone = PhoneNumberField(null=True)
email = models.EmailField(null=True)
web_site = models.TextField()
And then I created the following serializers ...
from rest_framework import serializers
from maps.models import Coop, CoopType
class CoopSerializer(serializers.ModelSerializer):
class Meta:
model = Coop
fields = ['id', 'name', 'type', 'address', 'enabled', 'phone', 'email', 'web_site']
def create(self, validated_data):
"""
Create and return a new `Snippet` instance, given the validated data.
"""
return Coop.objects.create(**validated_data)
def update(self, instance, validated_data):
"""
Update and return an existing `Coop` instance, given the validated data.
"""
instance.name = validated_data.get('name', instance.name)
instance.type = validated_data.get('type', instance.type)
instance.address = validated_data.get('address', instance.address)
instance.enabled = validated_data.get('enabled', instance.enabled)
instance.phone = validated_data.get('phone', instance.phone)
instance.email = validated_data.get('email', instance.email)
instance.web_site = validated_data.get('web_site', instance.web_site)
instance.save()
return instance
class CoopTypeSerializer(serializers.ModelSerializer):
class Meta:
model = CoopType
fields = ['id', 'name']
def create(self, validated_data):
"""
Create and return a new `CoopType` instance, given the validated data.
"""
return CoopType.objects.create(**validated_data)
def update(self, instance, validated_data):
"""
Update and return an existing `Snippet` instance, given the validated data.
"""
instance.name = validated_data.get('name', instance.name)
instance.save()
return instance
I'm trying to create an API to display my models as JSON. I created this views file
from maps.models import Coop
from maps.serializers import CoopSerializer
from django.http import Http404
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
class CoopList(APIView):
"""
List all coops, or create a new coop.
"""
def get(self, request, format=None):
coops = Coop.objects.all()
serializer = CoopSerializer(coops, many=True)
return Response(serializer.data)
def post(self, request, format=None):
serializer = CoopSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class CoopDetail(APIView):
"""
Retrieve, update or delete a coop instance.
"""
def get_object(self, pk):
try:
return Coop.objects.get(pk=pk)
except Coop.DoesNotExist:
raise Http404
def get(self, request, pk, format=None):
coop = self.get_object(pk)
serializer = CoopSerializer(coop)
return Response(serializer.data)
def put(self, request, pk, format=None):
coop = self.get_object(pk)
serializer = CoopSerializer(coop, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, pk, format=None):
coop = self.get_object(pk)
coop.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
However, my dependent model, CoopType, is not getting displayed as JSON. Only its primary key is getting displayed, e.g. ...
{
"id": 915,
"name": "Young Men's Educational Network",
"type": 10,
"address": 790,
"enabled": true,
"phone": null,
"email": null,
"web_site": "www.ymenchi.com/"
},
How do I get my dependent model to appear in my JSON?
Override the to_representation(...) method of the Serializer
class CoopSerializer(serializers.ModelSerializer):
# other code snippets
def to_representation(self, instance):
rep = super().to_representation(instance)
rep['type'] = CoopTypeSerializer(instance.type).data
return rep
Reference: DRF: Simple foreign key assignment with nested serializers?

Django serializer is not returning JSON data

I have a model Domain:
class Domain(models.Model):
name = models.CharField(max_length=50)
def __str__(self):
return self.name
And a corresponding serializer:
class DomainSerializer(serializers.ModelSerializer):
class Meta:
model = Domain
fields = ('name',)
I'm trying to serialize a queryset in a view like this:
def getDomains(request):
domains = Domain.objects.filter(name__startswith=request.GET['name_startsWith'])
data = DomainSerializer(domains, many=True)
print(data.data)
return HttpResponse(data.data)
This is not working correctly, and data.data is :
[OrderedDict([('name', 'Math')])]
I would like to have a JSON object, something like:
{'name': 'Math'}.
Try using JsonResponse to return the data:
from django.http import JsonResponse
.....
return JsonResponse(data.data)

Django Rest Framework - Add fields to JSON

Now I return a JSON file with the model fields and their values. I want to add some extra fields to the JSON that are not present in the model (I want to add a new field that specifies if an user can modify or not the diagnostic based on the permissions of the view). How I can do this?
models.py
class Diagnostic(models.Model):
Center = models.TextField(blank=True)
Author = models.TextField(blank=True)
Email = models.EmailField(blank=True)
Date = models.DateField(null = True, blank=True)
views.py
class DiagnosticViewSet(viewset.ModelViewSet):
model = Diagnostic
permission_classes = [GroupPermission]
serializers.py
class DiagnosticSerializer(serializers.ModelSerializer):
class Meta:
model = Diagnostic
Add this to your views
def list(self, request, *args, **kwargs):
response = super(Classname, self).list(request, *args, **kwargs)
try:
response.data['permission'] = 'give your permission'
except:
pass
return response
You add them to the serializer.
class DiagnosticSerializer(serializers.ModelSerializer):
auth_status = serializers.SerializerMethodField('get_auth_status')
class Meta:
model = Diagnostic
def get_auth_status(self, obj):
if obj.has_auth():
return True
return False
You have to use following code for the url localhost/diagnostics/1
from rest_framework.response import Response
def retrieve(self, request, *args, **kwargs):
self.object = self.get_object()
serializer = self.get_serializer(self.object)
data = serializer.data
data['permission'] = 'give your permission'
return Response(data)

Grails. Domain class. Method AddTo*?

I have this example:
def mycreate = {
def id = params.id;
def data = JSON.parse(params.data);
def credit = Credit.get(id);
def front = new Front ();
front.properties = data;
credit.addToFronts(front).save()
render (front as JSON)
}
This action returns something like this:
{"class":"test.Front","id":null,"credits":{"class":"Credit","id":1},"dateCreated":null,"description":"write text here."}
But, for me, the params "id" and "dateCreated" are null. How can I get the values of these params?