Hi Karim,

On Wed, Dec 10, 2014 at 8:07 AM, Karim <lemieli...@gmail.com> wrote:

> Hi everyone! I have a "Services" model and I would like to get a
> QuerySet with all the services filtered based on the distance between
> the logged user and the service.
>
> I have latitude and longitude about the user logged in and I filter
> the services based on the computed distance.
>
> At the moment I build the QuerySet Service.objects.all() and after
> that I exclude the services that I don't need, but I think there is a
> better way to do that.
>
> I was thinking to use a Manager. Quoting the docs:
>
> "Adding extra Manager methods is the preferred way to add
> “table-level” functionality to your models. (For “row-level”
> functionality – i.e., functions that act on a single instance of a
> model object – use Model methods, not custom Manager methods.)"
>
> As a "eternal newbie" I ask you
>
> 1) The distance must be computed based on two parameters "long" and
> "lat". Is that possible to define a manager only for this purpose? Is
> it a good practice?
>

Only if you can perform that calculation "database-side". Since you want to
do a filtering operation, the property you want to filter on must either be
stored on the database, or computable via the database. Essentially, the
manager needs to be no more than a shorthand for a query chain using normal
Django query clauses. You can't use a method on the *model* because that
value will only exist on the Python side of the query, not the database
side.

(A quick caveat - you *could* do it by filtering on the Python side -
essentially, you filter as much as possible on the database, and then
provide a Python-side filter - essentially "[s for s in
Service.objects.all() if s.distance(some_user) < maximum_value]" - but that
puts additional load on your web server. If your list of services is short
to start with, or can be filtered to be relatively short, this might be a
viable option - YMMV)

In some cases, the database filtering can be helped by pre-computing a
filterable value and storing it as a value on the database model, so you
can use a simple Django filter on that value. However, in your case, it's
not just about the lat/long of the object being filtered, but the lat/long
of the user as well.

Managers themselves can't take arguments, so the closest you'll get is a
method *on* the manager that can return a queryset. The fact that the
method is on the Manager is largely irrelevant - that's just a convenience.
You need to be able to construct a query chain, using purely database-side
queries. Putting that method on the manager is really just a convenience to
put the query in an obvious place; being on the manager doesn't give the
query any additional power.

If you're using Django 1.7, you should also look into using custom query
sets *as* managers:

https://docs.djangoproject.com/en/1.7/releases/1.7/#calling-custom-queryset-methods-from-the-manager

This means you'll be able to access your "nearest filter" anywhere in a
query chain. After all - does it really matter if you say:

Services.objects.nearest(some_user).filter(is_fun=True)

or

Services.objects.filter(is_fun=True).nearest(some_user)

(Maybe it does in your particular case, but broadly speaking, it shouldn't).

You may also want to take a look at django.contrib.gis (also known as
GeoDjango):

https://docs.djangoproject.com/en/1.7/ref/contrib/gis/

This toolbox gives you a whole bunch of useful tools for performing
geographic queries, including computing the distance to a point,
determining if a point is inside a polygonal geographic boundary, and so
on. It's a little more difficult to set up, but it's much more powerful
(and accurate) than a simple lat/lng pair.

The Expressions API that will be part of Django 1.8 would also be useful to
you:

https://docs.djangoproject.com/en/dev/ref/models/expressions/

However, that would be riding the bleeding edge of Django, so unless you're
looking to be particularly adventurous, I'd stick to the more stable
options.


> 2) The computed value is not just useful for the QuerySet, but I need
> also that on client side so I serialize it and I send it using JSON.
> Is possible to make sure that the manager attach the field "distance"
> to the objects in the QuerySet?
>

If it's available for the database to filter, then it will automatically be
on the objects in the QuerySet, which means it will be available for
serialisation.

Yours,
Russ Magee %-)

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-users+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at http://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/CAJxq84-J--XpJL%3DJjaVqcvu1qcC7yUUxu%2BB98A8suMTNPqFYZA%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to