Volodymyr  Prysiazhniuk
Volodymyr Prysiazhniuk

Reputation: 1913

django jeft join query

I have following models:

class TestCaseStatus(models.Model):
    name = models.CharField(default='n/a', max_length=50)
    def __str__(self):
        return self.name


class TestCase(models.Model):
    id = models.CharField(unique=True, max_length=100, primary_key=True)
    name = models.CharField(default='n/a', max_length=200)

    def __str__(self):
        return self.name


class TestRun(models.Model):
    test_id = models.ForeignKey(TestCase)
    run_id = models.CharField(max_length=100, default='0')
    datetime = models.DateTimeField()
    status = models.ForeignKey(TestCaseStatus)
    messages = models.CharField(default='n/a', max_length=500)

    def __str__(self):
        return self.run_id, self.test_id, self.status

I want to execute following SQL query:

select a.test_id_id, a.status_id, b.status_id 
from runscompare_testrun  as a
left join runscompare_testrun as b  on a.test_id_id = b.test_id_id 
where  a.run_id = 1 and b.run_id=2

SQL output:

sql output

I assume that there is a django way to do it to avoid using raw() call, but I can't seems to find it.

Upvotes: 1

Views: 84

Answers (1)

Scott Stevens
Scott Stevens

Reputation: 2651

If I'm understanding your query correctly, you want all the details where run_id="1", with additional details for any runs where the TestCase is the same, but run_id="2".

With that assumption, you could do something like this:

# Start with run_id=1
a = TestRun.objects.filter(run_id="1").select_related(
        'test_id', 'status').prefetch_related(
        'test_id__testrun_set', 'test_id__testrun_set__status')

# For each, get related
for i in a:
    b = i.test_id.testrun_set.filter(run_id="2")
    print(i.test_id, i.status, [j.status for j in b])

This won't be a single database query, as both select_related (docs) and prefetch_related (docs) will make a database call, but it will reduce the number of calls made.

Upvotes: 1

Related Questions