class Sentence(Model): name = CharField() class Tokens(Model): token = CharField() sentence = ForeignKey(Sentence, related_name='tokens')
I want to implement two cases: Sentence consists exactly of three tokens
['I', 'like', 'apples']
. So list ofsentence.tokens.all()
is exactly['I', 'like', 'apples']
.Same as above, but contains tokens (part of sentence).
Sentence.objects.annotate(n=Count('tokens',distinct=True)).filter(n=3).filter(tokens__name='I').filter(tokens__name='like').filter(tokens__name='apples')
doesn't work, since it matches I I I
as well.
Is there any way to filter on exact set of values in ForeignKey?
2 Answers
Answers 1
Ah, I understand the question better now. Just leveraging elements of your and Jay's code, the following might be one approach. May be not very elegant. But seems to work.
def get_sentences(my_tokens): counts = dict() for t in my_tokens: counts[t] = my_tokens.count(t) results = Sentence.objects for k, v in counts.iteritems(): results = results.filter(tokens__token=k).annotate(n=Count('tokens',distinct=True)).filter(n__gte=v) return results >>> from django.db.models import Count >>> from my.models import Sentence, Tokens >>> s1 = Sentence.objects.create(name="S1") >>> t10 = Tokens.objects.create(token="I", sentence=s1) >>> t20 = Tokens.objects.create(token="like", sentence=s1) >>> t30 = Tokens.objects.create(token="apples", sentence=s1) >>> s2 = Sentence.objects.create(name="S2") >>> t11 = Tokens.objects.create(token="I", sentence=s2) >>> t21 = Tokens.objects.create(token="like", sentence=s2) >>> t31 = Tokens.objects.create(token="oranges", sentence=s2) >>> s3 = Sentence.objects.create(name="S3") >>> t31 = Tokens.objects.create(token="I", sentence=s3) >>> t32 = Tokens.objects.create(token="I", sentence=s3) >>> t33 = Tokens.objects.create(token="I", sentence=s3) >>> my_toks = ("I", "like", "apples") >>> sentences = get_sentences(my_toks) >>> sentences[0].name u'S1' >>> my_toks = ("I", "I", "I") >>> sentences = get_sentences(my_toks) >>> sentences[0].name u'S3'
For exact reference, my models look like this:
class Sentence(Model): name = models.CharField(max_length=16) class Tokens(Model): token = models.CharField(max_length=16) sentence = models.ForeignKey(Sentence, related_name='tokens')
Answers 2
Are you trying to get every sentence that contains each of the search tokens?
A flexible (although likely non-optimal) way of doing this might be:
search_tokens = ('I', 'like', 'apples') results = Sentence.objects for token in search_tokens: results = results.filter(tokens__name=token) results.distinct()
This is equivalent to just chaining the filters together:
results = Sentence.objects.filter(tokens__name='I').filter(tokens__name='like').filter(tokens__name='apples').distinct()
0 comments:
Post a Comment