Greg Hinch
Greg Hinch

Reputation: 827

Django finding which field matched in a multiple OR query

I've got a couple models which are set up something like this:

class Bar(models.Model):
  baz = models.CharField()

class Foo(models.Model):
  bar1 = models.ForeignKey(Bar)
  bar2 = models.ForeignKey(Bar)
  bar3 = models.ForeignKey(Bar)

And elsewhere in the code, I end up with an instance of Bar, and need to find the Foo it is attached to in some capacity. Right now I came up with doing a multiple OR query using Q, something like this:

foo_inst = Foo.objects.get(Q(bar1=bar_inst) | Q(bar2=bar_inst) | Q(bar3=bar_inst))

What I need to figure out is, which of the 3 cases actually hit, at least the name of the member (bar1, bar2, or bar3). Is there a good way to do this? Is there a better way to structure the query to glean that information?

Upvotes: 2

Views: 117

Answers (2)

rockingskier
rockingskier

Reputation: 9346

You could change things up and use a ChoiceField?

BAR_VERSIONS = (
    ('Bar 1', 'bar1'),
    ('Bar 2', 'bar2'),
    ('Bar 3', 'bar3'),
)


class Bar(models.Model):
  baz = models.CharField()

class Foo(models.Model):
  bar = models.ForeignKey(Bar)
  bar_version = models.ChoiceField(choices=BAR_VERSIONS)

Then:

try:
    foo_instance = Foo.objects.get(bar=bar_instance)
except Foo.DoesNotExist:
    # Handle Exception
    pass
else:
    print(foo_instance.bar_version)

UPDATE: From your comment, as the idea is to have none or all bars set you could still use this approach but use a ManyToManyField with the through parameter. This would make it nice and extendible in the future if you wanted to add bar4 - barn rather than extending your try-except waterfall.

https://docs.djangoproject.com/en/dev/topics/db/models/#intermediary-manytomany

class Bar(models.Model):
  baz = models.CharField()

class Foo(models.Model):
  bars = models.ManyToManyField(bar, through='FooBars')

class FooBars(models.Model):
  foor = models.ForeignKey(Foo)
  bar = models.ForeignKey(Bar)
  bar_version = models.ChoiceField(choices=BAR_VERSIONS)

Upvotes: 0

thikonom
thikonom

Reputation: 4267

try:
    Foo.objects.get(bar1=bar_inst)
    print 'bar1'
except Foo.DoesNotExist:
    try:
        Foo.objects.get(bar2=bar_inst)
        print 'bar2'
    except Foo.DoesNotExist:
        try:
           Foo.objects.get(bar3=bar_inst)
           print 'bar3'
        except Foo.DoesNotExist:
           print 'nothing found'

Also consider adding related_name to all the bar fields of your model.

Upvotes: 1

Related Questions