Reputation: 13723
I have a Place
model which has a polygon field:
from django.contrib.gis.db import models
class Place(models.Model):
area = models.PolygonField()
I want to translate the area
field of an instance of this Place
model.
Here is how I am doing it right now:
from django.contrib.gis.db.models.functions import Translate
place = Place.objects.get(pk=1)
place.area = Place.objects.filter(pk=place.pk).annotate(new_area=Translate('area', 0.001, 0.001)).first().new_area
place.save()
This seems very hacky. I think that there should be a way of doing this in the following way:
place = Place.objects.get(pk=1)
place.area = Translate(place.area, 0.001, 0.001)
place.save()
But this throws an exception.
Should I be using some library? Which one works well with GeoDjango and its models/fields?
What is the better way of doing it?
Upvotes: 2
Views: 1601
Reputation: 9994
Note the "db" in django.contrib.gis.db.models.functions
. There aren't Python functions, these are classes (thus the initial capital in the names) that allow you to access the database system's spatial functions (usually provided by a spatial database extension like spatialite of SQLite or PostGIS for PostgreSQL). See the GeoDjango documentation
The functions documented on this page allow users to access geographic database functions to be used in annotations, aggregations, or filters in Django.
(Emphasis mine.)
That is, these can only be used in queries, as the spatial calculation work of offloaded to the database.
So what can you do instead of doing several queries?
update
queryIf you'd do this directly in SQL, you'd probably write an UPDATE
query. The Django ORM allows you to do the same from Django, with the update()
method.
It'd probably look something like this (untested):
Place.objects.filter(pk=1).update(area=Translate('area', 0.001, 0.001))
If you're using GeoDjango anyway, this is probably the preferred way.
As you suggested, you can use an external library instead of GeoDjango's Translate
, e.g. shapely.affinity.translate
from the shapely
library. However, I doubt it will accept GeoDjango's django.contrib.gis.geos.GEOSGeometry
as input, so you might have to go through GeoJSON or WKT to convert back and forth.
Use this approach if you need your spatial calculations to be independent of the underlying database system.
Upvotes: 1