Django/Python - Объекты группировки единым набором от many-many отношения

Это довольно просто, ваша ошибка объясняет это. 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 или что-то в этом роде.

7
задан 5 revs 23 May 2017 в 12:30
поделиться

5 ответов

Вы попытались сортировать список сначала? Алгоритм, который Вы предложили, должен работать, хотя с большим количеством базы данных совершает нападки.

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 является братом Вашего общеизвестного родительского элемента.

4
ответ дан 7 December 2019 в 05:33
поделиться

У Вас есть несколько проблем здесь.

Вы не отсортировали свой список прежде, чем назвать 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))
1
ответ дан 7 December 2019 в 05:33
поделиться

проверка перегруппировывает. это только для шаблонов, но я предполагаю, что этот вид классификации принадлежит уровню представления так или иначе.

2
ответ дан 7 December 2019 в 05:33
поделиться

Спасибо всем за полезные ответы. Я корпел в этой проблеме. 'Лучшее' решение все еще ускользает от меня, но у меня есть некоторые мысли.

Я должен упомянуть, что статистика набора данных работаю с. В 75% случаев будет одна Модификация. В 24% случаев, два. В 1% случаев будет нуль, или три или больше. Для каждой Модификации существует по крайней мере один уникальный Автомобиль, хотя Модификация может быть применена к многочисленным Автомобилям.

Однако я рассмотрел (но не реализовал), что-то как так:

class ModSet(models.Model):
  mods = models.ManyToManyField(Mod)

и автомобили изменения к

class Car(models.Model):
  modset = models.ForeignKey(ModSet)

Это тривиально для группировки Car.modset: Я могу использовать, перегруппировывают, как предложил Javier, например. Это кажется более простым и довольно изящным решением; мысли очень ценились бы.

0
ответ дан 7 December 2019 в 05:33
поделиться

Если производительность является беспокойством (т.е. много автомобилей на странице или сайт интенсивного трафика), денормализация имеет смысл и упрощает Вашу проблему как побочный эффект.

Знайте, что денормализовывание many-many отношения могло бы быть немного хитрым все же. Я еще не столкнулся ни с какими подобными примерами кода.

1
ответ дан 7 December 2019 в 05:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: