-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Simplify deployment chapter by using pythonanywhere "autoconfigure" script #1190
Changes from 6 commits
c0c06f5
7e173e2
b0c7961
d1e1c3b
b83511b
5378bbc
925acaa
b5fc623
45dbe41
30f3e6e
4b65d38
44b7f9d
5dd4a49
85f67fb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -130,159 +130,118 @@ Your code is now on GitHub. Go and check it out! You'll find it's in fine compa | |
|
||
# Setting up our blog on PythonAnywhere | ||
|
||
## Sign up for a PythonAnywhere account | ||
|
||
> **Note** You might have already created a PythonAnywhere account earlier during the install steps – if so, no need to do it again. | ||
|
||
{% include "/deploy/signup_pythonanywhere.md" %} | ||
|
||
|
||
## Pulling our code down on PythonAnywhere | ||
## Creating an API token | ||
|
||
When you've signed up for PythonAnywhere, you'll be taken to your dashboard or "Consoles" page. Choose the option to start a "Bash" console – that's the PythonAnywhere version of a console, just like the one on your computer. | ||
This is something you only need to do once. When you've signed up for PythonAnywhere, you'll be taken to your dashboard. Find the link near the top right to your "Accounts" page, then select the tab named "API token", and hit the button that says "Create new API token". | ||
|
||
<img src="images/pythonanywhere_bash_console.png" alt="pointing at Other: Bash in Start a new Console" /> | ||
<img src="images/pythonanywhere_create_api_token.png" alt="The API token tab on the Accounts page" /> | ||
|
||
> **Note** PythonAnywhere is based on Linux, so if you're on Windows, the console will look a little different from the one on your computer. | ||
|
||
Let's pull down our code from GitHub and onto PythonAnywhere by creating a "clone" of our repo. Type the following into the console on PythonAnywhere (don't forget to use your GitHub username in place of `<your-github-username>`): | ||
## Configuring our site on PythonAnywhere | ||
|
||
{% filename %}PythonAnywhere command-line{% endfilename %} | ||
``` | ||
$ git clone https://github.com/<your-github-username>/my-first-blog.git | ||
``` | ||
Go back to the main PythonAnywhere Dashboard by clicking on the logo, and choose the option to start a "Bash" console – that's the PythonAnywhere version of a command line, just like the one on your computer. | ||
|
||
<img src="images/pythonanywhere_bash_console.png" alt="Pointing at Bash in the New Console section" /> | ||
|
||
> **Note** PythonAnywhere is based on Linux, so if you're on Windows, the console will look a little different from the one on your computer. | ||
|
||
This will pull down a copy of your code onto PythonAnywhere. Check it out by typing `tree my-first-blog`: | ||
Deploying a web app on PythonAnywhere involves pulling down your code from GitHub, and then configuring PythonAnywhere to recognise it and start serving it as a web application. There are manual ways of doing it, but PythonAnywhere provide a helper tool that will do it all for you. Let's install it first: | ||
|
||
{% filename %}PythonAnywhere command-line{% endfilename %} | ||
``` | ||
$ tree my-first-blog | ||
my-first-blog/ | ||
├── blog | ||
│ ├── __init__.py | ||
│ ├── admin.py | ||
│ ├── migrations | ||
│ │ ├── 0001_initial.py | ||
│ │ └── __init__.py | ||
│ ├── models.py | ||
│ ├── tests.py | ||
│ └── views.py | ||
├── manage.py | ||
└── mysite | ||
├── __init__.py | ||
├── settings.py | ||
├── urls.py | ||
└── wsgi.py | ||
$ pip3.6 install --user pythonanywhere | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How does There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is the very first command the user runs on PythonAnywhere. There is no virtualenv active at this point. |
||
``` | ||
|
||
That should print out some things like `Collecting pythonanywhere`, and eventually end with a line saying `Successfully installed (...) pythonanywhere- (...)`. | ||
|
||
### Creating a virtualenv on PythonAnywhere | ||
|
||
Just like you did on your own computer, you can create a virtualenv on PythonAnywhere. In the Bash console, type: | ||
Now we run the helper to automatically configure our app from GitHub. Type the following into the console on PythonAnywhere (don't forget to use your GitHub username in place of `<your-github-username>`): | ||
|
||
{% filename %}PythonAnywhere command-line{% endfilename %} | ||
``` | ||
$ cd my-first-blog | ||
|
||
$ virtualenv --python=python3.6 myvenv | ||
Running virtualenv with interpreter /usr/bin/python3.6 | ||
[...] | ||
Installing setuptools, pip...done. | ||
|
||
$ source myvenv/bin/activate | ||
|
||
(myvenv) $ pip install django~=1.11.0 | ||
Collecting django | ||
[...] | ||
Successfully installed django-1.11.3 | ||
$ pa_autoconfigure_django.py https://github.com/<your-github-username>/my-first-blog.git | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On a fresh pythonanywhere account (
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
👍 Worked fine with
I might try that later, but as long as this option isn't mentioned in the tutorial, I don't think it's relevant to this PR. I'll also review the rest of the changed instructions in this PR, probably some time this evening.
Just as expected! 😃
Nope, we have them go the "deploy early, deploy often" way. Due to first introducing some general Internet and Web concepts and then teaching the participants some basic Python, this deploy chapter is already around halfway into the tutorial. Depending on the length of the workshop, this is often as far as participants get on-site. As the note at the top of the chapter explains, deploying in this "early" state of the project should also enable the participants to more easily finish the tutorial at home on their own, should they not be able to finish it during a workshop. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. great! glad it's working now. and thanks for the clarification re: the state of the repo at that point. that actually reminds me - I think the current instructions are missing the |
||
``` | ||
|
||
As you watch that running, you'll be able to see what it's doing: | ||
|
||
> **Note** The `pip install` step can take a couple of minutes. Patience, patience! But if it takes more than five minutes, something is wrong. Ask your coach. | ||
- Downloading your code from GitHub | ||
- Creating a virtualenv on PythonAnywhere, just like the one on your own PC | ||
- Updating your settings file with some deployment settings | ||
- Setting up a database on PythonAnywhere using the "migrate" command | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd use inline code markup instead of quotes here, and prepend
|
||
- Setting up your static files (we'll learn about these later) | ||
- And configuring PythonAnywhere to serve your web app via its API | ||
|
||
<!--TODO: think about using requirements.txt instead of pip install.--> | ||
On PythonAnywhere all those steps are automated, but they're the same steps you | ||
would have to go through with any other server provider. The main thing to notice | ||
right now is that your database on PythonAnywhere is actually totally separate from | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 This phrasing is better than the original one, as "separate" makes the point more clearly than "different". (Judging from the questions we get on https://gitter.im/DjangoGirls/tutorial, this often lead to confusion or misconceptions.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. thanks! |
||
your database on your own PC -- that means it can have different posts and admin accounts. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will GitBook show this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll replace it with an explict mdash literal just in case. |
||
|
||
### Creating the database on PythonAnywhere | ||
As a result, just as we did on your own computer, we repeat the step to | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While it can be concluded that we have to repeat that step, doing so is not a "result" of what was mentioned above.
instead of
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can i disagree with this? to me the meaning of "as a result" is almost exactly the same as "thus". we have to run createsuperuser again because the database is separate / as a result of the fact that the database is seperate / the database is seperate, thus we have to run createsuperuser again. they all mean the same thing to me. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, then maybe include the "have to":
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. never mind, I now see you already changed it to "need to", which is just as fine to make to logic work out |
||
initialize the admin account with `createsuperuser`. | ||
|
||
Here's another thing that's different between your own computer and the server: it uses a different database. So the user accounts and posts can be different on the server and on your computer. | ||
First, we activate the PythonAnywhere virtualenv, and then we `cd` into our | ||
code directory. PythonAnywhere has named them both after your site's name: | ||
|
||
Just as we did on your own computer, we repeat the step to initialize the database on the server, with `migrate` and `createsuperuser`: | ||
|
||
{% filename %}PythonAnywhere command-line{% endfilename %} | ||
``` | ||
(mvenv) $ python manage.py migrate | ||
Operations to perform: | ||
[...] | ||
Applying sessions.0001_initial... OK | ||
(mvenv) $ python manage.py createsuperuser | ||
$ workon $USER.pythonanywhere.com | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can never remember which non-whitespace characters terminate a shell variable name and which don't, so when doing something like this myself, I prefer to use the workon ${USER}.pythonanywhere.com But maybe that's just me, and to most of our participants this will be rather "magic" anyway (as we AFAIK don't introduce shell variables to them anywhere in the tutorial). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I couldn't tell you about shell variable name termination either, but in any case this one works. I'm still a bit uncomfortable about the magic here. We could revert back to just using "yourusername.pythonanywhere.com"? It has the benefit of teaching people that, when they copy and paste instructions from the internet, they always have to look out for any placeholder strings they need to substitute... Happy either way tbh. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we just mention that bash will substitute the username for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes! or at least, let's at least give it a try, then we can take a view as to whether we're throwing too many distracting explanations around... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK, I've done that. I am a bit worried that we're spending a lot of time explaining some stuff that's not really core to either the deployment, or pythonanywhere. Maybe we need to take a step back, or ask someone else to have a fresh pair of eyes on it? I don't know. It'll work, and we will definitely get the benefit of avoiding copy-paste errors, but I worry that adding the (in the ORM chapter for example, we expect people to substitute There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it OK to use the Maybe add a short explanation that this does the same as the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think at least a short explanation would be a good idea yes. I'll add one. ( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about I look into whether we could drop virtualenvwrapper for the autoconfigure script, and just have a "normal" virtualenv folder, in the same folder as the source code folder? maybe a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It makes me wonder: would it be possible to fully abstract the pythonanywhere setup behind a script? Including pulling. That way we don't need to explain it and skipping would be easy as well. It's a comment I heard a few times: deployment to pythonanywhere is nice, but doesn't add a lot of value in terms of learning. A lot of duplicated steps. It is nice that they can actually go there on their phones so the end result is certainly nice but in a time of PaaS and even more modern alternatives, should we really start with teaching about hosting? The basics of web development are hard enough as it is. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. finally, re: "vanilla" virtualenv vs virtualenvwrapper, the suggestion that we "hack" virtualenvwrapper by changing but I think we could definitely consider the option of adding a yes the script is intended to be useful for people outside of djangogirls, but djangogirls is my first target market, and it's more important to me to make y'all happy first, and I can worry about other people later. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if a nice way to sidestep this issue for now would be to have the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
What I meant was to do that
Thus pa_autoconfigure_django.py https://github.com/<your-github-username>/some-django-project.git would have the same behavior as it currently has, and for the tutorial, we'd do something like pa_autoconfigure_django.py https://github.com/<your-github-username>/my-first-blog.git --virtualenv-name myvenv --workon-home . or even WORKON_HOME="." pa_autoconfigure_django.py https://github.com/<your-github-username>/my-first-blog.git --virtualenv-name myvenv
👍 Yeah, if that's workable, it's probably an even better approach. ✨ Hide the magic behind sufficiently advanced technology, so it won't unsettle anyone. ✨ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. :) working on said magic now 🎩 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK magic done! |
||
(yourusername.pythonanywhere.com) $ cd $USER.pythonanywhere.com | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Dito w.r.t. variable interpolation |
||
(yourusername.pythonanywhere.com) $ python manage.py createsuperuser | ||
``` | ||
|
||
## Publishing our blog as a web app | ||
|
||
Now our code is on PythonAnywhere, our virtualenv is ready, and the database is initialized. We're ready to publish it as a web app! | ||
|
||
Click back to the PythonAnywhere dashboard by clicking on its logo, and then click on the **Web** tab. Finally, hit **Add a new web app**. | ||
|
||
After confirming your domain name, choose **manual configuration** (N.B. – *not* the "Django" option) in the dialog. Next choose **Python 3.6**, and click Next to finish the wizard. | ||
|
||
> **Note** Make sure you choose the "Manual configuration" option, not the "Django" one. We're too cool for the default PythonAnywhere Django setup. ;-) | ||
|
||
If you like you can also take a look at your code on PythonAnywhere by typing `tree`: | ||
|
||
### Setting the virtualenv | ||
|
||
You'll be taken to the PythonAnywhere config screen for your webapp, which is where you'll need to go whenever you want to make changes to the app on the server. | ||
|
||
<img src="images/pythonanywhere_web_tab_virtualenv.png" /> | ||
|
||
In the "Virtualenv" section, click the red text that says "Enter the path to a virtualenv", and enter `/home/<your-PythonAnywhere-username>/my-first-blog/myvenv/`. Click the blue box with the checkmark to save the path before moving on. | ||
|
||
> **Note** Substitute your own PythonAnywhere username as appropriate. If you make a mistake, PythonAnywhere will show you a little warning. | ||
|
||
|
||
### Configuring the WSGI file | ||
|
||
Django works using the "WSGI protocol", a standard for serving websites using Python, which PythonAnywhere supports. The way we configure PythonAnywhere to recognize our Django blog is by editing a WSGI configuration file. | ||
|
||
Click on the "WSGI configuration file" link (in the "Code" section near the top of the page – it'll be named something like `/var/www/<your-PythonAnywhere-username>_pythonanywhere_com_wsgi.py`), and you'll be taken to an editor. | ||
|
||
Delete all the contents and replace them with the following: | ||
|
||
{% filename %}<your-username>_pythonanywhere_com_wsgi.py{% endfilename %} | ||
```python | ||
import os | ||
import sys | ||
|
||
path = os.path.expanduser('~/my-first-blog') | ||
if path not in sys.path: | ||
sys.path.append(path) | ||
|
||
os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings' | ||
|
||
from django.core.wsgi import get_wsgi_application | ||
from django.contrib.staticfiles.handlers import StaticFilesHandler | ||
application = StaticFilesHandler(get_wsgi_application()) | ||
{% filename %}PythonAnywhere command-line{% endfilename %} | ||
``` | ||
$ tree | ||
. | ||
├── blog | ||
│ ├── __init__.py | ||
│ ├── admin.py | ||
│ ├── migrations | ||
│ │ ├── 0001_initial.py | ||
│ │ └── __init__.py | ||
│ ├── models.py | ||
│ ├── tests.py | ||
│ └── views.py | ||
├── manage.py | ||
└── mysite | ||
├── __init__.py | ||
├── settings.py | ||
├── urls.py | ||
└── wsgi.py | ||
``` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The output of 18 directories, 84 files (click to expand)
Maybe we should ignore some stuff with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. well spotted. tree -L 3 -- 22 directories, 93 files$ tree -L 3 . ├── blog │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-36.pyc │ │ ├── [...] │ ├── admin.py │ ├── forms.py │ ├── migrations │ │ ├── 0001_initial.py │ │ ├── __init__.py │ │ └── __pycache__ │ ├── models.py │ ├── static │ │ └── css │ ├── templates │ │ └── blog │ ├── tests.py │ ├── urls.py │ └── views.py ├── db.sqlite3 ├── manage.py ├── mysite │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-36.pyc │ │ ├── [...] │ ├── settings.py │ ├── urls.py │ └── wsgi.py └── static ├── admin │ ├── css │ ├── fonts │ ├── img │ └── js └── css └── blog.css I'm not sure we really want to dive into an explanation of
that seems simpler, maybe just go with that for now? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, good call. 👍
|
||
|
||
This file's job is to tell PythonAnywhere where our web app lives and what the Django settings file's name is. | ||
You can also go to the "Files" tab and navigate around using PythonAnywhere's built-in | ||
file browser. | ||
|
||
The `StaticFilesHandler` is for dealing with our CSS. This is taken care of automatically for you during local development by the `runserver` command. We'll find out a bit more about static files later in the tutorial, when we edit the CSS for our site. | ||
|
||
Hit **Save** and then go back to the **Web** tab. | ||
## You are now live! | ||
|
||
We're all done! Hit the big green **Reload** button and you'll be able to go view your application. You'll find a link to it at the top of the page. | ||
Your site should now be live on the public Internet! Click through to the | ||
PythonAnywhere "Web" tab to get a link to it. You can share this with anyone you want :) | ||
|
||
|
||
## Debugging tips | ||
|
||
If you see an error when you try to visit your site, the first place to look for some debugging info is in your **error log**. You'll find a link to this on the PythonAnywhere [Web tab](https://www.pythonanywhere.com/web_app_setup/). See if there are any error messages in there; the most recent ones are at the bottom. Common problems include: | ||
|
||
- Forgetting one of the steps we did in the console: creating the virtualenv, activating it, installing Django into it, migrating the database. | ||
If you see an error while running the `pa_autoconfigure_django.py` script, there are | ||
a couple of common causes: | ||
|
||
- Making a mistake in the virtualenv path on the Web tab – there will usually be a little red error message on there, if there is a problem. | ||
- Forgetting to create your API token. | ||
- Making a mistake in your GitHub URL | ||
|
||
- Making a mistake in the WSGI configuration file – did you get the path to your my-first-blog folder right? | ||
|
||
- Did you pick the same version of Python for your virtualenv as you did for your web app? Both should be 3.6. | ||
If you see an error when you try to visit your site, the first place to look for some debugging info is in your **error log**. You'll find a link to this on the PythonAnywhere [Web tab](https://www.pythonanywhere.com/web_app_setup/). See if there are any error messages in there; the most recent ones are at the bottom. | ||
|
||
There are also some [general debugging tips on the PythonAnywhere wiki](https://www.pythonanywhere.com/wiki/DebuggingImportError). | ||
There are also some [general debugging tips on the PythonAnywhere help site](http://help.pythonanywhere.com/pages/DebuggingImportError). | ||
|
||
And remember, your coach is here to help! | ||
|
||
|
@@ -295,3 +254,4 @@ Once you have a few posts created, you can go back to your local setup (not Pyth | |
|
||
|
||
Give yourself a *HUGE* pat on the back! Server deployments are one of the trickiest parts of web development and it often takes people several days before they get them working. But you've got your site live, on the real Internet, just like that! | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,4 +4,5 @@ Next, it's time to sign up for a free "Beginner" account on PythonAnywhere. | |
* [www.pythonanywhere.com](https://www.pythonanywhere.com/) | ||
|
||
|
||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why the added blank line? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no idea. have removed it again. |
||
> **Note** When choosing your username here, bear in mind that your blog's URL will take the form `yourusername.pythonanywhere.com`, so choose either your own nickname or a name for what your blog is all about. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/provide/provides/
, as "PythonAnywhere" seems to be singular, not plural (as seen by the "is" in the note above).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep!