8000 First steps towards a part 3 for the tutorial. by: Giles · pythonanywhere/flask-tutorials@625003e · GitHub
[go: up one dir, main page]

Skip to content

Commit 625003e

Browse files
committed
First steps towards a part 3 for the tutorial. by: Giles
1 parent cb652a4 commit 625003e

File tree

1 file changed

+318
-0
lines changed

1 file changed

+318
-0
lines changed

tutorial-3.md

Lines changed: 318 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,318 @@
1+
Welcome to the third part in our tutorial for getting started with Flask development on PythonAnywhere! This is a continuation of our previous tutorial ([part 1](https://blog.pythonanywhere.com/121/), [part 2](https://blog.pythonanywhere.com/158/)) and builds on the codebase we worked on there, so if you haven't been through those, you should do that first.
2+
3+
So at the end of the last part of the tutorial, we had a website that showed a list of comments posted by people who could log in to the site. Only authorized users could post comments, and list of authorized users was stored in the database. And, of course, all of our source code was under source-code control in a git repository that is stored in our private file storage on PythonAnywhere.
4+
5+
In this part of the tutorial, we're going to pretend that our site now has lots of people using it regularly. There are two knock-on effects from that:
6+
7+
* It would be really boring work to have to keep using the `flask shell` command that we used last time to add new users (and anyway, how would they contact us to ask to be added to the site?)
8+
* We really don't want to break the site, even temporarily. So far, when we've been making changes to it, we've just gone right in and hacked the code directly. If we have a lot of users for a site, that won't be acceptable.
9+
10+
So this time around we're going to fix the second one of those first, by creating a completely new copy of the site
11+
in a second PythonAnywhere account. This will be our "development" environment, where we can hack away to our hearts' content while adding new features, knowing that our thousands of happy users won't be inconvenienced.
12+
13+
And once we've got that ready, we can fix the first problem, by adding a registration form where people can sign up to join the site. They'll enter their name, email address and password, we'll do some simple email validation, and then once that's done they can post away.
14+
15+
Here's what it will look like:
16+
17+
IMAGE
18+
19+
Sound good? Let's get going :-)
20+
21+
22+
## Setting up a separate development environment
23+
24+
Because you can only have one website on a free PythonAnywhere account, but we want a separate one for our
25+
development environment, we'll need a second account. That's not a problem -- you can sign up for multiple
26+
free accounts with the same email address.
27+
28+
(If you already have a paid PythonAnywhere account -- thanks! -- then you could in theory do all of this in
29+
one account with multiple websites. But then you'd miss out on all of the cool git stuff that's coming up,
30+
so please do try doing it this way -- you won't regret it :-) Also, you could in theory set up a development
31+
environment on your own local computer; the techniques would be pretty much the same. I'll stick to explaining
32+
it in terms of separate PythonAnywhere accounts, though, as it makes the explanation simpler -- and if you want
33+
to move over to doing stuff from your own machine later, you'll know enough of the details to make it pretty
34+
easy to set up.)
35+
36+
Now, the development process that we want to set up is to have
37+
38+
* The "live" site running in our existing PythonAnywhere account, with all of our thousands of users happily using it.
39+
* The "dev" site in a new 10000 account, with no-one using it apart from us.
40+
41+
We'll make changes in dev, test them (against a separate database so that our test comments don't pollute the
42+
live site), and then move them from dev to live -- a process normally called "deployment".
43+
44+
The obvious question is, how do we move the code from dev to live? You could copy files around or use FTP or
45+
something like that, but it would be tedious and error-prone. However, we're already using a tool that can
46+
make it safe and easy -- git.
47+
48+
All of our code is stored in a git repository that is stored in our private file storage on PythonAnywhere.
49+
Now, one nice thing about git is that you can push code from one repository to another -- it's this
50+
functionality that has made it so popular; it was originally developed to make life easier for the Linux
51+
kernel developers; with a large number of people working on different copies of the code, they needed
52+
a tool so that they could pass proposed code changes around easily. Using git for complex workflows
53+
like that can be tricky, but for a simple case like ours, with two environments that we want to copy
54+
changed between, it's actually really easy.
55+
56+
There is one wrinkle, though. We could set things up so that we could simply push and pull changes between
57+
our dev and live environments directly, but it would be a bit tricky to do that in a free PythonAnywhere account.
58+
So instead, we're going to use GitHub.
59+
60+
If you're not familiar with GitHub, don't worry -- although it does a lot of great stuff, we're only going to
61+
use a simple subset of its features. Basically, you can see it as a place where you can store repositories
62+
of code. If you have a repository on GitHub, you can push code to it from one machine, and pull it down from
63+
another -- so it can act as a central place that we use to move code around. A diagram should help:
64+
65+
IMAGE
66+
67+
So we're going to create a repository on GitHub, then set things up so that it can receive code from
68+
the one we already have on PythonAnywhere, then ee'll push our existing code up there.
69+
70+
Once that's done, we'll pull the code down from GitHub into the PythonAnywhere account we're going to create
71+
for the dev environment. We'll set up the dev environment, and make sure that we can have a running copy
72+
of our site there. Once that's done, we'll be able to make changes in dev, test them, push them up to GitHub,
73+
and then pull them down into live to deploy the changes.
74+
75+
So let's do all of that then :-)
76+
77+
The first step will be to make sure that our code is something that we can safely put on GitHub. Right now
78+
it's not :-( This is because with a free GitHub account, your code repositories are visible to anyone in the
79+
world -- and we have our database password and the Flask "secret key" right there in the code. Whoops!
80+
81+
Sidebar: it's actually bad practice to put passwords and secrets in a repository, even if you plan to keep
82+
it private -- we shouldn't have
83+
done it in the first part of the tutorial. But on the other hand,
84+
doing this stuff at the start would have made the first tutorial hard, and
85+
so we've delayed it until now. Also doing it now and emphasizing that this is fixing a mistake maybe
86+
will make it easier to remember. Or, at least, that's my story and I'm sticking to it :-)
87+
88+
The way we'll sanitise our repository is to move all of the private stuff into a new private file -- that
89+
is, one that we won't put in the repository.
90+
91+
92+
Move SQLALCHEMY_DATABASE_URI, SECRET_KEY into private_settings.py
93+
94+
Add from private_settings import SQLALCHEMY_DATABASE_URI, SECRET_KEY to flask app
95+
96+
Reload, check it works.
97+
98+
Now, because the history of our repository contains the old secret and mysql password we
99+
need to cahnge them
10 B41A 0+
101+
102+
103+
104+
Change the SECRET_KEY
105+
106+
Change the DB password on the databases page, and change the URI appropriately
107+
108+
Reload, check.
109+
110+
Now add private_settings.py to .gitignore
111+
112+
Commit
113+
114+
So now we can safely share the code with other people without them knowing our password or secret key
115+
116+
Explainer on github push/pull
117+
118+
Let's sign up for a github account. If you already have one, you can use it, of course
119+
120+
Once we're in, click the "New repository" button.
121+
122+
This will create a publicly-visible empty git repository on GitHub. Make the repository name something like "flask-tutorial".
123+
124+
It will now display a page like this. These are the options for connecting a repository
125+
126+
127+
Note the "...or push an existing repository from the command line". We have our repository on PythonAnywhere,
128+
and we want to connect it up with this one on GitHub. Later well create a new one on our development account
129+
and then pull the repository down to there.
130+
131+
So copy/paste the two lines into your bash console. The second one will prompt you for your github username and password
132+
133+
Now go back to github -- you can see your code in their interface.
134+
135+
The next step is to create a new PythonAnywhere account for your development site.
136+
137+
Log out of PythonAnywhere, and sign up for a new free account
138+
139+
In the new account, create a new Python 3.6 website
140+
141+
Check that it displays the "Hello from Flask" message
142+
143+
Start a bash console
144+
145+
We're going to get our code down from GitHub. Firstly -- the code for our new website is
146+
just stored in a directory called mysite, which we want to replace. Here's the command in bash
147+
148+
rm -r mysite
149+
150+
Now we clone it. In the github window, there's a "clone or download" button. Click it, and a
151+
thing will pop up with "clone with HTTPS" and a URL like https://github.com/flasksimpletutorial/flask-tutorial.git
152+
-- copy that URL.
153+
154+
Back in the bash console, run
155+
156+
git clone https://github.com/flasksimpletutorial/flask-tutorial.git mysite
157+
158+
-- that is, clone the code from that URL into a directory called mysite
159+
160+
go into the directory (cd mysite) and run git log -- you'll see that all of your history is there,
161+
just like in the original account
162+
163+
Now we need a virtualenv. In bash, run this (the same as we did from the other account)
164+
165+
mkvirtualenv flask-tutorial --python=python3.6
166+
167+
Now we'll install our requirements.
168+
169+
cd mysite
170+
pip install -r requirements.txt
171+
172+
When it's done, on the "Web" page, type "flask-tutorial" into the virtualenv field (under code)
173+
and reload the website. It'll be broken -- no database.
174+
175+
Now we need a database for this version of our site. Best to have dev and live on different databases so that we don't
176+
break stuff while testing.
177+
178+
On the Databases page, initialize MySQL. Use a different password to the one in the other account.
179+
180+
Once it's all initialized, create a database called "comments", just like the one in the live site.
181+
182+
Our site will need a private_settings.py. On the "files" page, create an empty file with that name inside
183+
mysite.
184+
185+
Put appropriate contents in it -- remember, it should look something like:
186+
187+
SQLALCHEMY_DATABASE_URI = "mysql+mysqlconnector://{username}:{password}@{hostname}/{databasename}".format(
188+
username="SOMETHING",
189+
password="SOMETHINGELSE",
190+
hostname="SOMETHING.mysql.pythonanywhere-services.com",
191+
databasename="SOMETHING$comments",
192+
)
193+
SECRET_KEY = "SOMETHING RANDOM"
194+
195+
Generate the secret key with the normal random key-bashing; the username should come from the databases page,
196+
as should the hostname; the password should be the one you entered there. Also remember that you need the
197+
username from the databases page before the $ in the database name.
198+
199+
First we need to tell the Flask tools where our code is
200+
201+
export FLASK_APP=flask_app.py
202+
203+
....and now we can just upgrade the database, which will run all of the migrations we painstaking created in the last tutorial so that all of the appropriate tables are there.
204+
205+
flask db upgrade
206+
207+
So now we have a site with a database and a virtualenv.
208+
209+
Visit the site -- it'll all be up and running! But we can't log in, as there are no users.
210+
211+
>>> from flask_app import db, User
212+
>>> from werkzeug.security import generate_password_hash
213+
>>> admin = User(username="testuser", password_hash=generate_password_hash("youllneverguess"))
214+
>>> db.session.add(admin)
215+
>>> db.session.commit()
216+
217+
Now back to the tab showing the website; we can log in with testuser and the given password.
218+
219+
Try adding a comment -- it's there!
220+
221+
Check out our old site -- of course, the comment isn't there.
222+
223+
So now we have a development version of our site that we can hack on without having to worry
224+
about inconveniencing the thousands of keen users of our main "live" site.
225+
226+
Before we dive in and start making big changes, let's try making a nice simple change so that
227+
we can go through the deployment process once. Because we now have thousands of users for our
228+
site, calling it "My scratchpad" is a bit egotistical. Let's call it "Our scratchpad" :-)
229+
230+
Still in our dev PythonAnywhere account, go to the "Files" page and open up the "mysite" folder,
231+
then go into the "templates" directory. Open up, in turn, the login_page.html and the main_page.html
232+
files, and change the "title" tags to reflect our new, more-open site name.
233+
234+
CODE SAMPLES
235+
236+
Visit the site (remember, you don't need to reload if it's just a template change) and you'll see it's updated.
237+
But, of course, these changes only exist on the development version of the site.
238+
239+
Let's deploy!
240+
241+
First, commit the changes. Firstly, because this is a new PythonAnywhere account, we need
242+
to tell git who we are. Back to the bash console and run the two commands you did in the other
243+
account, way back in part 1 of the tutoria (replacing the stuff in the quotes appropriately):
244+
245+
git config --global user.name "Your Name"
246+
git config --global user.email "you@example.com"
247+
248+
We'll also need an extra bit of configuration:
249+
250+
git config --global push.default simple
251+
252+
(This is simply to disable a bothersome message git will print out.)
253+
254+
Now you can commit:
255+
256+
git add .
257+
git commit -m"Changed title to be more inclusive"
258+
259+
So the changes we've made exist in the local git repository, stored inside this PythonAnywhere account --
260+
but nowhere else. Run git log to see the history
261+
262+
Then, head over to the tab where you kept GitHub open -- click down through the templates directory and look at the main_page.html -- you'll see that the changes haven't propagated there yet, which makes sense because we haven't done anything to make that happen.
263+
264+
So the next step is to push the changes to GitHub. This is really simple:
265+
266+
(flask-tutorial) 18:01 ~/mysite (master)$ git push
267+
Username for 'https://github.com': flasksimpletutorial
268+
Password for 'https://flasksimpletutorial@github.com':
269+
Counting objects: 9, done.
270+
Delta compression using up to 2 threads.
271+
Compressing objects: 100% (5/5), done.
272+
Writing objects: 100% (5/5), 451 bytes | 0 bytes/s, done.
273+
Total 5 (delta 3), reused 0 (delta 0)
274+
remote: Resolving deltas: 100% (3/3), completed with 3 local objects.
275+
To https://github.com/flasksimpletutorial/flask-tutorial.git
276+
a0ef303..819bc87 master -> master
277+
278+
Now check out the code on GitHub -- you'll see the changes there.
279+
280+
The next step is the opposite side of the push we just did -- we want to pull the changes down
281+
into the live site.
282+
283+
Now, we could just log out of PythonAnywhere and log back in to the original account, but that could
284+
get boring quite quickly if we did it every time we did a deploy -- and hopefully we'll be doing
285+
a number of deployments over the course of this tutorial. One way of avoiding that is to make use of
286+
your browser's incognito mode; you can have two PythonAnywhere sesssions active, one in your browser's
287+
normal mode and one in incognito.
288+
289+
So, open a new incognito window, and in it, go to PythonAnywhere. From there, log in as your original
290+
user, the one that owns the live site. Got to your bash console, make sure you're cd'ed into the mysite
291+
directory, and do a "git pull":
292+
293+
16:51 ~/mysite (master)$ git pull
294+
remote: Counting objects: 5, done.
295+
remote: Compressing objects: 100% (2/2), done.
296+
remote: Total 5 (delta 3), reused 5 (delta 3), pack-reused 0
297+
Unpacking objects: 100% (5/5), done.
298+
From https://github.com/flasksimpletutorial/flask-tutorial
299+
a0ef303..819bc87 master -> origin/master
300+
Updating a0ef303..819bc87
301+
Fast-forward
302+
templates/login_page.html | 4 ++--
303+
templates/main_page.html | 4 ++--
304+
2 files changed, 4 insertions(+), 4 deletions(-)
305+
18:08 ~/mysite (master)$
306+
307+
The templates were updated; you can confirm that by going to the website, and you'll see that the
308+
titles have changed.
309+
310+
So now we've created an independent development environment for our website, and successfully set everything
311+
up so that we can easily push changes from dev through to live.
312+
313+
Now let's get started with some more serious changes.
314+
315+
316+
317+
318+
thoraway1234

0 commit comments

Comments
 (0)
0