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.