One thing that's come up a lot in this class --a question I've seen a lot on the forums--
is how do I organize code.
You don't want to keep all your stuff in one Python file. What's the correct way to organize things.
The first thing I had to say is there is no correct answer.
Code organization--whether you're writing web apps or any other type of software--
is something that comes from experience and you can develop your own style.
When I'm building a web app, generally things start off in one file,
and in this file we probably have a section for handlers.
These are the classes that define what we do when a particular URL is hit.
Almost every framework I've worked in has this notion of a handler.
It also has this notion of a URL mapping.
This maps a URL to a particular handler.
We've dealt with this a lot in this lecture.
There is also some DB stuff, some objects, the models, the things we're actually working on--
blog posts, pieces of art from ASCII Chan, links and comments, and that sort of thing.
Then almost immediately I have separate files for static content--
things like CSS, JavaScript.
We haven't done any JavaScript in this class really.
Images I store separately. You could encode them into your file, but that doesn't make sense.
You just store them separately. Generally you serve them separately as well.
App Engine makes it easy to do that.
Another thing that's almost always separate from the beginning are templates.
I almost always separate templates from the beginning.
I didn't teach them from the beginning in this class because I didn't want to explain
HTML and new Python and also this new mini-language of templates all at the same time.
I've never actually taught templates directly in this class,
although most of you seem to be using them at this point.
You've found the documentation. People have talked about them in forums.
These are always separate.
As things grow, this file here is actually my main file.
It's actually often called main.py, at least for me.
The first thing I do is I pull out the DB models.
I generally have one file if it's required. We don't need this in App Engine.
Refer to it as the ORM.
I almost always write my own ORM. I don't really like the home-brewed ones.
ORM stands for oject-relational mapping.
This is a piece of code that basically maps your Python objects
to the relational database.
Often it'll have a little query language that compiles into SQL--that sort of thing.
We haven't had to deal with any of that in this class,
because the App Engine provides it to us.
The db.model thing we've been using to interact with the Google datastore--
that's basically an ORM.
The data model underlying it isn't strictly relational.
Effectively what it's doing is taking your Python objects and abstracting away
querying and cursoring and all of that stuff you have to do to get stuff in and out of the database.
I generally have a separate file for each type of data.
In our case, we've been talking about posts and art.
As our systems grow and you have more datatypes and users ,
I generally pull those apart into different files and have a bunch of class-specific
functions in each of these--password hashing and all that stuff would go in a users file.
Functions to get the top post and top arts would go in those separate files.
I kind of pull all of that out.
The next thing I almost always have is some sort of utils.
I usually have a utils file or utils module --a series of files in a directory--
that basically have all the random stuff --things like make
and make
Generally, I want to put as much into utils as I can--just a list of flat functions
that have no dependencies on any other part of the project.
The reason I do this is so that I can test these things.
These are often little helpful files that any piece of the project can manage.
I have a lot of date manipulation stuff in these files,
a lot of string manipulation, escaping stuff --all those sort of functions that I write
I usually put in a file. It usually starts out called utils.py.
It's really important that it's always a one-way inheritance.
Handlers can import from utils. Databases can import from utils.
Anything can import from utils, but utils never brings in other parts of the project.
That just kind of keeps things simple,
and if you think about it that way, you'll have this nice, clean file
with a bunch of handy functions.
If you look at Reddit's source code, there is maybe about 100 handy little functions
that we use all over the code. I usually throw that in one spot.
Then the final thing I do, and this usually takes more time as the project grows
is I take handlers out of main.py.
You might have separate files for each type of handler.
For the homeworks I may have a separate file for just the blog,
a separate file for ASCII Chan,
a separate file for those Unit 2 ones--the rot13 stuff,
and then main.py is basically the url mapping and then a bunch of imports.
Then these guys would import whatever database pieces they need.
It kind of keeps things separate.
Sometimes it's really hard to enforce this, and you can have what's called
a circular import where one file--rot13 may depend on some generic files
that are defined in main.py, which depends on the actual handlers in rot13 itself.
You get this kind of circular import.
Generally when you start having circular imports that means it's time to pull some
common piece of functionality out so the inheritance only goes one way.
For example, I have that generic handler --I think I've been calling it blog_handler
in my homework solutions--that just kind of has all that helpful stuff on it.
That would get pulled out into its own file so that main.py could import it, if it needs it at all.
The big groups of handlers can import from there as well.
This is basically how I organize things.
I'm going to draw a slight different picture of how the file system might look.
We'll leave it at that. Now, again, this may not apply to you, but this is what's worked for me.
Usually at my top level I have /main.py.
I probably have some sort of common file that's called like handlers.py
or something of that nature that basically has the generic handler--
things that happen on every single request.
Then I'll probably have a directory called /lib that might have some of the DB stuff,
which may have all of my models.
I may have utils.py and any of the specific stuff that we're doing.
Got that generic handlers.py.
It might have the other handler as the blog.py, the rot13.py--that sort of thing.
The bulk of the code is either in handlers.py or in each of these specific things.
These are the pieces that import from all the other parts of my projects.
That's generally kind of how I start. Things grow from there.
Of course, I have directories for templates and static. I'll keep things organized that way.
If we need subdirectories in either of this, I may add them.
But actually generally for me my templates directory is just a monster pile of templates.
Of course, as you get more advanced with templates, these can start inheriting from each other.
I almost always have something like a base.html.
Then most of my main templates will inherit from this.
There you go. I hope that helps. Many of you have been asking. Let's move onto the next piece.