Модели Django - как отфильтровать повторяющиеся значения по PK? - PullRequest
6 голосов
/ 13 апреля 2009

Я строю список объектов модели Django, выполняя несколько запросов. Затем я хочу удалить любые дубликаты (все эти объекты одного типа с auto_increment int PK), но я не могу использовать set (), потому что они не могут быть хэшируемыми.

Есть ли быстрый и простой способ сделать это? Я рассматриваю возможность использования dict вместо списка с идентификатором в качестве ключа.

Ответы [ 6 ]

12 голосов
/ 14 апреля 2009

В общем случае лучше объединить все ваши запросы в один запрос, если это возможно. Т.е..

q = Model.objects.filter(Q(field1=f1)|Q(field2=f2))

вместо

q1 = Models.object.filter(field1=f1)
q2 = Models.object.filter(field2=f2)

Если в первом запросе возвращаются дублированные модели, тогда используйте Different ()

q = Model.objects.filter(Q(field1=f1)|Q(field2=f2)).distinct()

Если ваш запрос действительно невозможно выполнить с помощью одной команды, то вам придется прибегнуть к использованию dict или другого метода, рекомендованного в других ответах. Было бы полезно, если бы вы разместили точный запрос на SO, и мы могли бы посмотреть, можно ли объединить его в один запрос. По моему опыту, большинство запросов можно выполнить с помощью одного набора запросов.

6 голосов
/ 13 апреля 2009

Есть ли быстрый и простой способ сделать это? Я рассматриваю возможность использования dict вместо списка с идентификатором в качестве ключа.

Это именно то, что я бы сделал, если бы вы были привязаны к вашей текущей структуре, чтобы сделать несколько запросов. Тогда просто dictionary.values() вернет ваш список обратно.

Если у вас есть немного больше гибкости, почему бы не использовать Q объекты? Вместо того, чтобы фактически выполнять запросы, сохраняйте каждый запрос в объекте Q и используйте побитовое или ("|") для выполнения одного запроса. Это позволит достичь вашей цели и сохранить попадания в базу данных.

объекты Django Q

3 голосов
/ 13 апреля 2009

Вы можете использовать набор, если добавите функцию __hash__ к определению модели, чтобы она возвращала идентификатор (при условии, что это не влияет на другое поведение хеширования, которое может иметься в вашем приложении):

class MyModel(models.Model):

    def __hash__(self):
        return self.pk
0 голосов
/ 22 февраля 2010

Я использую это:

dict(zip(map(lambda x: x.pk,items),items)).values()
0 голосов
/ 13 апреля 2009

Удаление «дубликатов» зависит от того, как вы определяете «дубликат».

Если вы хотите, чтобы КАЖДЫЙ столбец (кроме ПК) совпадал, это боль в шее - это много для сравнения.

Если, с другой стороны, у вас есть некоторый столбец с «естественным ключом» (или короткий набор столбцов), вы можете легко запросить и удалить их.

master = MyModel.objects.get( id=theMasterKey )
dups = MyModel.objects.filter( fld1=master.fld1, fld2=master.fld2 )
dups.all().delete()

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


Редактировать

Если объекты модели еще не сохранены в базе данных, вы можете создать словарь на основе этих ключей.

unique = {}
...
key = (anObject.fld1,anObject.fld2)
if key not in unique:
    unique[key]= anObject
0 голосов
/ 13 апреля 2009

Если порядок не имеет значения, используйте диктовку.

...