The fourth part of the article, and probably not the last. Let me remind you that the previous three articles (as well as all subsequent ones) can now be seen at
this address - there are a lot of articles and I’m fed up with navigation links to each other ;-)
Let me remind you that we ended up with a review of the controller for
our example and a promise that everything will start in the next part, and, finally, everything will become interesting and exciting. It will become necessary. So -
Representation
As you know, words like MVC have long become not even fashionable, but directly implied (another question is that they understand them in their own way). Our example was no exception - and now we need to combine the achievements of the controller and the model together and show them to the user. This will help us a lot by the fact that GAE uses Django inside, the template mechanism of which is one of the best among those that I know. One of the most interesting, in my opinion, properties of Django templates is that they support inheritance.
')
Indeed, often the design of two functionally different pages of a website differs only slightly and uses common elements - header, footer, menu, etc. It will be a shame to duplicate this code - and at the same time, all sorts of include directives are, after all, yesterday. In Django, you can
inherit one pattern from another.
Consider our basic template, which can be found in the source tree as
templates / basic.html . Since the HTML on Habr doesn’t want to be nicely inserted (and no Habraredactor can handle it), and it’s ugly to read - you can break your head, you can see it in SVN using the link above. That's not the point. The bottom line is that in some places we declare "stubs":
<div id='content'> {% block content %} {% endblock %} </div>
<div id='content'> {% block content %} {% endblock %} </div>
<div id='content'> {% block content %} {% endblock %} </div>
The contents of these stubs are declared by the template that our basic.html inherits, for example, as shown in
please_login.html :
- {# $ Id: please_login.html 3 2010-01-25 12: 14: 40Z sigizmund $ #}
- {% extends "basic.html"%}
- {% block title%}
- HelloWorld! & mdash; a simple GAE application
- {% endblock%}
- {% block content%}
- Welcome to HelloWorld! & mdash; a simple application to illustrate some features of GAE. To continue, <a href=" subtus login_url }}"> please login </a> using your Google credentials.
- {% endblock%}
We will not consider the inheritance of patterns in Django - there are a lot of examples and it is easy to find them. Note only that
please_login.html defines two blocks — title and content; the first, respectively, is used in the title, and the second - in the body of the page.
Surely you noticed the design of the form:
- <a href=" sub account login_url }}"> ...
In principle, it is clear that there is a substitution of arguments in the pattern. Let's see how this happens:
- class StartPage:
- def __init __ (self, request):
- self.request = request
- def render (self, out):
- template_values ​​= {'login_url': users.create_login_url ("/ login")}
- path = os.path.join ('templates / please_login.html')
- out.write (template.render (path, template_values))
the beautiful code did not work again, because for some reason the highlighting in Habraredactor kills offsets, which, in the case of Python, agree, has some meaning
Actually, that's all the magic. We create the login URL as before, and simply pass it as a template parameter to the Janghi mechanism. The latter takes on all the tasks of resolving inheritance, combining many patterns together, block and value substitution, and we get a nice-looking page at the output:

In exactly the same way, we create a view for the logged in user page:
- {# $ Id: welcome.html 3 2010-01-25 12: 14: 40Z sigizmund $ #}
- {% extends "basic.html"%}
- {% block title%}
- Welcome page for {{username}}
- {% endblock%}
- {% block content%}
- Dear {{username}}! <br/> <br/>
- Welcome to HelloWorld! & mdash; a simple application to illustrate some features of GAE. Now you’re logged in, you can <a href='/stats'> view your stats </a>. Alternatively, you can <a href=" January al logout_url }}"> log out </a> and start all over again. <br/> <br/>
- {% endblock%}
and correspondingly,
- class WelcomePage:
- def __init __ (self, request):
- self.request = request
- self.user = users.get_current_user ()
- def render (self, out):
- template_values ​​= {
- 'username': self.user.nickname (),
- 'logout_url': users.create_logout_url ('/')
- }
- path = os.path.join ('templates / welcome.html')
- out.write (template.render (path, template_values))
At the output we get:

Nothing unpredictable. The only difference from the first example is where we create a logout url instead of login, and pass the username to “personalize” the greeting. I think if you read the post carefully, it will not be difficult for you to imagine what exactly should be in the template and presentation for the statistics page; you can check yourself, respectively, at the addresses
stats.html and
view.py.
Well then - it's time to take some results. The
GAE from the beginning series of articles already includes four parts, and we just touched upon the variety of Google AppEngine features. Then I’ll probably wait for comments from users and readers, with questions, suggestions, ideas - and after a couple of days, after a rest, I will write a couple more articles. What - it depends on you!
extracurricular reading
- As I already said, it’s worth starting with the official AppEngine QuickStart, and you will almost certainly be able to write something sensible after reading. If, by reading you understand that something is clearly not enough, then you need to look at ...
- ... official AppEngine documentation . It is really very well written and worth reading.
- Finally, you can read about the Django templates on the django website - I am sure that you will like it and you will not stop until you read all the documentation from cover to cover ;-)
Finally, if you have any questions, write here, there are obviously better specialists than me, and we will all try to answer you together.