pythondjangogoogle-app-enginegoogle-cloud-datastoredjango-nonrel

Django nonrel Query confusion


I'm creating a practice django-nonrel project hosted on Google AppEngine to get some familiarity with Django and the AppEngine Platform, but am running into a perplexing query issue. Here is my models.py:

  class Character(models.Model):
        name = models.CharField(max_length=200)
        url_name = models.CharField(max_length=200)

        def save(self, *args, **kwargs):
            self.url_name = self.name.replace(" ", "-").lower()
            super(Character, self).save(*args, **kwargs) # Call the "real" save() method.


    def __unicode__(self):
        return '%s' %(self.name)

class Season(models.Model):
    season_number = models.IntegerField()

    def __unicode__(self):
        return u'Season %d' % (self.season_number)

class Episode(models.Model):
    season = models.ForeignKey(Season)
    episode_name = models.CharField(max_length=200)
    episode_number= models.IntegerField()

    def __unicode__(self):
        return u'Season %d, Episode %d "%s"' %(self.season.season_number, self.episode_number, self.episode_name)

class Quote(models.Model):
    author = models.ForeignKey(Character)
    episode = models.ForeignKey(Episode)
    quote_text = models.TextField()

    def __unicode__(self):
        return u'"%s" (%s)' % (self.quote_text, self.episode)

Now here is where the confusion is: Why does Quote.objects.all().order_by('episode') work, while Quote.objects.filter(author__name="Michael Scott").order_by('episode') not work? As evidenced by the last filter, the problem is not with the author__name call, as that index has been registered using dbindexer. The problem is with the order_by('episode') portion, but I don't understand why that would work on one QuerySet but not another.

>>> from QuotesCMS.models import Character, Season, Episode, Quote
>>> Quote.objects.all().order_by('episode')
[<Quote: "My proudest moment here wasn't when I increased profits by 17 percent, or cut expenditure without losing a single member of staff. No no no. It was a young Guatemalan guy, first job in the country, barely spoke a word of English, but he came to me and said, 'Mr. Scott, will you be the godf
ather to my child?' Wow... wow. Didn't work out in the end. We had to let him go. He sucked." (Season 1, Episode 1 "Pilot")>, <Quote: " Abraham Lincoln once said, 'If you are a racist, I will attack you with the North,' and those are the principles I carry with me into the workplace." (Season 1, Epi
sode 2 "Diversity Day")>, <Quote: "I love inside jokes... I'd love to be a part of one someday." (Season 3, Episode 2 "The Convention")>, <Quote: "I declare...bankruptcy!!!" (Season 4, Episode 4 "Money")>, <Quote: "When I'm at home at night in my own house in my sweats, drinking red wine, watching m
y mystery stories the last thing in the whole godforsaken world I want to hear is the voice of Michael Scott." (Season 4, Episode 4 "Money")>, <Quote: "As of this morning, we are completely wireless here on Schrute Farms. So as soon as I find out where Mose hid all the wires, we can have power back
on. " (Season 4, Episode 4 "Money")>, <Quote: "I just realized that this is Pam's and my first night away together. I used to play it over in my head, and it was just a little bit different. Maybe a nice hotel, or a romantic dinner, wine, but wine that wasn't made out of beets. Didn't think Dwight w
ould be involved at all. And I always imagined less manure. I mean, some manure, just less." (Season 4, Episode 4 "Money")>]

-

>>> Quote.objects.filter(author__name="Michael Scott").order_by('episode')
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "C:\OfficeQuotes\django\db\models\query.py", line 93, in __repr__
    data = list(self[:REPR_OUTPUT_SIZE + 1])
  File "C:\OfficeQuotes\django\db\models\query.py", line 108, in __len__
    self._result_cache.extend(self._iter)
  File "C:\OfficeQuotes\django\db\models\query.py", line 317, in iterator
    for row in compiler.results_iter():
  File "C:\OfficeQuotes\djangotoolbox\db\basecompiler.py", line 411, in results_iter
    for entity in results:
  File "C:\OfficeQuotes\djangoappengine\db\compiler.py", line 138, in fetch
    for entity in results:
  File "C:\Program Files (x86)\Google\google_appengine\google\appengine\datastore\datastore_query.py", line 3317, in next
    next_batch = self.__batcher.next_batch(Batcher.AT_LEAST_OFFSET)
  File "C:\Program Files (x86)\Google\google_appengine\google\appengine\datastore\datastore_query.py", line 3203, in next_batch
    batch = self.__next_batch.get_result()
  File "C:\Program Files (x86)\Google\google_appengine\google\appengine\api\apiproxy_stub_map.py", line 613, in get_result
    return self.__get_result_hook(self)
  File "C:\Program Files (x86)\Google\google_appengine\google\appengine\datastore\datastore_query.py", line 2917, in __query_result_hook
    yaml_index=yaml, xml_index=xml)
NeedIndexError: no matching index found.
The suggested index for this query is:
- kind: QuotesCMS_quote
  properties:
  - name: author_id
  - name: episode_id

-

 >>> Quote.objects.filter(author__name="Michael Scott")
    [<Quote: "I declare...bankruptcy!!!" (Season 4, Episode 4 "Money")>, <Quote: " Abraham Lincoln once said, 'If you are a racist, I will attack you with the North,' and those are the principles I carry with me into the workplace." (Season 1, Episode 2 "Diversity Day")>, <Quote: "My proudest moment her
    e wasn't when I increased profits by 17 percent, or cut expenditure without losing a single member of staff. No no no. It was a young Guatemalan guy, first job in the country, barely spoke a word of English, but he came to me and said, 'Mr. Scott, will you be the godfather to my child?' Wow... wow.
    Didn't work out in the end. We had to let him go. He sucked." (Season 1, Episode 1 "Pilot")>, <Quote: "I love inside jokes... I'd love to be a part of one someday." (Season 3, Episode 2 "The Convention")>]

Hope the quotes are a bit entertaining, and thanks in advance for any help.


Solution

  • You need to manage and update the indexes for your app's queries.

    Check (at least) the Index configuration section of Datastore Indexes.

    The error message you got also includes the information about the index you'll likely need for the particular query you performed.

    Also note that the index configuration doesn't become effective immediately after upload, it may take a while to build newly added indexes. I only saw delays of max a few minutes, but my DB is also quite small. YMMV.