2013-06-15 2 views
1

Я запускаю набор фильтров на одной из моих моделей. В частности, я делаю что-то подобное в одном из моих взглядов:Фильтрация набора запросов django на основе вычисленных значений

cities = City.objects.filter(name__icontains=request.GET['name'] 
cities = City.objects.filter(population__gte=request.GET['lowest_population'] 
return cities 

Теперь я хотел бы добавить еще один, другой тип фильтра. В частности, я хотел бы включить только те города, которые находятся на определенном расстоянии от определенного почтового индекса. У меня уже есть соответствующие функции для этого, то есть что-то вроде:

distanceFromZipCode(city, zipCode) 
# This returns 110 miles, for example 

Как объединить QuerySet Джанго фильтрации с этим дополнительным фильтром, я хотел бы добавить? Я знаю, что если города были просто списком, я мог бы просто использовать .filter() и передать соответствующую лямбду (например, вернуть true, если расстояние от соответствующего почтового индекса < 100).

Но я имею дело с наборами запросов, а не с простыми списками, так как я могу это сделать?

ответ

2

Корень вопроса является то, что вы пытаетесь смешать SQL фильтры, которые сделаны в БД, и питон фильтр, который выполняется один раз записи материализуются из БД. Вы не можете этого сделать, не беря элементы из базы данных и затем фильтруя поверх этого.

Вы не можете, сделать это с помощью вашей функции питона, но вы можете сделать это с помощью GeoDjango:

https://docs.djangoproject.com/en/dev/ref/contrib/gis/db-api/#distance-queries

cites = cities.filter(distance_lt=101) 

бы получить, что вы хотите

1

Вы пытаетесь смешивать метод Python с запросом базы данных, и это невозможно. Либо вы пишете SQL для выполнения вычисления расстояния (быстро), либо вы выбираете каждую строку и вызываете ваш метод (медленный). Фильтры Django просто переводят параметры в предложение SQL WHERE, поэтому, если вы не можете выразить это в SQL, вы, вероятно, не можете выразить это в фильтре.

0

Если вы храните расположение города в геометрии можно использовать на расстоянии пространственный фильтр прикован с остальными вашими фильтрами:

from django.contrib.gis.measure import D 
zipCode = ZipCode.objects.all()[0] 
cities = City.objects.filter(point__distance_lte=(zipCode.geom, D(mi=110))) 

Это подразумевает, что вы имеете модель ZipCode с геометрией каждого почтового индекса и геометрия хранится в поле «geom», а ваш объект City имеет поле точек, называемое «point».

0

По-моему, вы должны использовать Queryset object и определить сложный метод фильтрации внутри custom manager.

from django.db import models 
from django.db.models import Q 


class CityManager(models.Manager): 

    def get_filtered_cities(self, name=None, lowest_population=None, zip_code=None): 
     query = Q() 

     if(name): 
      query = Q(name__icontains=name) 

     if(lowest_population): 
      query = query & Q(population__gte=lowest_population) 

     if(zip_code): 
      pass #other query object 

     return self.get_query_set().filter(query) 
Смежные вопросы