问题
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 Document
s 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