Search code examples
pythongoogle-app-enginejinja2blobstorewebapp2

Python Google App Engine. GET Request sent twice


A GET Request is being sent twice when a User clicks a link in a Google App Engine, Python App. The App uses webapp2 and jinja2.

This only happens if a Blobstore image is missing from the Datastore Model, "Event". If the image is present in "Event", there is only one GET Request recorded in Logs. If the blobstore image has not been uploaded by the User, then there is a second GET Request, which is returned with a NoneType Error.

The GET Requests are sending to the same Handler, "InfoHandler(BaseHandler)".

Code:

NDB Model:

class Event(ndb.Model):
    """datastore class for storing events"""

    # : event properties
    org_user = ndb.StringProperty() #ID string for the Organiser
    poster_url = ndb.StringProperty() #blobstore image url
    poster_key = ndb.StringProperty() #blobstore image key
    ....

BaseHandler:

def get_obj_from_url(self, position, kind):
    """ returns a datastore object from a url"""

    #: first get the url string
    url_string = self.request.url
    #: then split the string on POSITION to get the key value
    key_value = url_string.split('/')[position]
    #: now query to get the entity instance from the key value
    qry = ndb.Key(kind, key_value)
    #: finally you can get the datastore object
    db_obj = qry.get()
    return db_obj

events.py for rendering the page

class InfoHandler(BaseHandler):
    """handler to render the event info page"""
    def get(self):

        #: SET LOCALE
        self.set_locale()
        #: TEST FOR THE USER
        user_id = self.user_obj()
        if user_id:
            if db_user.User.get_by_id(user_id):
                #: get the user info from datastore
                info = db_user.User.get_by_id(user_id)
                #: get the event object from the datastore
                event_obj = self.get_obj_from_url(-1, "Event")
                org_user_id = event_obj.org_user

Logging Error Stack:

- [14/Mar/2015:07:20:13 -0700] "GET     /events/event_info/None     HTTP/1.1" 500 719         "http://www.x.com/events/event_info/example_event" "Mozilla/5.0     (Linux; Android     4.4.2; SM-T805 Build/KOT49H) AppleWebKit/537.36     (KHTML, like Gecko)     Chrome/40.0.2214.109 Safari/537.36"     "www.x.com" ms=94     cpu_ms=76 cpm_usd=0.000080     app_engine_release=1.9.18         instance=00c61b117c03db016d0f4da5a9f36a8e9aea83fd
E 2015-03-14 15:20:13.235
'NoneType' object has no attribute 'org_user'
Traceback (most recent call last):
  File         "/base/data/home/runtimes/python27/python27_lib/versions/third_party/        webapp2-2.5.2/webapp2.py", line 1535, in __call__
    rv = self.handle_exception(request, response, e)
  File         "/base/data/home/runtimes/python27/python27_lib/versions/third_party/        webapp2-2.5.2/webapp2.py", line 1529, in __call__
    rv = self.router.dispatch(request, response)
  File         "/base/data/home/runtimes/python27/python27_lib/versions/third_party/        webapp2-2.5.2/webapp2.py", line 1278, in default_dispatcher
    return route.handler_adapter(request, response)
  File         "/base/data/home/runtimes/python27/python27_lib/versions/third_party/        webapp2-2.5.2/webapp2.py", line 1102, in __call__
    return handler.dispatch()
  File         "/base/data/home/runtimes/python27/python27_lib/versions/third_party/        webapp2-2.5.2/webapp2.py", line 572, in dispatch
    return self.handle_exception(e, self.app.debug)
  File         "/base/data/home/runtimes/python27/python27_lib/versions/third_party/        webapp2-2.5.2/webapp2.py", line 570, in dispatch
    return method(*args, **kwargs)
  File "/base/data/home/apps/s~x/0-9-9-9-        4.382865846043625422/events/events.py", line 753, in get
    org_user_id = event_obj.org_user
AttributeError: 'NoneType' object has no attribute 'org_user'

This Error doesn't affect the User, as the first GET Request returns the "Event" object, without the image, and the page is rendered without Errors. It is however a quirk that I would like to figure out.

Why is the GET Request being sent twice?

Thanks for your help.

EDIT:

Template Code:

def render_template(self, route, filename, template_values):
    """ you need a function to render the template from jinja.
        takes these inputs:
        route - route to template folder
        filename - the name of the template
        template_values - the values returned in the template
    """

    #: first you need to define the loader environment and extensions
    jinja_env = jinja2.Environment(
        loader=jinja2.FileSystemLoader(route),
        autoescape=True,
        extensions=['jinja2.ext.i18n'])
    #: you need to set gettext to retrieve translation from templates via the {{trans}} tag
    jinja_env.install_gettext_translations(i18n)
    #: you need to set the attribute, template, using the filename value
    template = jinja_env.get_template(filename)
    #: now you can output the template with the template_values
    self.response.write(template.render(template_values))

Solution

  • Your question is missing critical information, how are the routes set up, where's the template code? The problem obviously comes from the client, where else could the request come from? You should be providing information on that front.

    Anyway, for some weird reason I think I might know what it is...

    I'm guessing when you render the page you have some img tag with a url, and that url is event.poster_url, which if uploaded will be whatever you got from get_serving_url, but if that hasn't happened yet the value will be None.

    I'm also guessing the current location (in the browser, when the problem happens) is /events/event_info/, and so in the 2nd case will cause a request to /events/event_info/None.

    Hoping my crystal ball works :)