Leah Sapan
Leah Sapan

Reputation: 3791

Django - Check if model has children (related model)

I have two very simple models:

class Author(models.Model):
    name = models.CharField(max_length=255)

    def hasBooks(self):
        return self.books.count()

class Book(models.Model):
    title = models.ForeignKey(Author, related_name="books")

I want to write a function hasBooks (shown above) that simply returns true or false if the author has an associated book. The only way I can think to do this is to get the count() and return true if it is greater than 0, and false if it is 0. The problem with this, is the table of books is enormous, and some authors have thousands of books, so it is a waste of processing to get the exact count. All I want to know is if a single one is there.

Is there a way to do this using less processing?

Upvotes: 2

Views: 2356

Answers (2)

Shrikant Joshi
Shrikant Joshi

Reputation: 76

Why not both? :)

def has_books(self):
    return self.books.count() or False

Python evaluates 0 ( or [], or {} or None, for that matter) as False. Thus, when the count returns 0 the logical expression evaluates to 0 or False = False -- which happens to be exactly what you want your code to do! The neat part is, when the count is non-zero, the function will still return an integer!

You can probably use it in your code as follows:

a = Author.objects.get(pk=1827)
if not a.has_books():
    num_books = a.has_books()

The advantage (as I see it) is that you are getting more out of the same db call and potentially saving yourself an unnecessary extra call to the db.

Upvotes: 0

Julio
Julio

Reputation: 2523

You can try to get the first element:

def hasBooks(self):
    return len(self.books.all()[:1]) == 1

For sure this will note retrieve all the elements but only the first book of an actor (the slice implies a LIMIT 1 in the SQL query).

You can also use the useful exists() function:

def hasBooks(self):
    return self.books.exists()

Upvotes: 4

Related Questions