views:

653

answers:

1

Good Afternoon,

I'm currently trying to build something incredibly simple inside of the Google AppEngine. The goal is to build a simple photo sharing application that will connect back to my iPhone application. It's all a learning experience for both Python and Objective-C.

(I've been a PHP programmer for quite some time).

The goal, create URL's that look like the following: /img/{{ model.key.id }}

The problem is that it seems no matter how I do the python script, I either end up with an error or simply get nothing to display on my template page that's wrapped in the FOR statement.

My App.yaml File:

application: randomwebappname
version: 1
runtime: python
api_version: 1

handlers:
- url: /media
  static_dir: media

- url: /b/.*
  script: beta.py
  login: required

- url: /.*
  script: main.py

My Model (inside beta.py):

class Photo(db.Model):
    author = db.StringProperty()
    title = db.StringProperty()
    slugline = db.StringProperty()
    content = db.StringProperty(multiline=True)
    coordinates = db.StringProperty()
    avatar = db.BlobProperty()
    date = db.DateTimeProperty(auto_now_add=True)

My Class For Viewing The Image Page:

class ViewPage(webapp.RequestHandler):
def get(self, id):


template_values = {
 'image': image,
}

path = os.path.join(os.path.dirname(__file__), 'templates/view.html')
self.response.out.write(template.render(path, template_values))

I tried all of the following in my class, but they all end in failure. I tried them with key, key.name, and key.id in the URL:

photos = db.Query(Photo).filter('key', slug).fetch(limit=1)

photos = Photo.get_by_key_name(id)

photos = Photo.get_by_key_name(key)

key = db.Key.from_path('Photo', id) 

photos = db.GqlQuery("SELECT * FROM Photo WHERE __key__ = :key", key=key)

photos = db.get(photo_key)

photos = self.request.get("id")

My URL's:

application = webapp.WSGIApplication([
    ('/b/', HomePage),
    ('/b/upload', UploadPage),
    ('/b/add', MainPage),
    ('/b/img', Image),
    ('/b/img/([-\w]+)', ViewPage),
    ('/b/submit', Submission)
], debug=True)

The Template Query:

{% for photo in photos %}
<img alt="" title="" src="img?img_id={{ photo.key }}" alt="main image" />
{% endfor %}

This seems like it would be something incredibly simple and I know I'm missing something, but I'm just not sure where it's at. I would write this in PHP, but I like the concept of AppEngine and I've said above, it's a good Python learning experience.

As a side note, this application does work on the homepage of the site. I simply have a GQL query and it outputs the images fine, it just fails when I try to go to the /img/id pages.

Any advice guys (and gals)? Thanks in advance!

UPDATE #1:
As per Jonathan's request, the following is the Image class:

class Image (webapp.RequestHandler):
    def get(self):
        photo = db.get(self.request.get("img_id"))
        if photo.avatar:
            self.response.headers['Content-Type'] = "image/png"
            self.response.out.write(photo.avatar)
        else:
            self.response.out.write("No image")

Also, after posting this, I realized that this was part of the problem as I was trying to do /img as the actual image and /img/ to display the view page. I've since changed this and now have a working model. But it's based upon the Key and not key.id:

URL:

('/b/i', ViewPage)

New ViewPage Class:

class ViewPage(webapp.RequestHandler):
    def get(self):
    image = db.get(self.request.get("id")) 

    template_values = {
     'image': image,
    }

    path = os.path.join(os.path.dirname(__file__), 'templates/view.html')
    self.response.out.write(template.render(path, template_values))

So... to get to the View page (which includes comments and such), you now have to go to the following URL: /b/i?img_id={{ image.key }}

Atleast the page is working now, but I would much prefer to get the page to look like the following as stated above: /b/img/{{ image.key.id }}

Update #2: ViewPage class updated as well as URL's:

class ViewPageV2(webapp.RequestHandler):
    def get(self, id):
    images = [ db.get(id) ]

    template_values = {
     'image': image,
    }

    path = os.path.join(os.path.dirname(__file__), 'templates/view.html')
    self.response.out.write(template.render(path, template_values))

New URL: ('/b/image/([-\w]+)', ViewPageV2),

The following are two screenshots with one being proof of id "1" existing and the error that is coming with it currently.

alt text

alt text

Again, Thanks All!

+3  A: 

A simple way to grab them all:

photos = Photo.gql('ORDER BY __key__')

For more, see Queries on Keys in the App Engine docs.

Are you storing your photos with predefined keys?

photo = Photo(key_name="xzy123")
photo.put()

Then you can retrieve it in your ViewPage:

photos = [ Photo(key_name="%s" % id) ]

See Getting an Entity Using a Key.

Finally, to retrieve a photo based on its appengine-assigned key and assuming this key is present in the URL (e.g., http://host/b/img/ahByY..., so change your template to generate URLs of this form), use

class ViewPage(webapp.RequestHandler):
  def get(self, id):
    photos = [ db.get(id) ]
    ...
Greg Bacon
gbacon, thanks for the response! Right now, on the homepage I'm querying all of the content via the following:query_str = "SELECT * FROM Photo ORDER BY date DESC LIMIT 10"photos = db.GqlQuery (query_str)It's the subpages where I want people to be able to comment on a picture that I've having the issues with. To answer your question though, I am not using any predefined keys, simple letting Google assign a Key as information is inserted into the database.I will admit that I'm incredibly use to MySQL and the Datastore on AppEngine has some quirks I'm not quite use to yet.
Oubipaws
I've updated my answer to cover your design.
Greg Bacon
Yeah, according to the documentation, the signature for the `get` function is `get(*args)` and regular expression captures are passed in here. To get all records, wouldn't you just do `photos = Photo.all().order('-date').fetch(1000)`?
Bob Aman
Also, don't forget to set the parent of any comments to the image: http://code.google.com/appengine/docs/python/datastore/keysandentitygroups.html#Entity_Groups_Ancestors_and_Paths
Bob Aman
Thanks again guys for all of your help! gbacon, I've changed the code to match as you've stated and I get the following error: 'Invalid string key %s. Details: %s' % (encoded, e))BadKeyError: Invalid string key 1===. Details: Incorrect padding
Oubipaws
Not sure where `1===` is coming from. Inspect the Photos in your datastore in the SDK console. Click one of the Photos, copy its key to the end of `http://localhost:PORT/b/img/` and visiting the resulting URL (make sure PORT is the port for your app) should should show your image if the single to change to your `ViewPage` from the end of my answer is wired to `/b/img/([-\w]+)`.
Greg Bacon
Gbacon, thanks for your continued help with this problem! I've updated my initial post with the current code after your suggestions as well as screenshots of the error and item in my datastore.
Oubipaws
As written, you can get your image at `.../b/image/aglvbWd3ZWJhcHByCwsSBVBob3RvGAEM` — assuming no transcription errors on my part!
Greg Bacon
I was trying to do it with the ID, not the key! Thanks, it appears to be working perfect now! Thanks again for all of the help!
Oubipaws
You're welcome. I'm glad it helped!
Greg Bacon