views:

60

answers:

1

I have a model with a reference property, eg:

class Data(db.Model):
    x = db.IntegerProperty()

class Details(db.Model):
    data = db.ReferenceProperty(reference_class = Data)

The data reference can be None.

I want to fetch all Details entities which have valid data, ie for which the reference property is not None.

The following works:

Details.all().filter('data !=', None).fetch(1000)

However, according to the documentation on queries, a != query will actually perform two queries, which seems unnecessary in this case. Is != optimised to only perform one query when used with None?

Alternatively, this post mentions that NULL always sorts before valid values. Therefore the following also appears to work:

Details.all().filter('data >', None).fetch(1000)

Although this would only do one query, using > instead of != makes the intent of what it is doing less obvious.

As a third option, I could add an extra field to the model:

class Details(db.Model):
    data = db.ReferenceProperty(reference_class = Data)
    has_data = db.BooleanProperty()

As long as I keep has_data synchronised with data, I could do:

Details.all().filter('has_data =', True).fetch(1000)

Which way would be best?

Thanks.

+2  A: 

I would advise you to use the extra model field. This is more flexible, since it also allows you to query for Details that have no Data references. In addition, queries can only have one inequality filter, so you're better off saving this inequality filter for another property where inequality makes more sense, such as integer properties.

To make sure the flag is always updated, you can add a convenience function to Details, like so:

class Details(db.Model):
    data = db.ReferenceProperty(reference_class=Data)
    has_data = db.BooleanProperty(default=False)

    def add_data(self, data):
        """ Adds data"""
        if not data: return
        self.has_data = True
        self.data = data
        return self.put()
mahmoud
Triple quotes, not quadruple quotes :)
Tim McNamara
Oops. Thank you, Tim. Edited.
mahmoud
@mahmoud: Re "This is more flexible, since it also allows you to query for Details that have no Data references" - it is actually possible to use `Details.all().filter('data =', None).fetch(1000)` to do this. However I hadn't considered the angle of saving the inequality filter for something else if I need it in the future - good point. Thanks.
Saxon Druce