Now that we understand Handlers we’re going to create one for Posts.
The Posts handler should have the following actions:
With what we’ve learned already you could write all of these actions yourself. Fortunately, the bulk of this functionality is already provided to you by Ferris via the Scaffold.
To demonstrate the full extent of what scaffolding can do, we’re going to enable Admin scaffolding for Posts using the EasyHandler class.
Create app/handlers/posts.py:
from ferris.core.easy_handler import EasyHandler, scaffold
@scaffold
class Posts(EasyHandler):
pass
Open http://localhost:8080/admin/posts in your browser. You’ll see that you have a complete interface for managing posts.
Let’s walk through what we did:
There’s a lot of magic going on here, but all EasyHandler does is save you the trouble of writing this:
@scaffold
class Posts(Handler):
prefixes = ['admin']
@scaffold
def admin_list(self):
pass
@scaffold
def admin_view(self, id):
pass
...
Let’s walk through what EasyHandler does for us:
Let’s take a moment to explore the features that the admin scaffold provides us. Open http://localhost:8080/admin/posts again and click ‘Add’ on the left navigation.
Here we see that a form has been automatically generated for the two fields in our Post model. Recall that we made the title property required. If we try to submit this form without putting anything in the title field, we’ll see that we get a nicely formatted error field.
Let’s go ahead and create an actual post with a title and content. Once we’ve submitted the form, we’ll be redirected to the list. Our new post has appeared.
On the right side of our new Post there are three buttons: view, edit, and delete. These map to the actions admin_view, admin_edit, and admin_delete.
Our requirements state that we need to have two different lists: one of everyone’s posts, and one of just our posts. This means that we need to build on top of the scaffold’s list action to conditionally add a filter.
First, create a few posts as one user and a few posts as another user using the Admin scaffold so that we have some data to test with.
Note
You can sign in as a different user via the url http://localhost:8080/_ah/login. You’ll want keep being an admin so you can add posts via the Admin scaffold.
If we open http://localhost:8080/posts we’ll see that EasyHandler has provided us with a scaffolded list action that lists everyone’s posts. However, they’re in the wrong order. We need to modify it to use the all_posts method from our Posts class.
First, let’s pull EasyHandler‘s scaffolded list action into our class so we can modify it. Add this to our Posts handler:
@scaffold
def list(self):
pass
This produces the same functionality that EasyHandler gives us by default. We need to do a couple of things to use our all_posts methods. First, we need to remove the scaffold decorator from the action to remove the scaffold behavior. Second, we need to call our method and set the posts template variable.
Modify our list action to this:
def list(self):
self.set(posts=self.Model.all_posts())
Notice that we’re still able to use the scaffold’s template; all we had to do was set the posts template variable and the scaffold knew what to display. You’ll also notice that the scaffold automatically determined that the Posts controller uses the Post model and provides that via self.Model.
With that in place all that’s left is to add the ability for list to show just our posts using the all_posts_by_user method. Modify the list method:
def list(self):
if 'mine' in self.request.params:
self.set(posts=self.Model.all_posts_by_user())
else:
self.set(posts=self.Model.all_posts())
Now if we open up http://localhost:8080/posts?mine it will show only the posts for the currently logged-in user.
As nice as the admin scaffold is, we don’t want to have to give every user admin rights to be able to add a new post. We can give all users that ability by adding a non-prefixed add action:
@scaffold
def add(self):
pass
We’ll just use the scaffold’s behavior since it is perfectly acceptable for this case. If we open up http://localhost:8080/posts/add we’ll see a form like the one in the admin scaffolding.
At this point users can add posts but they can’t edit any of the posts they’ve already created. Let’s add the edit using the scaffold like we did with add:
@scaffold
def edit(self, id):
pass
Notice that we needed to add the second parameter id to this action. id is needed for view, edit, and delete in order to determine the correct item to edit.
At this point we have a problem: a user can edit any post, even those created by other users. While this could be slightly amusing, this behavior is undesirable. We need to add a check to make sure the user is editing a post that they created:
def edit(self, id):
post = self.key_from_string(id).get()
if post.created_by != self.user:
return 401
return self.scaffold.edit(self, id)
Let’s walk through this:
Now users may not edit posts that they did not create. However, they are still allowed to edit one of their own posts without a problem.