1

again I would like to search for duplicates in my models, but now slightly different case.

Here are my models:

class Concept(models.Model):
    main_name = models.ForeignKey(Literal)
    ...
class Literal(models.Model):
    name = models.Charfield(...)
    concept = models.ForeignKey(Concept)
    ...

And now the task I'm trying to achieve: Select all literals that are NOT main_names, that have the same name for the same concept.

For example if I have literals:

[{id:1, name:'test', concept:1}, {id:2, name:'test', concept:1}]

and concepts:

[{id:1, main_name:1}]

Then in result I should get literal with the ID=2.

2 Answers 2

1

It sounds to me as though you want to execute a SQL query something like this:

SELECT l1.* FROM myapp_literal AS l1,
                 myapp_literal AS l2
WHERE l1.id <> l2.id
  AND l1.name = l2.name
  AND l1.concept = l2.concept
  AND l1.id NOT IN (SELECT main_name FROM myapp_concept)
GROUP BY l1.id

Well, in cases where the query is too complex to easily express in Django's query language, you can always ask Django to do a raw SQL query—and this may be one of those cases.

Sign up to request clarification or add additional context in comments.

4 Comments

Yes, I think I gives exactly what I want, except that you need to specify l1.id instead of l1.*, otherwise it will be column must appear in the GROUP BY clause or be used in an aggregate function
could you also tell me what should I write do delete everything selected from l1?
I guess I'm too used to MySQL, which allows non-aggregated columns in the SELECT part of GROUP BY queries. You're quite right to point out that in most databases this won't be allowed.
To delete the records matching a query, you can use Django's delete method on the query. Something like Literal.objects.raw('SELECT ...').delete() But take care—the query I wrote selects all records with duplicates—you probably want to delete all but one of each matching set.
1

If I understand your question you want:

  1. All Literal objects that are not ForeignKey'd to Concept.
  2. From that set, select those where the name and the concept is the same.

If so, I think this should work:

For the first part:

q = Literal.objects.exclude(pk__in=Concept.objects.values_list('id', flat=True))

EDIT:

Based on excellent feedback from Jan, I think for #2 you would need to use raw SQL.

6 Comments

It should be values_list and I think your second part doesn't do anything. Do you mean q.filter(name=F('concept__main_name__name'))? I'm not sure if this is optimal in performance though.
I'm not sure about the performance part to be honest; but I think the F expression is correct as per my understanding of the docs. Thanks for the values_list, edited.
Does it not just test whether the literal's name equals its own name (same for concept), which is of course true for all literals?
OK. I posted a possible solution in my comment and think that it does actually work, without using raw SQL but foreign-key lookups.
Yep, I know have to select all not main literals, this is fairly simple, my insterest was how to perform the whole task. Thanks for the help anyway.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.