Combine __icontains lookup with __in lookup in django to get objects that contain part of name in names array

有些话、适合烂在心里 提交于 2019-12-13 04:39:55

问题


Hi My models are as follows

class Document(models.Model)
    id = models.BigIntegerField(primary_key=True)
    text = models.TextField()

class DocumentTags(models.Model):
    name = model.CharField(max_length=256)
    documents_for_tag = models.ManyToManyField(Document)

Now with this I can get all the tags for a particular document with

parent_document = Document.objects.get(id = 1)
parent_document_tags = [x.name for x in parent_document.documenttags_set.all()]

So the parent_document_tags will have all the tags for the parent document for eg.

["nice" , "unique"]

Now I want to next get all the Documents that have tags that closely match this list of tags. I am doing this with

Document.objects.filter(documenttags__name__in=parent_document_tags).distinct()

This however matches only documents that have exactly the names in the parent_document_tags. I want to match with an __icontains (or LIKE) match. How do I do this without splitting up my tags and doing an icontains type lookup one by one.

for eg.

d1 has tags : "nice", "unique"
d2 has tags :  "nice"
d3 has tags : "nicer"

I want the query to return document d3 as well with a LIKE match for "nicer" by chaining the __icontains onto the lookup documenttags__name__in . Can I achieve that or do I have to have a for loop and filter out the duplicates in the end like this code below

related_documents_with_duplicates = []
for tag in parent_document_tags:
    docs = Document.objects.filter(documenttags__name__icontains=tag).distinct()
    related_documents_with_duplicates.extend(docs)
related_documents_id_unique = list(set([x.id for x in related_documents_with_duplicates]))
return Documents.objects.filter(id__in=related_documents_id_unique)

回答1:


A way of acomplishing what you want is to use iregex field lookup.

First, get the tags you want. Instead of doing:

parent_document = Document.objects.get(id = 1)
parent_document_tags = [x.name for x in parent_document.documenttags_set.all()]

you can do:

parent_document_tags = DocumentTags.objects.filter(documents_for_tag=1).values_list("name",flat=True)

Secondly, you get a regular expression that behaves as you want. For example, suppose you have just one tag in parent_document_tags called "tag". If i understand what you want, you would like to match all documents that have tags that contains (icontains) this tag. So your query need to match documents tagged with "tag1" tag, "its_a_common_tag" tag... Am i right?

So, this is how you can create such a regular expression (a string with regex format):

sregex = "|".join(parent_document_tags)
sregex = "(" + sregex + ")"

Finally, the queryset you want would be like this:

Document.objects.filter(documenttags__name__iregex=sregex)

Regular expressions are great. It's difficult to start using them but when you understand how they work, you will earn a lot of effort.

Hope it helps!



来源:https://stackoverflow.com/questions/9647142/combine-icontains-lookup-with-in-lookup-in-django-to-get-objects-that-contai

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!