Reputation: 2948
I have the following models:
class TradeList(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, unique=True)
text = models.TextField(null=True, blank=True)
modified = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['-modified']
def __str__(self):
return "{}'s trade list".format(self.user.username)
def get_absolute_url(self):
return reverse('tradelist_detail', kwargs={'username': self.user.username})
class TradeItem(models.Model):
tradelist = models.ForeignKey('TradeList')
card = models.ForeignKey('cards.Card')
quantity = models.PositiveSmallIntegerField()
class Meta:
abstract = True
class ForTrade(TradeItem):
class Meta:
verbose_name_plural = 'for trade'
ordering = ['card']
class LookingFor(TradeItem):
class Meta:
verbose_name_plural = 'looking for'
ordering = ['card']
I want to be able to search these models from my site, so I created a form like so:
class TradeListSearchForm(forms.Form):
for_trade = forms.ModelMultipleChoiceField(queryset=Card.objects.all())
I am using the generic FormView to handle the form, so I have overridden its form_valid
method to customise the behaviour when the form has been validated successfully:
class TradeListSearchView(FormView):
form_class = TradeListSearchForm
template_name = 'trades/tradelist_search.html'
def form_valid(self, form):
search_results = TradeList.objects.filter(fortrade__card__in=form.cleaned_data['for_trade'])
return self.render_to_response(self.get_context_data(form=form,
search_results=search_results))
This works great except for one thing. At the moment, the user can select multiple cards to search for and the view searches for all tradelists that have any of those particular cards for trade. However I would like to be able to perform the search to that it looks for only those tradelists that have ALL the cards selected for trade, but I cannot think how to do this.
Upvotes: 0
Views: 69
Reputation: 7622
I think you can use a little magic:
This line is what kills your boom:
search_results = TradeList.objects.filter(fortrade__card__in=form.cleaned_data['for_trade'])
Instead of it, use this: (notice i'm explicitly filtering down the TradeList instances many times)
for_trade = form.cleaned_data['for_trade']
search_results = Tradelist.objects.all()
for card in for_trade:
search_results = search_results.filter(fortrade__card__id=card.id)
This way, you'll filter your objects on all for all of the cards. Previously you were returning (as you already said) every tradelist that had a card among your selection.
Upvotes: 2