├── core ├── images │ ├── .gitignore │ ├── form-input.png │ ├── form-radio.png │ ├── form-select.png │ ├── form-submit.png │ ├── hello-world.png │ ├── form-checkbox.png │ ├── form-dropdown.png │ ├── form-textarea.png │ ├── sample_web_form.png │ └── sample_web_form.html ├── README.md ├── js │ └── partypartyparty.js ├── hello-world.md ├── form-submission.md ├── html-css-js.md ├── setup.md ├── forms.md ├── files-templates.md └── data.md ├── extras ├── images │ └── .gitignore ├── README.md ├── heroku.md ├── learn-html-css.md ├── css.md ├── databases.md └── sessions.md ├── Gemfile ├── .gitignore ├── favicon.ico ├── images └── background.png ├── bootstrap ├── img │ ├── glyphicons-halflings.png │ └── glyphicons-halflings-white.png ├── css │ ├── bootstrap-responsive.min.css │ └── bootstrap-responsive.css └── js │ └── bootstrap.min.js ├── LICENCE ├── .gitattributes ├── Gemfile.lock ├── _layouts ├── default.html └── ots.html ├── css ├── zenburn.min.css └── styles.css ├── _config.yml ├── coach-guide.md ├── reference └── web-frameworks.md ├── README.md ├── index.md └── js └── highlight.min.js /core/images/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extras/images/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | gem 'jekyll' 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | _site/ 3 | *~ 4 | .ruby-version 5 | 6 | -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenTechSchool/python-flask/HEAD/favicon.ico -------------------------------------------------------------------------------- /images/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenTechSchool/python-flask/HEAD/images/background.png -------------------------------------------------------------------------------- /core/images/form-input.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenTechSchool/python-flask/HEAD/core/images/form-input.png -------------------------------------------------------------------------------- /core/images/form-radio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenTechSchool/python-flask/HEAD/core/images/form-radio.png -------------------------------------------------------------------------------- /core/images/form-select.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenTechSchool/python-flask/HEAD/core/images/form-select.png -------------------------------------------------------------------------------- /core/images/form-submit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenTechSchool/python-flask/HEAD/core/images/form-submit.png -------------------------------------------------------------------------------- /core/images/hello-world.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenTechSchool/python-flask/HEAD/core/images/hello-world.png -------------------------------------------------------------------------------- /core/images/form-checkbox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenTechSchool/python-flask/HEAD/core/images/form-checkbox.png -------------------------------------------------------------------------------- /core/images/form-dropdown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenTechSchool/python-flask/HEAD/core/images/form-dropdown.png -------------------------------------------------------------------------------- /core/images/form-textarea.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenTechSchool/python-flask/HEAD/core/images/form-textarea.png -------------------------------------------------------------------------------- /core/images/sample_web_form.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenTechSchool/python-flask/HEAD/core/images/sample_web_form.png -------------------------------------------------------------------------------- /bootstrap/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenTechSchool/python-flask/HEAD/bootstrap/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /bootstrap/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenTechSchool/python-flask/HEAD/bootstrap/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | This material is licensed under Creative Commons CC BY-SA 3.0. For more 2 | information, follow this link http://creativecommons.org/licenses/by-sa/3.0/ 3 | -------------------------------------------------------------------------------- /core/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: ots 3 | title: Core Content 4 | --- 5 | 6 | This directory is for core course content. Starting with setting up Git, creating a GitHub account and all that nice stuff. 7 | -------------------------------------------------------------------------------- /extras/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: ots 3 | title: Extra Content 4 | --- 5 | 6 | This directory is for extra content. Stuff that isn't part of the main course but can be done by students if they are extra interested in it. 7 | 8 | -------------------------------------------------------------------------------- /core/js/partypartyparty.js: -------------------------------------------------------------------------------- 1 | function partypartyparty() { 2 | var quotes = document.getElementsByClassName('fancyquote'); 3 | for(var i=0; i= 1.0.0) 7 | colorator (0.1) 8 | commander (4.1.5) 9 | highline (~> 1.6.11) 10 | fast-stemmer (1.0.2) 11 | ffi (1.9.3) 12 | highline (1.6.20) 13 | jekyll (1.4.3) 14 | classifier (~> 1.3) 15 | colorator (~> 0.1) 16 | commander (~> 4.1.3) 17 | liquid (~> 2.5.5) 18 | listen (~> 1.3) 19 | maruku (~> 0.7.0) 20 | pygments.rb (~> 0.5.0) 21 | redcarpet (~> 2.3.0) 22 | safe_yaml (~> 0.9.7) 23 | toml (~> 0.1.0) 24 | liquid (2.5.5) 25 | listen (1.3.1) 26 | rb-fsevent (>= 0.9.3) 27 | rb-inotify (>= 0.9) 28 | rb-kqueue (>= 0.2) 29 | maruku (0.7.1) 30 | parslet (1.5.0) 31 | blankslate (~> 2.0) 32 | posix-spawn (0.3.8) 33 | pygments.rb (0.5.4) 34 | posix-spawn (~> 0.3.6) 35 | yajl-ruby (~> 1.1.0) 36 | rb-fsevent (0.9.4) 37 | rb-inotify (0.9.3) 38 | ffi (>= 0.5.0) 39 | rb-kqueue (0.2.0) 40 | ffi (>= 0.5.0) 41 | redcarpet (2.3.0) 42 | safe_yaml (0.9.7) 43 | toml (0.1.0) 44 | parslet (~> 1.5.0) 45 | yajl-ruby (1.1.0) 46 | 47 | PLATFORMS 48 | ruby 49 | 50 | DEPENDENCIES 51 | jekyll 52 | -------------------------------------------------------------------------------- /_layouts/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Social Coding with OpenTechSchool 7 | 8 | 9 | 10 | 11 | 14 | 15 | 16 | 17 | 18 | 19 |
20 |

{{ page.title }}

21 |

22 |
23 | 24 |
25 | 28 |
29 | {{ content }} 30 |
31 | 35 |
36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /css/zenburn.min.css: -------------------------------------------------------------------------------- 1 | pre code{display:block;padding:.5em;background:#3f3f3f;color:#dcdcdc}pre .keyword,pre .tag,pre .css .class,pre .css .id,pre .lisp .title,pre .nginx .title,pre .request,pre .status,pre .clojure .attribute{color:#e3ceab}pre .django .template_tag,pre .django .variable,pre .django .filter .argument{color:#dcdcdc}pre .number,pre .date{color:#8cd0d3}pre .dos .envvar,pre .dos .stream,pre .variable,pre .apache .sqbracket{color:#efdcbc}pre .dos .flow,pre .diff .change,pre .python .exception,pre .python .built_in,pre .literal,pre .tex .special{color:#efefaf}pre .diff .chunk,pre .subst{color:#8f8f8f}pre .dos .keyword,pre .python .decorator,pre .title,pre .haskell .type,pre .diff .header,pre .ruby .class .parent,pre .apache .tag,pre .nginx .built_in,pre .tex .command,pre .prompt{color:#efef8f}pre .dos .winutils,pre .ruby .symbol,pre .ruby .symbol .string,pre .ruby .string{color:#dca3a3}pre .diff .deletion,pre .string,pre .tag .value,pre .preprocessor,pre .built_in,pre .sql .aggregate,pre .javadoc,pre .smalltalk .class,pre .smalltalk .localvars,pre .smalltalk .array,pre .css .rules .value,pre .attr_selector,pre .pseudo,pre .apache .cbracket,pre .tex .formula{color:#cc9393}pre .shebang,pre .diff .addition,pre .comment,pre .java .annotation,pre .template_comment,pre .pi,pre .doctype{color:#7f9f7f}pre .coffeescript .javascript,pre .javascript .xml,pre .tex .formula,pre .xml .javascript,pre .xml .vbscript,pre .xml .css,pre .xml .cdata{opacity:.5} -------------------------------------------------------------------------------- /core/images/sample_web_form.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 18 | 19 | 20 | 21 | 27 | 28 | 29 | 30 | 34 | 35 | 36 | 40 | 41 | 42 | 45 | 46 |
Pizza Shop 2.0
Name
Pizza Topping 14 | Supreme
15 | Vegetarian
16 | Hawaiian
17 |
Pizza Sauce
Optional Extras 31 | Extra Cheese 32 | Gluten Free Base 33 |
37 | Delivery Instructions:
38 | 39 |
43 | 44 |
47 |
48 | 49 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | permalinks: title 2 | baseurl: /python-flask 3 | title: Websites with Python Flask 4 | map: 5 | - title: Home 6 | path: / 7 | caption: Websites with Python Flask 8 | - title: Core 9 | caption: The 'mandatory' workshop content 10 | subpages: 11 | - title: Setting up 12 | path: /core/setup.html 13 | caption: Installation instructions for Windows, OSX and Linux. 14 | - title: Hello, World! 15 | path: /core/hello-world.html 16 | caption: Serving our first web page. 17 | - title: Languages of the Web 18 | path: /core/html-css-js.html 19 | caption: What the web is built on 20 | - title: Files & Templates 21 | path: /core/files-templates.html 22 | caption: How to serve different all the files 23 | - title: Forms 24 | path: /core/forms.html 25 | caption: How forms work on the web. 26 | - title: Form Submission 27 | path: /core/form-submission.html 28 | caption: Receiving and processing the form. 29 | - title: Data Structures 30 | path: /core/data.html 31 | caption: The basics of organising data in Python. 32 | - title: Extras 33 | caption: Additional workshop content 34 | subpages: 35 | - title: Learning HTML and CSS 36 | path: /extras/learn-html-css.html 37 | caption: 38 | - title: Professional CSS 39 | path: /extras/css.html 40 | caption: 41 | - title: Keeping track of users 42 | path: /extras/sessions.html 43 | caption: Using flask sessions 44 | - title: Using a database 45 | path: /extras/databases.html 46 | caption: 47 | - title: Hosting on Heroku 48 | path: /extras/heroku.html 49 | caption: Host your website for free online using Heroku. 50 | -------------------------------------------------------------------------------- /css/styles.css: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | /* keep the above dashes for jekyll to preprocess this file */ 4 | body { 5 | background: url("{{site.baseurl}}/images/background.png") #FFF repeat fixed; 6 | font-family: "Open Sans", Helvetica, sans-serif; 7 | line-height: 1.6; 8 | } 9 | 10 | h1, h2, h3, h4, h5, h6 { 11 | font-family: "Montserrat", "Helvetica Neue", Arial, Helvetica, sans-serif; 12 | margin: 1em 0 .5em 0; 13 | } 14 | 15 | .sidebar-nav { 16 | margin-top: 2.25em; 17 | } 18 | 19 | code { 20 | font-family: Monaco, Menlo, Consolas, "DejaVu Sans Mono", Inconsolata, 21 | "Courier New", monospace; 22 | } 23 | 24 | pre { 25 | border: none; 26 | background: none; 27 | } 28 | 29 | pre code { 30 | font-size: 15px; 31 | background: #222222 !important; 32 | } 33 | 34 | .navbar h1 a, .navbar h1 { 35 | color: #f5f5f5; 36 | font-size: 18px; 37 | line-height: 20px; 38 | text-align: center; 39 | text-decoration: none; 40 | } 41 | 42 | .navbar h1 a:hover { 43 | color: #fff; 44 | } 45 | 46 | .navbar-static-top { 47 | z-index: 1000; 48 | position: relative; 49 | } 50 | 51 | .navbar-inner { 52 | background: #085987 !important; 53 | border-color: #085987 !important; 54 | } 55 | 56 | .title { 57 | text-align: center; 58 | margin-bottom: 30px; 59 | margin-top: 30px; 60 | } 61 | 62 | .container-fluid { 63 | max-width: 1200px; 64 | margin: auto; 65 | } 66 | 67 | #main-content { 68 | background: rgb(255, 255, 255); 69 | background: rgba(255, 255, 255, 0.5); 70 | -webkit-box-shadow: 0px 0px 50px 20px rgba(255, 255, 255, 0.5); 71 | -moz-box-shadow: 0px 0px 50px 20px rgba(255, 255, 255, 0.5); 72 | box-shadow: 0px 0px 50px 20px rgba(255, 255, 255, 0.5); 73 | } 74 | 75 | #main-content p, #main-content li { 76 | font-size: 15px; 77 | } 78 | 79 | #footer { 80 | text-align: center; 81 | background-color: #085987; 82 | clear: both; 83 | margin-top: 6em; 84 | padding: 1em 0; 85 | width: 100%; 86 | color: #FFF; 87 | } 88 | 89 | #footer a { 90 | color: #c1d5e1; 91 | } 92 | 93 | #footer a:hover { 94 | color: #FFF; 95 | } 96 | 97 | -------------------------------------------------------------------------------- /_layouts/ots.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | OpenTechSchool – {{ page.title }} 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 26 | 27 |
28 | 29 |
30 |

{{ page.title }}

31 |
32 |
33 | 34 |
35 | 36 | 52 | 53 |
54 | {{ content }} 55 |
56 | 57 |
58 | 59 |
60 | 61 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /coach-guide.md: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | layout: ots 4 | title: Coach Guide 5 | 6 | --- 7 | 8 | Thanks for coaching! Check out the generic [OpenTechSchool coaching guide](http://opentechschool.github.com/slides/presentations/coaching/) as well! 9 | 10 | ## Python 11 | 12 | We are recommending Python 3.3 for this workshop, though they can use Python 2.7 if they wish. Python 3 versions older than 3.3 are not supported by Flask. 13 | 14 | With Python installed, we then recommend using [distribute](http://pythonhosted.org/distribute/)'s `easy_install` to install [pip](https://pypi.python.org/pypi/pip), then using pip to install [virtualenv](https://pypi.python.org/pypi/virtualenv). 15 | 16 | Then with virtualenv they can create an isolated installation of Python inside their working directory for the workshop. Once they have run the virtualenv activate script then when they run `pip install flask` it will install Flask to their working directory instead of the system Python. 17 | 18 | ## Flask 19 | 20 | This workshop is concerned with building a simple website with Python Flask. There are two parts: 21 | 22 | * A home page containing a form for submitting an email address. 23 | * A page for listing the submitted emails. 24 | 25 | A Flask app is just a single Python file with a function for each URL in the web app. It has a simple template system and we just use an in-memory list to store the email addresses. 26 | 27 | See it running on Heroku: Here is the [home page](http://python-flask-code.herokuapp.com/) where people can enter their email address and the [emails page](http://python-flask-code.herokuapp.com/emails.html) where you can view the list of submitted emails. 28 | 29 | You can see the source code for the final example [here](https://github.com/OpenTechSchool/python-flask-code/tree/master/core/data). 30 | 31 | Finally, the [Flask Documentation](http://flask.pocoo.org/docs/) is quite comprehensive and covers a lot of topics about building a website. The reason we chose Flask (over Bottle et al) is that the documentation is very good. So we encourage you to send people there! 32 | 33 | ## HTML/CSS/Javascript 34 | 35 | Participants will likely have questions about HTML and CSS. We have some links in the extras section for learning more which you can direct them to. There is also the 'Professional CSS' section if they are interested in hardcore stuff like Twitter Bootstrap, SASS and LESS. 36 | 37 | For this workshop the focus is on what the website can _do_, not what the website looks like. So perhaps try to ask people what things they want their sites to do rather than how they look. 38 | 39 | ## Help with Windows 40 | 41 | Windows can be a little annoying to set up. Because people will probably end up with multiple installations of Python I wouldn't recommend setting up PATH. Instead, just use the full path to `python.exe` and scripts. It only needs to be done to get virtualenv. Once they have activated a virtualenv environment then they will not need to use full paths. 42 | -------------------------------------------------------------------------------- /core/hello-world.md: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | layout: ots 4 | title: Hello World 5 | 6 | --- 7 | 8 | Now that we have Python and Flask installed it's time to start with our first website. But first it helps to know a little about how your web browser retrieves web pages from a web server. 9 | 10 | # HTTP 11 | 12 | The HyperText Transfer Protocol is what your browser speaks to talk to a web server. In HTTP, the browser will make a _request_ and the server sends back a _response_. 13 | 14 | There are two main types of request, `GET` and `POST`. 15 | 16 | * The browser sends a `GET` request to retrieve data. For example, going to `http://www.opentechschool.org/team.html` will cause the browser to send `GET /team.html` to OpenTechSchool's server. 17 | * The `POST` request is used to send data. For example if you fill out a web form and click _Submit_ it will usually send the form data back to the server through a POST. 18 | 19 | We will be handling both GET and POST requests today in our app! First we'll handle a GET request with the Hello World example. Then in a later chapter we will try using POSTs to receive an email address. 20 | 21 | # Hello World - A Static Website 22 | 23 | In the early days people would write HTML files in a directory being watched by an Apache server. It was simple, but limiting. The content was _static_, with no way to make it change without editing the files on the server. Today we are going to start with something just as simple. This is the [Quickstart example](http://flask.pocoo.org/docs/quickstart/) from the Flask documentation. 24 | 25 | Open a new file called `catseverywhere.py` in your workshop directory. This might look a little cryptic: 26 | 27 | from flask import Flask 28 | app = Flask(__name__) 29 | 30 | @app.route('/') 31 | def hello_world(): 32 | return 'Hello World!' 33 | 34 | if __name__ == '__main__': 35 | app.run() 36 | 37 | Let's type it into our new file, and break it down a little: 38 | 39 | from flask import Flask 40 | app = Flask(__name__) 41 | 42 | This imports the Flask library and creates a new website in a variable called `app`. 43 | 44 | @app.route('/') 45 | def hello_world(): 46 | return 'Hello World!' 47 | 48 | The `@` is new, it's called a [_decorator_](http://en.wikipedia.org/wiki/Python_syntax_and_semantics#Decorators) and it is used to 'augment' function definitions. Flask uses `route()` to say that if the browser requests the address `/` (the default, or home address), then our app should _route_ that request to this `hello_world` function. 49 | 50 | The function itself returns the string "Hello World!". This will be sent to the web browser. 51 | 52 | if __name__ == '__main__': 53 | app.run() 54 | 55 | This is Python for "if this script is run directly then start the application". 56 | 57 | Now you can start running your first website! In your terminal: 58 | 59 | $ python catseverywhere.py 60 | * Running on http://127.0.0.1:5000/ 61 | 62 | Open that address in your browser! It probably looks something like this: 63 | 64 | ![](images/hello-world.png) 65 | 66 | Hmmm, looks a little basic. In the next section we will look at making it a little better looking. 67 | -------------------------------------------------------------------------------- /core/form-submission.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: ots 3 | title: Form Submission 4 | --- 5 | 6 | Rumours of _Cats Everywhere_ have sent the web into a frenzy. Now is the time to move our dusty old static landing page into an exciting and invigorating sign-up page! 7 | 8 | To do this we will need two things: 9 | * A HTML form on the web page. This will have a text input field and a submit button. 10 | * A _route_ in our Flask app to accept the data posted by the form. 11 | 12 | At the moment we will just print out the email addresses that we receive directly to the console. 13 | 14 | # HTML Form 15 | 16 | The form is simple enough: 17 | 18 |
19 | 20 | 21 |
22 | 23 | **Place this form** inside the `` section of `index.html`. You can fiddle around a bit to get it in the place you want. 24 | 25 | # Python route 26 | 27 | Now the action attribute of the form is saying it will be posted to `/signup`. We don't have any code for this URL at the moment, so it is time to make some! 28 | 29 | We are going to need to import more objects from Flask. We need `request` to get the form data, `redirect` to redirect the browser once we are done. **Integrate this to the top of your Python code**: 30 | 31 | from flask import request, redirect 32 | 33 | Now we can add our **new route** for `/signup`. 34 | 35 | @app.route('/signup', methods = ['POST']) 36 | def signup(): 37 | email = request.form['email'] 38 | print("The email address is '" + email + "'") 39 | return redirect('/') 40 | 41 | This gets a little complicated, so we'll go through it line-by-line: 42 | 43 | @app.route('/signup', methods = ['POST']) 44 | 45 | We apply a _decorator_ to the signup function, saying that we want it to be used when the browser requests `/signup`. It will accept the HTTP _POST_ method, which you can see is mentioned in the HTML form element as `method="post"`. 46 | 47 | def signup(): 48 | email = request.form['email'] 49 | print("The email address is '" + email + "'") 50 | 51 | In the signup method we can retrieve the email address using the `request` object, which contains the form data. In the HTML we used `name="email"`, which means that in the `request` object we can use `request.form["email"]`. If we used `name="address"` in the HTML then it would be `request.form["address"]`. 52 | 53 | When we write `request.form["email"]` we are using `request.form` as a Python Dictionary, looking up the entry held in there for `"email"`. Dictionaries are a type of data structure we haven't seen before, we'll talk about them more in the Data Structures chapter. 54 | 55 | At this stage We just print out the email address that's supplied. So when you submit the form you should be able to see the address you supplied printed out on the console. 56 | 57 | return redirect('/') 58 | 59 | Once we have printed the email address we still need a response to send back to the web browser. A common option is to send a HTTP _Redirect_ response. This tells the browser to go to another page. In our case we just send them back to the home page, `/`, which is served by the `hello_world()` function. 60 | 61 | # Try it out! 62 | 63 | Give it a whirl and see how the email addresses get printed to the console. Perhaps you would like to experiment by adding some extra form elements such as a text box for a name, or a checkbox for also including dogs. 64 | -------------------------------------------------------------------------------- /extras/learn-html-css.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: ots 3 | title: Learning HTML and CSS 4 | --- 5 | 6 | Let's face it: our homepage is not _that_ spectacular. A picture of a cat, some text shadow and a custom font isn't exactly ground-breaking. If you are looking to develop your web skills and have a bit of an eye for design, here is a guide for getting you started. 7 | 8 | The first thing to know is that web design is all about experimentation. It's a _do stuff_ sort of place. It might be tempting to pull out a pen and paper every time you want to design a new page, and many people start out that way. But it can be a very frustrating experience. HTML and CSS can be incredibly inflexible one way, and also completely open in another. For example, you can do anything you like with squares, any `
` tag is basically a rectangle, but how do you make triangles? If you doodled a nice pretty triangular design you might be in for a bit of a shock when it came time to create the HTML. 9 | 10 | So it's time to play around, and you know what? It's a _great_ time to play around. There are more web gurus than ever and a ton of good resources available for free online. 11 | 12 | ## Online Playgrounds 13 | 14 | Messing around with HTML/CSS and Javascript can be annoying on your local computer. You need at least an editor and a web server, then you are constantly going through the edit-save-reload cycle. After a while you can get used to it, but there are some good online services that let you hack away for free. 15 | 16 | * [CSSDeck](http://cssdeck.com/) is simple and effective and includes lots of more complicated examples. Check out the _Cats Everywhere_ home page [here](http://cssdeck.com/labs/aqzfyeyn). 17 | * [Codepen](http://codepen.io/) is a bit fancier, with paid-for plans for people wanting some extra features. ([cats Everywhere home page](http://codepen.io/anon/pen/xcteG)) 18 | * [JsFiddle](http://jsfiddle.net/) is one of the older sites and has more of a focus on JavaScript. Check out the [home page](http://jsfiddle.net/TcJc8/). 19 | 20 | ## Browser Tools 21 | 22 | One of the most frustrating parts of web development is debugging when something goes wrong. There has been a lot of work done in this area, and the major browsers now have good tools for debugging web pages directly in the browser. 23 | 24 | * Google Chrome comes with [Developer Tools](https://developers.google.com/chrome-developer-tools/) 25 | * Firefox has the [Firebug](https://addons.mozilla.org/en-US/firefox/addon/firebug/) add-on. 26 | 27 | Learning just the basics can save you hours and hours of painful debugging. 28 | 29 | ## References 30 | 31 | I always find it best to have a good solid reference by my side. Sometimes I just can't remember whether it is `text-align: center;` or `text-align: middle;` and spend half an hour wondering why it doesn't work. Here are some of the more popular online references: 32 | 33 | * HTML Dog has [HTML](http://www.htmldog.com/reference/htmltags/) and [CSS](http://www.htmldog.com/reference/cssproperties/) that are clean and straight-forward. 34 | * Mozilla provide [HTML Element](https://developer.mozilla.org/en-US/docs/HTML/Element) and [HTML Attribute](https://developer.mozilla.org/en-US/docs/HTML/Attributes) references. These are much more complete than HTML Dog and include links to relevant specifications and browser compatibility. 35 | 36 | ## Tutorials 37 | 38 | If you are looking for something a little more guided introduction to HTML/CSS and JavaScript then we have collected links to a whole pile of tutorials for you. All these can be completed online for free: 39 | 40 | * [HTML Dog](http://www.htmldog.com/) does raw beginner HTML and CSS with a slight canine focus. 41 | * [Mozilla Developer CSS Tutorial](https://developer.mozilla.org/en-US/docs/CSS/Getting_Started) is a "from scratch" CSS tutorial. It will take you all the way from basic syntax to the box model and layouts. 42 | * [Dive into HTML5](http://fortuito.us/diveintohtml5/) covers a lot of the nifty new features introduced in HTML5, which is available to most contemporary browsers and phones. 43 | * [Mozilla Learn](https://developer.mozilla.org/en-US/learn) contains whole bunch of links to Mozilla and third-party content. 44 | -------------------------------------------------------------------------------- /extras/css.md: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | layout: ots 4 | title: Professional CSS 5 | 6 | --- 7 | 8 | Once you are comfortable with CSS rules and properties you might start to wonder how the professionals use it. There is actually a big difference between learning CSS and using it. When learning you usually just put some CSS rules into a single file and leave it at that. But a real website might have many hundreds of rules combined with some strict design requirements and a need for cross-browser compatibility. Combine that with having to be understood and kept up-to-date by a team of developers and you have got yourself quite a challenge. 9 | 10 | ## CSS Frameworks 11 | 12 | CSS Frameworks make it easier to manage styles for these larger, more complicated websites. All usually have the same key features: 13 | 14 | **Style reset**. Internet Explorer's `

` tag might not look the same as Google Chrome's `

` tag. Frameworks start their CSS with a bunch of directives redefining most HTML tags to a common styling. 15 | 16 | **Grid Layout**. You may be wondering how we get websites with multiple columns and nice box layouts. Traditionally it was all done with manual `
` styling. But now frameworks define a grid layout, usually with something like 12 columns per row. 17 | 18 | Here is an example of a two-column layout: 19 | 20 |
21 |
Left sidebar
22 |
Main content
23 |
24 | 25 | **Typographical reset**. This is a font reset that looks a little more pleasing to the eye. It sets things like line spacing and font size. 26 | 27 | **Form styles**. Because the default form buttons and input boxes look boring these days. 28 | **Extra components**. Many frameworks provide things like a menu bar system that can turn a `
    ` tag into a pretty menu, or styled boxes for showing `` tags in. 29 | 30 | Learning a framework is similar to learning something like Flask. It can be a lot of work to get started, but over time it enables you to do things a lot quicker and still keep a decent amount of control. Things like a properly maintained grid system can save days of headaches with cross-browser compatibility. 31 | 32 | Here are some of the more popular frameworks used today: 33 | 34 | * [Twitter Bootstrap](http://twitter.github.com/bootstrap/) is one of the most popular. In some ways it has redefined what a standard web page looks like. 35 | * [Foundation](http://foundation.zurb.com/) is a good, fully featured alternative that works great with SASS css. 36 | * [Blueprint](http://www.blueprintcss.org/) is a bit older but very mature. 37 | * [YUI](http://yuilibrary.com/) comes from the Yahoo team. It's very comprehensive and covers a lot of JavaScript as well. You might like to play with the [grid builder](http://yui.github.com/gridbuilder/). 38 | 39 | Finally, there is a great compilation website comparing some of the most popular frameworks [here](http://usablica.github.com/front-end-frameworks/compare.html)! 40 | 41 | ## CSS Languages 42 | 43 | There are in fact a few entire languages that are dedicated to CSS. These languages are more powerful than CSS, often allowing things like variables and templates, but are compiled down to regular CSS files for hosting. 44 | 45 | A common problem is how to deal with colours. For example if you had a corporate colour scheme of `#3311FF` your CSS would be littered with `#3311FF` references: 46 | 47 | .nav { background-color: #3311FF; } 48 | .button { border-color: #3311FF; } 49 | .cake .icing { color: #3311FF; } 50 | 51 | In a CSS language you would be able to use a variable instead: 52 | 53 | $corporate_color: #3311FF; 54 | .nav { background-color: $corporate_color; } 55 | .button { border-color: $corporate_color; } 56 | .cake .icing { color: $corporate_color; } 57 | 58 | And if you later decided that the colour needed to be #3311EE instead, there would only be one place you needed to change it! Use of a CSS language is very common in large websites these days. Here are some of the more popular ones in use today: 59 | 60 | * [SASS](http://sass-lang.com/) is one of the original CSS languages. It uses the Ruby programming language under the hood. You might like to try the [Python](https://pypi.python.org/pypi/pyScss/1.1.5) port which is compatible with SASS 3.2. You can also take a look at [Compass](http://compass-style.org/) which pushes SASS even further. 61 | * [LESS](http://lesscss.org/) has a very similar philosophy. It is written in JavaScript, so it can either be run in the browser or, using Node, on the server. 62 | -------------------------------------------------------------------------------- /extras/databases.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: ots 3 | title: Databases 4 | --- 5 | 6 | There is a reason why we haven't used a more permanent method for storing our email addresses, and that's because _databases are complicated_. Seriously. 7 | 8 | But fortunately they are not that difficult once you get the hang of it. Since the 1970s many databases have standardised on using the **SQL** language. It defines how to store and search data in _tables_, which contain _columns_, and rows of data usually referred to as _records_. If you learn SQL then you can use quite a lot of different databases. 9 | 10 | Because of their size and complexity databases are generally written as their own separate servers that run in addition to your web server. That comes with additional work that we probably don't need at this moment. For now we'll use [SQLite](http://www.sqlite.org/) which is a simple and very widely used database engine that just happens to come bundled in Python. 11 | 12 | ## Creating the database 13 | 14 | Since Python 2.5 the SQLite library has shipped in the standard distribution. This means it should be available already. You can import the `sqlite3` library in a Python shell to see if it works: 15 | 16 | >>> import sqlite3 17 | 18 | We are going to start by creating a database in a file called `emails.db`. It will have one table called `email_addresses` which will keep all our emails. Make sure your Python shell started in the same directory as your website code. 19 | 20 | >>> conn = sqlite3.connect("emails.db") 21 | >>> cursor = conn.cursor() 22 | >>> cursor.execute("CREATE TABLE email_addresses ( email TEXT );") 23 | 24 | 25 | Here you can see we connected to `emails.db` (this file didn't exist, so SQLite created it). We opened a _cursor_, which is what allows us to send commands, and executed a _CREATE TABLE_ statement to create the email addresses table. It has one column, _email_, which can just be a string of text. 26 | 27 | ## Using SQLite in Flask 28 | 29 | The Flask documentation has a [section](http://flask.pocoo.org/docs/patterns/sqlite3/) on using SQLite which we will use here. It recommends that we store the database connection in a global variable, and open/close the connection before and after every request. 30 | 31 | We'll need to import the `g` object from Flask, as well as `sqlite3`: 32 | 33 | from flask import g 34 | import sqlite3 35 | 36 | Now we use `@app.before_request` to run a function before every request from the browser: 37 | 38 | @app.before_request 39 | def before_request(): 40 | g.db = sqlite3.connect("emails.db") 41 | 42 | Likewise we use `@app.teardown_request` to close the database connection after every request. 43 | 44 | @app.teardown_request 45 | def teardown_request(exception): 46 | if hasattr(g, 'db'): 47 | g.db.close() 48 | 49 | ## Adding a new email address 50 | 51 | Now that we have everything installed and set up we can just use an SQL _INSERT_ statement to add new email addresses to the table. 52 | 53 | @app.route('/signup', methods = ['POST']) 54 | def signup(): 55 | email = request.form['email'] 56 | g.db.execute("INSERT INTO email_addresses VALUES (?)", [email]) 57 | g.db.commit() 58 | return redirect('/') 59 | 60 | Notice that we use `g.db.commit()`. If you don't use `commit()` then it won't save the email address! 61 | 62 | ## Listing email addresses 63 | 64 | Now that we have all our emails stored in a database we have to use a _SELECT_ statement to get them all back. Let's update the `emails()` function to use the database: 65 | 66 | @app.route('/emails.html') 67 | def emails(): 68 | email_addresses = g.db.execute("SELECT email FROM email_addresses").fetchall() 69 | return render_template('emails.html', email_addresses=email_addresses) 70 | 71 | You might notice that the list of emails now looks a little strange on the web page. This is because the `g.db.execute()` statement returns an entire tuple for _every_ email address. In the Python console it looks like this: 72 | 73 | >>> db.execute('select * from email_addresses').fetchall() 74 | [(u'eroaskdlg',), (u'kjzdfhks',), (u'lksrlajkr',)] 75 | 76 | So every item in the list is actually a tuple (a non-modifiable list). The email itself is at position 0 in each tuple. So update the emails template to print just the first element: 77 | 78 | {% raw %} 79 | 80 |
      81 | {% for email in email_addresses %} 82 |
    • {{ email[0] }}
    • 83 | {% endfor %} 84 |
    85 | 86 | {% endraw %} 87 | 88 | And that's it! You can now restart the web server as many times as you like, and your list of emails will remain! All the emails are now stored directly in the database. 89 | 90 | ## Further Reading 91 | 92 | * [Learn SQL the Hard Way](http://sql.learncodethehardway.org/) is currently in alpha, but many have enjoyed other books in the series. 93 | * [Python sqlite documentation](http://docs.python.org/2/library/sqlite3.html) describes the Python API for SQLite. 94 | * SQLite has [SQL Syntax](http://www.sqlite.org/lang.html) and [Data types](http://www.sqlite.org/datatype3.html) references. 95 | -------------------------------------------------------------------------------- /reference/web-frameworks.md: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | layout: ots 4 | title: Web Frameworks 5 | 6 | --- 7 | 8 | Python Flask is only one of a wide variety for website platforms. We've listed some of the most popular ones below for most of the major programming languages. 9 | 10 | ## Python 11 | 12 | Python is a very popular language with a long history of web development. 13 | 14 | * [Django](https://www.djangoproject.com/) is the predominant web framework for Python. It is a very large framework, handling many factors common to major websites. Well suited to people investing a large amount of time into full-featured websites. 15 | * [web2py](http://www.web2py.com/) is a very, very comprehensive framework. It comes with it's own web-based editor and administrative interface, so it can be good for creating big websites when you aren't so comfortable with raw code and command lines. It currently supports Python 2. 16 | * [Bottle](http://bottlepy.org/docs/dev/) is a popular micro-framework, almost identical to Flask. Unlike Flask it has native Python 3 support, but documentation is not quite as complete. 17 | * [Flask](http://flask.pocoo.org/) is the micro-framework used in the workshop today. At this moment it does not officially support Python 3. 18 | 19 | ## Ruby 20 | 21 | Similar to Python in many ways, Ruby is also a scripting language with cross-platform support and a popular choice for web development. 22 | 23 | * [Ruby on Rails](http://rubyonrails.org/) is the main Ruby web framework. Like Django it is a large framework with a great number of features. It is one of the most popular web frameworks in computing today. Suited to people spending a lot of time writing websites. 24 | * [Sinatra](http://www.sinatrarb.com/) is a very popular micro-framework, very similar to Flask. The Ruby language is even more flexible than Python, so the code can look very clean. 25 | 26 | ## PHP 27 | 28 | PHP is unique in being the only language created just to make web pages. Originally it was more like a template language, like how we used a for loop inside HTML during the workshop. But over time it has developed some very sophisticated frameworks. 29 | 30 | * [CakePHP](http://cakephp.org/) provides the basics of a web framework and is very popular. 31 | * [Symfony](http://symfony.com/) is another PHP web framework with a long history and a strong following. 32 | 33 | ## Java 34 | 35 | Java is still one of the most popular languages for websites. It's history as an "enterprise platform" though has made it not very popular amongst enthusiasts. That said, it is still a good option for services that require high performance. 36 | 37 | * [Spring Web MVC](http://www.springsource.org/spring-framework) is part of the Spring Framework and the most popular of the Java web frameworks. Compared to Ruby and Python frameworks it requires more configuration, but there are sample applications included that can help get you started. Historically it predates all the other frameworks here, but though there may be a few rough edges it has stood the test of time. 38 | 39 | ## Groovy 40 | 41 | The Groovy programming language is an attempt to make a Python/Ruby-esque scripting language for the Java platform. It aims to combine the simplicity of scripting languages with the power and speed of Java. 42 | 43 | * [Grails](http://grails.org/) is the dominant framework for Groovy. As the name suggests it was inspired by Ruby on Rails. 44 | 45 | ## Scala 46 | 47 | Scala is another Java platform language. It aims for a "better Java" type of programming language. The language itself can be very technical, with lots of features and interesting mechanisms. 48 | 49 | * [Play](http://www.playframework.com/) is a popular framework inspired from the newer Django and Ruby on Rails frameworks. It tends to go it's own way though as the Java platform is not particularly suited to Django/Rails-style development. 50 | 51 | ## .NET / Mono 52 | 53 | The Microsoft .NET platform is technically very similar to Java, though only intended to run on Microsoft Windows. Seeing as most services are Linux based and many developers are on OSX that makes it a tough sell. But the platform is technically sound and has many productive programmers. Fortunately much of the technology is free to use for developers now. You just have to pay for the servers. 54 | 55 | Mono is an open-source implementation of the .NET platform. It is reasonably complete in many ways, but not quite as polished as .NET. 56 | 57 | * [ASP.NET MVC](http://www.asp.net/mvc) is the current website platform for .NET. It is reasonably complete as a framework, somewhere around the Spring Web MVC/Ruby on Rails/Django mark. 58 | * [Nancy](http://nancyfx.org/) is a minimalist framework aiming to support the "super-duper-happy-path". It works on .NET and Mono. 59 | 60 | ## Javascript 61 | 62 | The Javascript language (completely unrelated to the Java language) is often used on the server these days thanks to the Node server. It's a popular choice for people who already know Javascript. 63 | 64 | * [Express](http://expressjs.com/) is a popular conventional web framework. It contains a lot of the basics that others have. 65 | * [Meteor](http://meteor.com/) is a new framework that is quite unlike any others. It attempts to blur the line between browser and server, as the same code can theoretically run on both. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: ots 3 | title: README 4 | --- 5 | 6 | Site can be viewed [here](http://opentechschool.github.com/python-flask) 7 | 8 | This is a friendly how-to for contributors to the Websites with Python Flask course at OpenTechSchool. First, a quick refresher on the course: 9 | 10 | > Ever wanted to learn how websites work or wanted to build one yourself? Or maybe you have played around with some HTML but wonder how to get it to actually do something? Now is the time to start with our Websites with Python Flask workshop. We'll take you through creating a basic interactive website using Flask, a very popular choice for websites created using the Python programming language. 11 | 12 | > You will only need a laptop and a very basic understanding of Python (such as from our Introduction to Programming workshop). If you have previous experience with HTML, CSS and JavaScript then that is great too (but not required). 13 | 14 | So we are expecting users who have written a little code before but never shared it. They may have some JS, Python or Ruby skills, and may have written a bit of HTML and CSS. We won't be expecting them to have Python installed when they show up. 15 | 16 | # Class format 17 | 18 | At OpenTechSchool we tend to go *practical* and *at your own pace*. 19 | 20 | Practical meaning that we aren't big on theory, or requiring that people understand something completely before using it. We aren't expecting any of the students to become computer scientists. Generally programming for our students is a way of solving some practical problem. If they want to accomplish it with LISP or a spreadsheet is entirely up to them. 21 | 22 | At your own pace means that we provide access to the complete course notes at the beginning of the session. Then students can progress individually. Some students will get through very quickly, others will take some time, and most will finish the core work with time to spare. The core work should be completable by everyone. To keep things interesting we supply various additional topics which are entirely optional. 23 | 24 | A class schedule looks like this: 25 | 26 | 1200 - Students still arriving, writing name tags, setting up laptops. 27 | 1230 - Introductions, wifi instructions and location of coursework. 28 | 1235 - Students learn stuff. 29 | 1545 - Thankyous, maybe demonstrations. 30 | 31 | As you can see, the schedule just has a big chunk of 'learn stuff'. We like to keep things open. 32 | 33 | # Author Guide 34 | 35 | So, fork this repository. The guide is written as a [Jekyll](http://jekyllrb.com/) site, hosted on GitHub pages. It's set up so you can just write pages in Markdown. A markup guide is below. 36 | 37 | Course work goes under `core/` or `extras/`. It's all linked together by `index.md` in the root direcory. 38 | 39 | * `core/` covers the basic goals of the course. In this course that means setting up Git, creating a GitHub account, creating a repo, etc etc. Put any images in `core/images/` 40 | * `extras/` are all the interesting things people can do once they have completed the basics. Things like hosting with Heroku, or sending emails. 41 | 42 | It's easiest to start at the end. Think of a fun and interesting topic to add to the extras. Then you can copy this file to get an idea for formatting. 43 | 44 | ## Editing Text 45 | 46 | * We use long-lines (no newlines in paragraphs) to keep diffs moderately sane. 47 | * Code is indented with 4 spaces. 48 | * HTML/CSS is indented with 2 spaces. 49 | 50 | I use Emacs 24, with markdown-mode (Ubuntu emacs-goodies-el) and gfm-mode (GitHub markdown minor-mode). Set `longlines-show-hard-newlines` if you want to see where all the newlines are. These settings are useful: 51 | 52 | (add-to-list 'auto-mode-alist '("\\.md\\'" . markdown-mode)) 53 | (setq-default indent-tabs-mode nil) 54 | 55 | In Vim, you might like these settings: 56 | 57 | set tabstop=4 58 | set shiftwidth=4 59 | set expandtab 60 | 61 | # Markup Guide 62 | 63 | # First level section 64 | ## Second level section 65 | ### Third level section 66 | #### Fourth level section 67 | 68 | * List item 69 | * Sub item 70 | * Sub item 2 71 | * List it m 2 72 | 73 | 1. Ordered list item 74 | 2. Ordered list item 2 75 | 3. Ordered list item 3 76 | * Sub item 1 77 | * Sub item 2 78 | 4. Ordered list item 4 79 | 1. Ordered sub item 1 80 | 2. Ordered sub item 2 81 | 5. Ordered list item 5 82 | 83 | 84 | *emphasis text* for emphasis 85 | 86 | **strong text** for strong 87 | 88 | Getting literal with `backticks` 89 | 90 | Or use an indent of 4 spaces, 91 | to get yourself a code block, 92 | that looks lovely. 93 | 94 | > Do a bit of blockquoting. You can still reflow the text as much as you like. Newlines are awesome. And made of win. 95 | 96 | [links for nerds](http://slashdot.org) 97 | 98 | [links for internal stuff](section8.html) 99 | 100 | This is a horizonal rule: 101 | 102 | ****** 103 | 104 | If you want to highlight some ruby code: 105 | 106 | def foo 107 | puts 'foo' 108 | end 109 | 110 | Bit of command line: 111 | 112 | $ holla holla 113 | get dolla 114 | $ 115 | 116 | For a more complete list of languages see [highlight.js](http://softwaremaniacs.org/media/soft/highlight/test.html) 117 | -------------------------------------------------------------------------------- /extras/sessions.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: ots 3 | title: Keeping track of users 4 | --- 5 | 6 | ## What are sessions, and why do we need them? 7 | 8 | HTTP is, by itself, a _stateless_ protocol. That means it doesn't keep track of information or change much in-between requests. You should see the conundrum implicated by this if you look at the fact that practically every application on the web _does_ keep track of information - namely, they mostly keep track of you. If facebook was purely stateless, it wouldn't be able to recognise that you were logged in from one page to another - and probably wouldn't be very popular! 9 | 10 | A session then, is simply the name web developers usually give to the mechanism that lets you do this when serving (running) a web application. 11 | 12 | If you'd like to know how it works, the web server is usually instructed to send your browser a [HTTP cookie](http://en.wikipedia.org/wiki/HTTP_cookie_) along with the page content, when you visit. The cookie holds a unique value - that your browser will send back to the server with every request - that the application can then look up and re-identify you with when you ask for another page. 13 | 14 | In case you were wondering, when we run flask, it is acting as both a web server _and_ the web application (nicely bundled together to be easy to use!). 15 | 16 | ## So flask has sessions, right? How does one use them? 17 | 18 | It sure does, and they're very simple to use. Firstly, **add `session` as another module to import** from the `flask` package: 19 | 20 | from flask import session 21 | 22 | Then you need to give flask a secret key to use, to make sure the session is secure. To get a nice secret key, **run this at a command prompt**: 23 | 24 | python -c "import os; print repr(os.urandom(24))" 25 | 26 | and copy the string you get. To set this as the flask app's secret key, just **add the following line** after you initialize your `app` (use your own key!): 27 | 28 | app.secret_key = '#d\xe9X\x00\xbe~Uq\xebX\xae\x81\x1fs\t\xb4\x99\xa3\x87\xe6.\xd1_' 29 | 30 | You can now use the `session` that you imported, just as you would a dictionary - anywhere in your application. It will be a special dictionary, in that any key/value you set will be specific only for the user you set it to. When a different user visits your server, it will hold their own value (or not be there). 31 | 32 | How can we use this? Let's say we would like users to be able to delete their own email off of the email list. 33 | 34 | First, we have to **modify the `signup()` route** to remember the user's email address in the session: 35 | 36 | @app.route('/signup', methods = ['POST']) 37 | def signup(): 38 | email = request.form['email'] 39 | email_addresses.append(email) 40 | session['email'] = email 41 | print(email_addresses) 42 | return redirect('/') 43 | 44 | You can see that we simply added a line to save that email to our session dictionary. 45 | 46 | Then we can **create a new route**, that the user can visit to delete their address. 47 | 48 | @app.route('/unregister') 49 | def unregister(): 50 | # Make sure they've already registered an email address 51 | if 'email' not in session: 52 | return "You haven't submitted an email!" 53 | email = session['email'] 54 | # Make sure it was already in our address list 55 | if email not in email_addresses: 56 | return "That address isn't on our list" 57 | email_addresses.remove(email) 58 | del session['email'] # Make sure to remove it from the session 59 | return 'We have removed ' + email + ' from the list!' 60 | 61 | 62 | Here, we use a few `if` checks to make sure that our user added an email address already, and it's in our list. We can't remove it otherwise! Read through the code and the comments careful to make sure you understand what's happening. 63 | 64 | **Try out the new functionality!** Add an email address, and then visit `/unregister` in your web browser. When you next look at the list, your email address should have been removed! 65 | 66 | ### Extensions 67 | 68 | * Change the `/unregister` route to be a POST method only. Normally URLs that change data should only be POSTed to - otherwise a user might be tricked into changing data just from their browser accessing a link! After that, add a button / form on your main page that can send a POST to that route so your users can still unregister their email address. 69 | 70 | * Allow the app to remember when a user has already registered their email, and not show them an email input form when they have (maybe say Thanks! for signing up). Check out the [Jinja2 template documentation](http://jinja.pocoo.org/docs/templates/) if you'd like to use a little template logic to help with this. You could change the above button so that it also only shows after registering an email. 71 | 72 | Extra points: 73 | 74 | * Add a "protected" page which allows you to delete any email address, and a very simple admin login system (with just a single password) to access it. You can use a session to determine whether someone is currently logged in or not. This might be a little more difficult, but any challengers are welcome to try it out! You can check out the code sample [here](http://flask.pocoo.org/docs/quickstart/#sessions) for some hints on how to go about that. 75 | 76 | * Integrate these features into using your databases as needed 77 | -------------------------------------------------------------------------------- /core/html-css-js.md: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | layout: ots 4 | title: HTML, CSS and JavaScript 5 | 6 | --- 7 | 8 | Websites can be roughly divided into two parts, the browser and the server. 9 | 10 | We are all familiar with web browsers, you are using one right now. There are a number of popular ones, such as Chrome, Firefox and Internet Explorer. 11 | 12 | All web browsers handle the four fundamental technologies of the web. We've already seen the first, HTTP, which handles delivering content to the browser. Here are the remaining three: 13 | 14 | ## HTML 15 | 16 | The HyperText Markup Language. This is a file containing most of the text content of a web page and has a `.html` extension. The text is wrapped in _tags_ to give them meaning. A snippet of HTML might look like this: 17 | 18 |
    Nerds like us are allowed to be unironically enthusiastic about stuff. Nerds are allowed to love stuff - like, jump-up-and-down-in-your-chair-can't-control-yourself love it. When people call other people nerds, mostly what they're saying is "You like stuff", which is not a good insult at all. Like, "You are too enthusiastic about the miracle of human consciousness".
    19 |
    John Green
    20 | 21 | And when the browser _renders_ the HTML it looks like this: 22 | 23 |
    24 |
    Nerds like us are allowed to be unironically enthusiastic about stuff. Nerds are allowed to love stuff - like, jump-up-and-down-in-your-chair-can't-control-yourself love it. When people call other people nerds, mostly what they're saying is "You like stuff", which is not a good insult at all. Like, "You are too enthusiastic about the miracle of human consciousness".
    25 |
    John Green
    26 |
    27 | 28 | If you want to get a feel for what all the different HTML tags can be, and what they do, check out Mozilla's [HTML Element Reference](https://developer.mozilla.org/en-US/docs/HTML/Element). 29 | 30 | ## CSS 31 | 32 | Cascading Style Sheets give the browser styling hints for the HTML. It has a `.css` extension. Every website has CSS, because HTML looks _absolutely terrible_ without it. 33 | 34 | For the quote above we can do a stylesheet like this: 35 | 36 | blockquote { 37 | background-color: black; 38 | color: yellow; 39 | padding: 10px; 40 | } 41 | 42 | .cite { 43 | text-align: right; 44 | font-weight: bold; 45 | font-size: x-large; 46 | } 47 | 48 | Each section in the stylesheet applies to a different set of tags. The first section applies to any ``blockquote`` tags. The second section applies to any tags which have the attribute ``class="cite"`` as part of their name (like the second tag in the example.) 49 | 50 | When applied, this "styles" the quote to look like this: 51 | 52 |
    53 |
    Nerds like us are allowed to be unironically enthusiastic about stuff. Nerds are allowed to love stuff - like, jump-up-and-down-in-your-chair-can't-control-yourself love it. When people call other people nerds, mostly what they're saying is "You like stuff", which is not a good insult at all. Like, "You are too enthusiastic about the miracle of human consciousness".
    54 |
    John Green
    55 |
    56 | 57 | Note that even though the default style is terrible, that didn't stop me from creating an alternate, equally ugly, style. 58 | 59 | If you want a deeper understanding of what all of the CSS properties like ``padding`` or ``background-color`` can possibly do, check out Mozilla's [CSS Reference](https://developer.mozilla.org/en-US/docs/CSS/CSS_Reference). 60 | 61 | ## JavaScript 62 | 63 | JavaScript is an entire programming language contained entirely within the browser. Though HTML with CSS might look pretty, it can't actually do anything once the page has been rendered. 64 | 65 | This snippet of JavaScript will run in your browser and scan the current page for `blockquote` tags and give them a random color every 200 milliseconds (five times per second). 66 | 67 | function partypartyparty() { 68 | var quotes = document.getElementsByClassName('fancyquote'); 69 | for(var i=0; i 83 |
    Nerds like us are allowed to be unironically enthusiastic about stuff. Nerds are allowed to love stuff - like, jump-up-and-down-in-your-chair-can't-control-yourself love it. When people call other people nerds, mostly what they're saying is "You like stuff", which is not a good insult at all. Like, "You are too enthusiastic about the miracle of human consciousness".
    84 |
    John Green
    85 |
86 | 87 | We won't be covering JavaScript in this workshop, but if you do end up doing one of our JavaScript workshops in future then you will find much more useful things to do with it. 88 | 89 | 90 | -------------------------------------------------------------------------------- /core/setup.md: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | layout: ots 4 | title: Setup 5 | 6 | --- 7 | 8 | # Which Python? 9 | 10 | For this workshop it is recommended to use Python 3.4, which the latest version of Flask is compatible with! 11 | 12 | You can see what version of Python is installed by starting the Python interpreter. For example on Linux and OSX you can run the `python` command: 13 | 14 | $ python 15 | Python 2.7.6 (default, Nov 26 2013, 12:52:49) 16 | [GCC 4.8.2] on linux2 17 | Type "help", "copyright", "credits" or "license" for more information. 18 | >>> 19 | 20 | Here you can see it is version `2.7.6`. If you don't have Python installed or you have Python 2 then continue reading. It is very possible to use Flask with Python 2, but we recommend moving to the latest version of the language. 21 | 22 | # Python 3.3+ 23 | 24 | If you don't have this installed then you can download it [**here**](http://python.org/download/). The latest version at the time of writing is 3.4.1. 25 | 26 | * Windows: Choose one of the Installer packages - 'x86' if you have 32-bit Windows, or 'x86-64' if you have 64-bit Windows. Just ask if you're not sure which. 27 | * Mac: You most likely want the 64-bit/32-bit Installer. 28 | * Linux: most distributions will already have Python 2 installed, but you can install Python 3 using your system's package manager. For example, with Ubuntu, use `$ sudo apt-get install python3`. 29 | 30 | # pip 31 | 32 | Python comes with a lot of built-in functionality in the form of "packages". For example, we used the `turtle` module in the Introduction to Programming course. However, Python doesn't come with everything you might need. You can extend Python by adding new modules, which come bundled up in *packages*. 33 | 34 | The `pip` command uses the [Python Packages Index](https://pypi.python.org/pypi) to install new Python packages made by others. This makes it super-easy to install Flask and other packages that you might want to use in future, for example [Twitter](https://pypi.python.org/pypi/twitter) (to access the Twitter API to request data about Twitter) or [bashplotlib](https://pypi.python.org/pypi/bashplotlib) (to plot data on a graph in your terminal.) 35 | 36 | ### Windows 37 | 38 | To install pip on Windows, download and open [get-pip.py](https://raw.github.com/pypa/pip/master/contrib/get-pip.py). This will install both [pip] and [setuptools] \(pip uses setuptools to install packages\). 39 | 40 | Pip is a command line program, so we'll need to open up a Command Prompt to use it. You can type `cmd` in your Start Menu / Start Screen and Windows should find it for you to start. 41 | 42 | Afterwards there should be **pip** installed in Python's `Scripts` folder. In the command prompt you might not have python and its scripts in Windows' PATH; this essentially means when you type something like `pip install flask`, Windows won't be able find `pip`. To fix this, you can go to `C:\Python33\Tools\Scripts\` and run the `win_add2path.py` file. 43 | 44 | [pip]: https://pypi.python.org/pypi/pip 45 | [setuptools]: https://pypi.python.org/pypi/setuptools 46 | 47 | ### Mac OS X & Linux 48 | 49 | The `pip` command might already be installed, try running `pip` in the terminal. If that didn't work then try: 50 | 51 | $ curl -O https://bootstrap.pypa.io/get-pip.py 52 | $ python get-pip.py --user 53 | 54 | On Mac OSX you might need to use an older version of `pip` to workaround errors in the Mac OSX installation of OpenSSL. Details [here](https://github.com/pypa/pip/issues/829). If you have any troubles please 55 | ask! 56 | 57 | # Virtualenv 58 | 59 | This part isn't required for Flask, but its very useful if you think you'll ever work on more than one python project! You can skip over this section if you like, or come back to it later. 60 | 61 | **virtualenv** makes it easy to use different packages, and even different versions of packages, in your python projects. So you could have one project using Flask, another using Django, another using Bottle and they won't step all over each other, and you won't be confused for which project you installed which package. 62 | 63 | Installing on Windows is as easy as: 64 | 65 | C:\> pip install virtualenv 66 | 67 | On OS X and Linux, try 68 | 69 | $ pip install --user virtualenv 70 | 71 | Now that it is installed, we can set up a "virtual environment" for this workshop. This will keep Flask and it's dependencies contained to just this workshop. 72 | 73 | On OSX and Linux: 74 | 75 | # Create the directory for this workshop 76 | $ mkdir flask-workshop 77 | $ cd flask-workshop 78 | # Create a Python 3 virtualenv under the 'flaskenv' directory 79 | $ virtualenv --python=python3 flaskenv 80 | # Activate the virtual environment 81 | $ source flaskenv/bin/activate 82 | 83 | On Windows: 84 | 85 | # Create the directory for this workshop 86 | C:\> mkdir flask-workshop 87 | C:\> cd flask-workshop 88 | # Create a Python 3 virtualenv under the 'flaskenv' directory 89 | C:\> virtualenv flaskenv 90 | # Activate the virtual environment 91 | C:\> flaskenv\Scripts\activate 92 | 93 | The last step, *activate* sets up your terminal/command prompt session for using a contained Python3 installation in the `flask-workshop` directory. If you start up a new terminal then you will need to repeat the activation step again. 94 | 95 | The `deactivate` command can be used to return your terminal back to normal. But for now let's leave it activated because it's time to install Flask. 96 | 97 | # Installing Flask 98 | 99 | So far as website frameworks go, Flask has a minimal number of libraries that it needs to run. Though it would be possible to find and install all these libraries manually it is much easier to use the `pip` command. 100 | 101 | Now that everything is set up, installing Flask is as easy as: 102 | 103 | $ pip install flask 104 | 105 | Phew! That should be all the housekeeping, now we can get on with the fun stuff. 106 | -------------------------------------------------------------------------------- /core/forms.md: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | layout: ots 4 | title: Forms 5 | 6 | --- 7 | 8 | Now that we have a pretty home page it's time to put a _form_ on it. This will let people submit their email address. You've probably seen HTML forms a billion times already. Now we will take a brief tour of how forms work: 9 | 10 | ![HTML Sample Form](images/sample_web_form.png) 11 | 12 | This one comes from the world renowned Web 2.0 startup company "The Corner Pizza Shop". 13 | 14 | Forms start with the `
` tag. This marks the start of the form area, and can surround basically anything inside the HTML body. A form area starts like this: 15 | 16 | 17 | 18 | This means: this form sends an HTTP _POST_ to a page on the server called `post.html`. 19 | 20 | Inside the `` tag there are a number of different `` tags available: 21 | 22 | ## Text input 23 | 24 | ![HTML Sample Form](images/form-input.png) 25 | 26 | The text input element allows people to type in one line of text. The input type is `text`. 27 | 28 | 29 | 30 | Whatever is typed into this text box will be sent to the server with the variable `name`. 31 | 32 | ## Radio buttons 33 | 34 | ![HTML Sample Form](images/form-radio.png) 35 | 36 | Radio buttons allow users to select one option from many. They are named from the preset buttons on car radios. 37 | 38 | To create some radio buttons you use the input type `radio`: 39 | 40 | Supreme 41 | Vegetarian 42 | Hawaiian 43 | 44 | Here we can see that each `` has a type of `radio` and _the same name_, `topping`. It is imperative that each radio input has the same name, so they're all grouped together. The selected radio option will be sent back to the server with variable `topping`. The value of that variable will be one of the choices - `supreme`, `vegetarian` or `hawaiian`. 45 | 46 | ## Select dropdown 47 | 48 | ![HTML Sample Form](images/form-select.png) 49 | 50 | Select input is a little trickier. The ` 53 | 54 | 55 | 56 | 57 | 58 | 59 | When sent back to the server the browser will use the variable name `sauce` and the value of the selected option. 60 | 61 | ![HTML Sample Form](images/form-dropdown.png) 62 | 63 | There are a couple of gotchas with select boxes: 64 | 65 | * There is no built-in way to say "Select an option..." when the user has not selected an option yet. Although this is a very common scenario, and the browser automatically selects the first option which may be confusing. In HTML you have to specifically create a ` 69 | 70 | * There is an attribute called `multiple` which allows multiple selections in the `Extra Cheese 81 | Gluten Free Base 82 | 83 | When both are selected this will send back _two_ variables, `extra_cheese` and `gluten_free`. Each variable will have the value `1` if the checkbox is checked. 84 | 85 | The second is to use one name for each option: 86 | 87 | Extra Cheese 88 | Gluten Free Base 89 | 90 | When both are selected this will send back _one_ variable, `extras`, containing any value that is checked. Multiple values are separated by commas - ie `extra_cheese,gluten_free`. It is up to the server to split the value back into separate items. 91 | 92 | ## Textarea 93 | 94 | ![HTML Sample Form](images/form-textarea.png) 95 | 96 | When you want more than a single line of text from a user you can use the ` 99 | 100 | It even has the archaic `cols` and `rows` attributes, which hark back to the days of green-screen text terminals. These attributes decide the size of the textarea, but generally you should just use CSS. 101 | 102 | ## Submit button 103 | 104 | ![HTML Sample Form](images/form-submit.png) 105 | 106 | To get everything back to the server you need a submit button: 107 | 108 | 109 | 110 | When clicked the browser knows it is time to submit the form data back to the server. The browser gathers all the data in the ``, `