Это довольно просто, ваша ошибка объясняет это. userParams.MaxPrice
является нулевым. Так что вам нужно добавить проверку на ноль к нему. Простым способом было бы изменить ваш запрос на:
if (userParams.MinPrice > 0 && userParams.MaxPrice != null && userParams.MaxPrice != 999999999)
{
products = products.Where(p => (p.Price >= userParams.MinPrice) &&
(p.Price <= userParams.MaxPrice));
}
Хотя, в зависимости от вашей логики, вам может потребоваться немного изменить положение вещей. Ключевой момент заключается в том, чтобы не предполагать, что свойство имеет значение, если оно имеет значение NULL, то сначала нужно проверить, что оно не равно NULL, а затем проверить его.
Также следует добавить, что в теории вы могли бы сделать userParams.MaxPrice.GetValueOrDefault() != 999999999
, предполагая, что это null-значение int или что-то в этом роде.
Вы попытались сортировать список сначала? Алгоритм, который Вы предложили, должен работать, хотя с большим количеством базы данных совершает нападки.
import itertools
cars = [
{'car': 'X2', 'mods': [1,2]},
{'car': 'Y2', 'mods': [2]},
{'car': 'W2', 'mods': [1]},
{'car': 'X1', 'mods': [1,2]},
{'car': 'W1', 'mods': [1]},
{'car': 'Y1', 'mods': [2]},
{'car': 'Z1', 'mods': [1,2,3]},
{'car': 'X3', 'mods': [1,2]},
]
cars.sort(key=lambda car: car['mods'])
cars_by_common_mods = {}
for k, g in itertools.groupby(cars, lambda car: car['mods']):
cars_by_common_mods[frozenset(k)] = [car['car'] for car in g]
print cars_by_common_mods
Теперь, о тех запросах:
import collections
import itertools
from operator import itemgetter
from django.db import connection
cursor = connection.cursor()
cursor.execute('SELECT car_id, mod_id FROM someapp_car_mod ORDER BY 1, 2')
cars = collections.defaultdict(list)
for row in cursor.fetchall():
cars[row[0]].append(row[1])
# Here's one I prepared earlier, which emulates the sample data we've been working
# with so far, but using the car id instead of the previous string.
cars = {
1: [1,2],
2: [2],
3: [1],
4: [1,2],
5: [1],
6: [2],
7: [1,2,3],
8: [1,2],
}
sorted_cars = sorted(cars.iteritems(), key=itemgetter(1))
cars_by_common_mods = []
for k, g in itertools.groupby(sorted_cars, key=itemgetter(1)):
cars_by_common_mods.append({'mods': k, 'cars': map(itemgetter(0), g)})
print cars_by_common_mods
# Which, for the sample data gives me (reformatted by hand for clarity)
[{'cars': [3, 5], 'mods': [1]},
{'cars': [1, 4, 8], 'mods': [1, 2]},
{'cars': [7], 'mods': [1, 2, 3]},
{'cars': [2, 6], 'mods': [2]}]
Теперь, когда у Вас есть свои списки автомобильных идентификаторов и ультрасовременных идентификаторов при необходимости в полных объектах работать с Вы могли бы сделать единый запрос для каждого, чтобы получить полный список для каждой модели и создать поиск dict
для, включенных их идентификаторами - затем, я верю, Bob является братом Вашего общеизвестного родительского элемента.
У Вас есть несколько проблем здесь.
Вы не отсортировали свой список прежде, чем назвать groupby, и это требуется. Из itertools документации:
Обычно повторяемые потребности, которые уже будут отсортированы на той же ключевой функции.
Затем Вы не копируете список, возвращенный groupby. Снова, документация указывает:
Возвращенная группа является самостоятельно итератором, который совместно использует базовое повторяемое с groupby (). Поскольку источник совместно используется, когда объект groupby совершенствуется, предыдущая группа больше не видима. Так, если те данные необходимы позже, они должны быть сохранены как список:
groups = [] uniquekeys = [] for k, g in groupby(data, keyfunc): groups.append(list(g)) # Store group iterator as a list uniquekeys.append(k)
И заключительная ошибка использует наборы в качестве ключей. Они не работают здесь. Быстрое исправление должно бросить их к отсортированным кортежам (могло быть лучшее решение, но я не могу думать о нем теперь).
Так, в Вашем примере последняя часть должна быть похожей на это:
sortMethod = lambda x: tuple(sorted(set(x.mods)))
sortedMods = sorted(list(mods), key=sortMethod)
for key, mods_group in groupby(sortedMods, sortMethod):
ret.append(list(mods_group))
проверка перегруппировывает. это только для шаблонов, но я предполагаю, что этот вид классификации принадлежит уровню представления так или иначе.
Спасибо всем за полезные ответы. Я корпел в этой проблеме. 'Лучшее' решение все еще ускользает от меня, но у меня есть некоторые мысли.
Я должен упомянуть, что статистика набора данных работаю с. В 75% случаев будет одна Модификация. В 24% случаев, два. В 1% случаев будет нуль, или три или больше. Для каждой Модификации существует по крайней мере один уникальный Автомобиль, хотя Модификация может быть применена к многочисленным Автомобилям.
Однако я рассмотрел (но не реализовал), что-то как так:
class ModSet(models.Model):
mods = models.ManyToManyField(Mod)
и автомобили изменения к
class Car(models.Model):
modset = models.ForeignKey(ModSet)
Это тривиально для группировки Car.modset: Я могу использовать, перегруппировывают, как предложил Javier, например. Это кажется более простым и довольно изящным решением; мысли очень ценились бы.
Если производительность является беспокойством (т.е. много автомобилей на странице или сайт интенсивного трафика), денормализация имеет смысл и упрощает Вашу проблему как побочный эффект.
Знайте, что денормализовывание many-many отношения могло бы быть немного хитрым все же. Я еще не столкнулся ни с какими подобными примерами кода.