Pergunta

I construir uma lista de objetos de modelo Django, fazendo várias consultas. Então eu quero remover todas as duplicatas, (todos estes objetos são do mesmo tipo com um int PK auto_increment), mas não pode usar set (), porque eles não são Hashable.

Existe uma maneira rápida e fácil de fazer isso? Estou pensando em usar um dicionário em vez de uma lista com o ID como a chave.

Foi útil?

Solução

Existe uma maneira rápida e fácil de fazer isso? Estou pensando em usar um dicionário em vez de uma lista com o ID como a chave.

Isso é exatamente o que eu faria se estivesse trancado em sua estrutura atual de fazer várias consultas. Em seguida, um simplesmente dictionary.values() voltará lista de suas costas.

Se você tem um pouco mais de flexibilidade, por que não usar objetos Q? Em vez de realmente fazer as consultas, armazenar cada consulta em um objeto Q e usar um bit a bit ou ( "|") para executar uma única consulta. Isso vai atingir o seu objetivo e salvar sucessos de banco de dados.

Django Q objetos

Outras dicas

Em geral, é melhor combinar todas as suas consultas em uma única consulta, se possível. Ie.

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

em vez de

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

Se a primeira consulta está retornando Models duplicados em seguida, usar distinct ()

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

Se a consulta é realmente impossível de executar com um único comando, então você vai ter que recorrer ao uso de um dicionário ou outra técnica recomendada em outras respostas. Pode ser útil se você postou a consulta exata no SO e pudemos ver se seria possível combinar em uma única consulta. Na minha experiência, a maioria das consultas pode ser feito com um único queryset.

Você pode usar um conjunto se você adicionar a função __hash__ à sua definição de modelo para que ele retorna o id (assumindo que este não interfere com outros comportamentos de hash você pode ter em seu aplicativo):

class MyModel(models.Model):

    def __hash__(self):
        return self.pk

Se a ordem não importa, use um dicionário.

Remover "duplicatas" depende de como você define "duplicado".

Se você quiser cada coluna (exceto a PK) para corresponder, que é uma dor no pescoço. - É um monte de comparação

Se, por outro lado, você tem alguma coluna "chave natural" (ou curto conjunto de colunas) do que você pode facilmente consulta e removê-los.

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

Se você pode identificar um conjunto menor de campos-chave para identificação duplicado, isso funciona muito bem.


Editar

Se os objetos do modelo não foram salvas no banco de dados, no entanto, você pode fazer um dicionário em uma tupla destas chaves.

unique = {}
...
key = (anObject.fld1,anObject.fld2)
if key not in unique:
    unique[key]= anObject

Eu uso este:

dict(zip(map(lambda x: x.pk,items),items)).values()
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top