I want to get x and y coordinates from the point in the following queryset:
user = User.objects.values('id', 'email', 'username', 'point').first()
These are my models:
from django.db.models import Model
from django.contrib.gis.db.models import PointField
class BasePointModel(Model):
point = PointField(null=True, spatial_index=True, geography=True)
class Meta:
abstract = True
class User(AbstractUser, BasePointModel, HashableModel): # type: ignore
# First Name and Last Name do not cover name patterns
# around the globe.
name = CharField(_("Name of User"), blank=True, max_length=255)
is_online = BooleanField(_("Is online"), default=False)
I am getting the following result:
{'id': 85270,
'email': 'username_0#email.com',
'username': 'username_0',
'point': <Point object at 0x7f8e061cc2b8>}
How can I get an x and y, making a queryset with values?
I want to get something like this:
{'id': 85270,
'email': 'username_0#email.com',
'username': 'username_0',
'point__x': '-4.266398314110177',
'point__y': '-39.39432682357033'}
I make requests that return 50,000 lines from a database, and I notice that performance is getting worse due to data serialization. I want to minimize serialization by returning values.
But the PointField always returns an object, and I still haven't found a way to serialize it in the best way.
Tough luck :/
You are setting the points as geography and therefore you cannot use a custom GeoFunc in order to apply PostGIS's ST_X and ST_Y in an annotation query because they will only work on geometry fields.
In order to get the [lat, long] values of those points in the values results of the query we can annotate the query with the GeoJSON representation of the points and get those as values. To do that we will use the AsGeoJSON database function:
user = User.objects.annotate(
point_as_json=AsGeoJSON('point')
).values('id', 'email', 'username', 'point_as_json').first()
which will give us the following result:
{
'id': 85270,
'email': 'username_0#email.com',
'username': 'username_0',
'point_as_json': {
'type': 'Point',
'coordinates': [-4.26639831, -39.39432682]
}
}
As a side note, you can consider augmenting Django with django-rest-framework` and use django-rest-framework-gis on top of that which has some very handy tricks on serialization according to GeoJSON standards.
You could access the __dict__ method of your object and then directly with your geometry:
user = User.objects.values('id', 'email', 'username', 'point').first()
user_dict = user.__dict__
user_dict.update({'point__x':user_dict['point'].x, {'point__y':user_dict['point'].y})
The best way to get what you need is through a Serializer like the one bellow.
class LayerGeometrySerializer(GeoFeatureModelSerializer):
"""
GeoFeatureModelSerializer is a subclass of rest_framework.ModelSerializer which will output data in a format that is GeoJSON compatible
"""
values = LayerValueMinimalSerializer(source='layervalue_set', many=True)
class Meta:
model = LayerGeometry
geo_field = 'geom'
exclude = ('created', 'modified', )
Related
This may be rudimentary, but after some searches I couldn't find a way, but pop(), del, remove().
I have the following python (django) code:
class PageSerializer(serializers.ModelSerializer):
# ..
class Meta:
model = Page
fields = ('id','user','created_at','title','url','og_image','desc','voters','is_public','updated_at', 'pagevote','pageidenticals',)
read_only_fields = ('id','user','created_at','voters','is_public','updated_at','pagevote','pageidenticals')
Notice the redundancy on the fields and read_only_fields. The only difference of the two is title','url','og_image','desc.
So I just want to reduce the code in read_only_fields, like this pseudo code:
class PageSerializer(serializers.ModelSerializer):
# ..
class Meta:
model = Page
fields = ('id','user','created_at','title','url','og_image','desc','voters','is_public','updated_at', 'pagevote','pageidenticals',)
read_only_fields = fields.chomps(['title','url','og_image','desc',])
Since it's on a class, adding an extra pop() like you do in a def method is not an option. So, is there a way?
Seems like a job for set and its difference operator:
fields = ('id','user','created_at','title','url','og_image','desc','voters','is_public','updated_at', 'pagevote','pageidenticals',)
read_only_fields = tuple(set(fields)-{'title','url','og_image','desc'}))
print(read_only_fields)
Result:
('id', 'created_at', 'updated_at', 'pagevote', 'user', 'is_public', 'pageidenticals', 'voters')
Just be careful that the order preservation is an implementation detail of CPython, it is not guaranteed to stay the same in the future. So the following alternative might be more appropriate if you absolutely need the order guarantee
tuple(x for x in fields if x not in {...})
Python set provides with a function symmetric_difference which basically returns all the items present in given sets, except the items in their intersections.
Try this :
fields = ('id','user','created_at','title','url','og_image','desc','voters','is_public','updated_at', 'pagevote','pageidenticals',)
read_only_fields = ('id','user','created_at','voters','is_public','updated_at','pagevote','pageidenticals')
final_output = set(fields).symmetric_difference(set(read_only_fields))
print(final_output)
OUTPUT :
{'og_image', 'url', 'desc', 'title'}
I have 3 tables
AllTests
ReportFormat
Parameter
AllTests has reportFormat as ForeignKey with one to one relation.
class AllTests(models.Model):
id=models.AutoField(primary_key=True)
name=models.CharField(max_length=200)
reportFormat=models.ForeignKey(ReportFormat)
.....
.....
class Meta:
db_table = 'AllTests'
Parameter table has reportFormat as ForeignKey with one too many relations. Means one report format has many parameters.
class Parameter(models.Model):
id=models.AutoField(primary_key=True)
name=models.CharField(max_length=200)
reportFormat=models.ForeignKey(ReportFormat)
.....
.....
class Meta:
db_table = 'AllTests
ReportFormat Table:-
class ReportFormat(models.Model):
id=models.AutoField(primary_key=True)
.....
.....
class Meta:
db_table = 'ReportFormat'
I want to make a query on the parameter model that return parameter data with the related test data. Please suggest me a better way for the same.
my current query is like this.
from django.db.models import (
Sum, Value, Count, OuterRef, Subquery
)
data = Parameter.objects.filter(isDisable=0).values('id', 'name', 'reportFormat_id').annotate(
test=Subquery(Alltsets.objects.filter(reportFormat_id=OuterRef('reportFormat_id').values('id', 'name')))
)
Since, report format column of both the tables refer to the same column of reportformat table, maybe you can directly relate them with something like below.
select * from parameter inner join alltests on parameter.reportformat=alltests.reportformat
Maybe in ORM something like this?
Parameter.objects.filter().annotate(alltests_id=F('reportformat__alltests__id'),alltests_name=F('reportformat__alltests__name'),....other fields)
Fetch all Parameter and AllTests objects. Find the parameter's alltests object using reportFormat field. Add the corresponding data to the parameter dict.
Solution:
parameter_qs = Parameter.objects.all().select_related('reportFormat')
alltests_qs = AllTests.objects.all().select_related('reportFormat')
data = []
for parameter in parameter_qs:
item = {
'id': parameter.id,
'name': parameter.name,
'alltests': {}
}
# fetch related AllTests object using `reportFormat` field
alltests_obj = None
for alltests in alltests_qs:
if parameter.reportFormat == alltests.reportFormat:
alltests_obj = alltests
break
if alltests_obj is not None:
item['alltests'] = {
'id': alltests_obj.id,
'name': alltests_obj.name
}
data.append(item)
Given some model
class Loan(models.Model):
time_of_loan = models.DateTimeField()
username = models.CharField()
I have attempted to use the ModelSerializer from Django's REST Framework to serialize the Loan.
class LoanSerializer(serializers.ModelSerializer):
time_of_loan = serializers.DateTimeField(
format=None, input_formats=['%Y-%m-%d %H:%M:%S',])
class Meta:
model = `Loan`
fields = ['time_of_loan', 'username']
On using the serializer.data to get the JSON format, when I save the first time, the first time the model is saved, the JSON is well-behaved.
{
'time_of_loan': '2016-06-20 00:00:00+08:00',
'username': 'doe'
}
However, when I attempt to update the model, it "misbehaves" and it appears in a python datetime format.
{
'time_of_loan': datetime.datetime(2016, 6, 20, 7, 55, tzinfo=<UTC>),
'username': 'doe'
}
What change do I need to do so that, whenever the model gets serialized, it remains as the first format that I want?
FIRST EDIT
Can you show what you're doing to update the object
The question asked was what I did to update the model. I actually am using this as an audit log and so it took from an actual Django Form. In forms.py:
id = forms.cleaned_data.get('id')
username = forms.cleaned_data.get('username')
loan = Loan.objects.filter(id=id) #Queryset with count() = 1
loan.update(username=username)
loan_obj = loan[0]
serializer = LoanSerializer(loan_obj)
print(serializer.data)
After so much finding, I finally got the answer.
from rest_framework.renderers import JSONRenderer
serializer = LoanSerializer(loan_obj)
serializer.data
json = JSONRenderer().render(serializer.data)
I have a model is pretty straight forward and I've created a property on the model to essentially return child data as JSON. The property is simple:
#property
def question_data(self):
from api.models import TemplateQuestion
questions = TemplateQuestion.objects.filter(template__id=self.template.id)
question_dict = [obj.as_dict() for obj in questions]
return(json.dumps(question_dict, separators=(',', ': ')))
Which does its job and outputs valid JSON. That said I'm at a total loss of how to add that property to the Serializer as JSON and not a string like
{
"questions": "[{\"sequence\": 2,\"next_question\": \"\",\"modified_at\": \"2016-01-27T19:59:07.531872+00:00\",\"id\": \"7b64784e-a41d-4019-ba6e-ed8b31f99480\",\"validators\": []},{\"sequence\": 1,\"next_question\": null,\"modified_at\": \"2016-01-27T19:58:56.587856+00:00\",\"id\": \"99841d91-c459-45ff-9f92-4f75c904fe1e\",\"validators\": []}]"
}
It's stringifying the JSON and which I need as proper JSON.
Serializer is probably too basic but I haven't worked with DRF in a while and have never tried to append JSON to the serialized output.
class BaseSerializer(serializers.ModelSerializer):
class Meta:
abstract = True
class SurveySerializer(BaseSerializer):
included_serializers = {
'landing_page': 'api.serializers.LandingPageSerializer',
'trigger': 'api.serializers.TriggerSerializer',
'template': 'api.serializers.TemplateSerializer'
}
questions = serializers.ReadOnlyField(source='question_data')
class Meta:
model = Survey
fields = ('id',
'name',
'slug',
'template',
'landing_page',
'trigger',
'trigger_active',
'start_date',
'end_date',
'description',
'fatigue_limit',
'url',
'questions',)
meta_fields = ('created_at', 'modified_at')
I'll add that I'm also bolting on the Django Rest Framework JSON API formatting but I think that in the end I'm just not getting how to append JSON to a model's serialization without it being returned as a string.
You should not be dumping the results of the method to JSON. Just return the dict; DRF's serializer will take care of converting it.
I get the relative objects from queryset, but it have a further relative query, how to get those objects?
class PropertyTaxItem(models.Model):
property = models.ForeignKey(Property)
class Property(models.Model):
citizens = models.ManyToManyField(Citizen, null=True, through = 'Ownership',help_text="a property could belong to multiple citizens")
class Citizen(models.Model):
first_name = models.CharField(max_length = 50, help_text = 'First name')
last_name = models.CharField(max_length = 50, help_text = 'Last name')
my getting the citzien part:
items = PropertyTaxItem.objects.filter(i_status='active').select_related('property_id').prefetch_related('property_id.citizens')
for i in items:
pp.pprint(i.citizens.__dict__)
the output is:
{'_db': None,
'_fk_val': 10092,
'_inherited': False,
'core_filters': {'property__pk': 10092},
'creation_counter': 69,
'instance': <Property: 306 GASHIHA, KAGINA, Kicukiro,Kicukiro>,
'model': <class 'citizen.models.Citizen'>,
'prefetch_cache_name': 'citizens',
'query_field_name': 'property',
'reverse': False,
'source_field_name': 'asset_property',
'symmetrical': False,
'target_field_name': 'owner_citizen',
'through': <class 'property.models.Ownership'>}
but I want get the items of citizens like:
{'id': 18980,
'first_name': 'Jack',
'last_name' : 'blablabla',
....
}
how to do it?
You have a few issues. You are querying PropertyTaxItem which foreign keys to Property, which then has multiple Citizens. This would be a correct query to select the related 'propertys and prefetch theproperty.citizens`
items = PropertyTaxItem.objects.filter(i_status='active').select_related('property').prefetch_related('property__citizens')
You can access the citizens like this:
for i in items:
citizens = i.property.citizens.all() # now you have a queryset of citizens.
# To get a list of dictionaries, you can call `.values()` on the queryset.
pp.pprint(citizens.values())
Another possible problem you will have is that citizens uses a custom through model. There are some limitations on ManyToManyField query sets when using custom though models.