Hi Karim, On Wed, Dec 10, 2014 at 8:07 AM, Karim <[email protected]> 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 [email protected]. To post to this group, send email to [email protected]. 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.

