Jump to content

Django for ISchoolers: Difference between revisions

no edit summary
imported>Aldeka
imported>Aldeka
No edit summary
Line 1:
This is a tutorial for how to build a question-and-answer type site using Django and various other technologies, plus some lessons in general web dev concepts and best practices along the way.
 
= TheChunk basicsone =
 
== Prerequisites ==
Line 36:
 
== Spec'ing yer application ==
Your client, LulzTech, wants you to build them a Q & A website, called qandabear. ('Q and A bear', rhymes with panda bear.) For mysterious reasons, they don't want to use any of the open source Q&A website packages that are out there already; they want you to build one from scratch. Go figure.)
 
There are whole classes on how to research and decide what to build, and how to state those requirements in a useful, clear way. (Bob's ISSD class, for one.) So we won't go into that. For our initial prototype for our client, then, our requirements are as follows:
Line 170:
== Set up settings ==
 
Now that we have a the scaffolding for our project in place, we can get to work! First, it needs to be configured.
(skipping demonstration of magic git backup powers)
 
===Add yourself as an admin!===
* Open settings.py in your editor. settings.py is a Python script that only contains variable definitions. Django looks at the values of these variables when it runs your web app.
* Find ADMINS and replace Your Name and your_email@example.com with your name and your email address.
Remove the pound mark from the front of the line to uncomment it out.
* git add and commit it:
 
<code># even though git knows to "listen" to settings.py now, it still won't add it to the 'staging area' for your commit unless you tell it to explicitly with git add<br>
git add settings.py<br>
git commit -m "made myself an admin"</code>
 
===Set up the Database===
 
Keep looking at settings.py: The DATABASES variable is a dictionary (note the ‘{}’ characters) with one key: default.
 
<code> DATABASES = {<br>
'default': {<br>
'ENGINE': 'django.db.backends', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.<br>
'NAME': '', # Or path to database file if using sqlite3.<br>
'USER': '', # Not used with sqlite3.<br>
'PASSWORD': '', # Not used with sqlite3.<br>
'HOST': '', # Set to empty string for 127.0.0.1. Not used with sqlite3.<br>
'PORT': '', # Set to empty string for default. Not used with sqlite3.<br>
}<br>
}</code>
 
Notice that the value of default is itself another dictionary with information about the site’s default database.
 
* Set your app to use a sqlite database, in the ENGINE attribute. Sqlite is great for development because is stores its data in one normal file on your system and therefore is really simple to move around with your app. It's not sturdy enough to use for a website in production, though.
 
<code>'ENGINE': 'django.db.backends.sqlite3',</code>
 
* Set your app to use a file called 'database.db' to store information for this project.
 
<code>'NAME': 'database.db',</code>
 
Does database.db exist right now? (No, but that's okay. It'll get created automatically when it's needed.)
 
Notice the INSTALLED_APPS setting towards the bottom of the settings.py. That variable (a tuple... note the ‘()’ symbols) holds the names of all Django applications that are activated in this Django instance. Apps can be used in multiple projects, and you can package and distribute them for use by others in their projects. What do you think these various apps do? Why does it make sense for them to come in a standard configuration?
 
* Add South to our list of installed apps. (We'll need it later.)
 
<code>INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
# Uncomment the next line to enable the admin:
# 'django.contrib.admin',
# Uncomment the next line to enable admin documentation:
# 'django.contrib.admindocs',
'south',
)</code>
 
* Each of these applications makes use of at least one database table, so we need to create the tables in the database before we can use them. To do that, run the following command:
 
<code>python manage.py syncdb</code>
 
The syncdb command looks at the INSTALLED_APPS setting and creates any necessary database tables according to the database settings in your settings.py file. You’ll see a message for each database table it creates.
 
* When prompted, you’ll get a prompt asking you if you’d like to create a superuser account for the authentication system. Say yes! Use ‘super’ as your password.
 
Does database.db exist right now? (Yes! Calling syncdb made Django realize it needed a sqlite database file, so it made one for us.)
 
* Save and commit your work
 
<!-- (skipping demonstration of magic git backup powers) -->
 
== Projects v. apps -- what's the difference? ==
 
We’ve talked a little about Django apps and projects. You might be wondering what that nonsense is all about. Here are the things to know:
 
* An '''app''' is component of a website that does something. South is a Django app. So is qandabear (or will be, anyway). An app is:
** single purpose - login, passwords, polls, forum, etc.
** orthogonal to / independent of other apps - qandabear shouldn’t have to know the inside details of authentication, for example.
 
* A '''project''' corresponds to a ‘website’: it contains a settings.py file, and it may have corresponding databases or other data stores that the apps interact with.
 
Most projects--those for more complex websites--should use multiple apps, one for each core piece of functionality.
 
Ideally, you should reuse existing free, open source Django apps that other people have written for things like user accounts, image galleries, and other common use cases. [Django Packages http://www.djangopackages.com] is a good resource for finding such apps. Django adheres to the principle of DRY -- Don't Repeat Yourself -- and in your real world coding adventures, you should strive to avoid repeating other, wiser developers as well. :)
 
== Starting yer app ==
 
In this tutorial, we’ll create our poll app in the myproject directory for simplicity. In the future, when you decide that the world needs to be able to use your poll app and plug it into their own projects, and after you determine that your app plays nicely with other apps, you can publish that directory separately!
== Test-driven development, part one ==
 
* Open your terminal and navigate into the mysite folder
* Make scaffolding for the app:
 
<code>$ python manage.py startapp qandabear</code>
 
That’ll create a directory qandabear to house our Q & A application.
 
* Verify what is new.
 
<code>$ git status<br>
# should show 'qandabear/' in 'untracked'</code>
 
* Examine the layout of qandabear (we will do more of this in following sections).
 
<code># remember not to type the '$', it just means the prompt'.<br>
$ ls qandabear<br>
qandabear/<br>
__init__.py<br>
models.py<br>
tests.py<br>
views.py<br>
</code>
 
* Add and commit <code>qandabear/*py</code>.
* Install the Q&A app into the project. Edit the settings.py file again, and change the INSTALLED_APPS setting to include the string ‘qandabear’ as the last entry.
* Save and commit the settings.py file.
 
= Chunk 2 =
 
At the end of each 'chunk', I'm going to push our progress so far to the tutorial git repository. If you're doing this tutorial in class, please switch back to the master branch, then pull my changes.
 
<code>$ git checkout master<br>
$ git pull origin master</code>
 
This will make it so that everyone starts out each chunk with the same working code, so even if you get stuck or confused in one session, you can still keep up. (Since I don't have any TAs to help debug or answer questions, and we don't have that much time.)
 
Remember that *you* shouldn't be putting your modifications inside the master branch, though! (Otherwise, you'd have to overwrite them at the next chunk checkpoint, and that would be sad.) Instead, make a new branch for chunk 2 based off the master code you just downloaded, and let's get going!
 
<code>$ git branch my-chunk-2<br>
$ git checkout my-chunk-2</code>
 
<!-- == Test-driven development, part one ==
 
(use provided tests.py file)
Line 183 ⟶ 306:
# Test
# Code
# Commit -->
 
== M-V-C separation ==
 
Model: how the data is organized.
Controller: how the logic of the app works.
View: How the app looks to the user.
 
(chart explaining model-view-controller separation in Django)
 
== urls.py ==
 
The first step to writing your application is to design your URL structure. You do this by creating a Python module, called a URLconf. URLconfs are how Django associates a given URL with given Python code.
 
=== How URLconfs work (or, the joy of regular expressions!) ===
When a user requests a Django-powered page, the system looks at the ROOT_URLCONF setting, which contains a string in Python dotted syntax.
 
Django loads that module and looks for a module-level variable called urlpatterns, which is a sequence of Python tuples in the following format: (regular expression, Python callback function [, optional dictionary])
 
Django starts at the first regular expression and makes its way down the list, comparing the requested URL against each regular expression until it finds one that matches.
 
You might ask, “What’s a regular expression?” Regular expressions, or "regexes", are patterns for matching text. In this case, we’re matching the URLs people go to, and using regular expressions to match whole ‘groups’ of them at once. (If you’d like to learn more about regular expressions, read the [Dive into Python guide to regular expressions http://diveintopython.org/regular_expressions/index.html] sometime. Or you can look at this [xkcd http://xkcd.com/208/].)
 
In addition to matching text, regular expressions can capture text. Capturing means to remember that part of the string, for later use. Regexes use parentheses () to wrap the parts they’re capturing.
 
For Django, when a regular expression matches the URL that a web surfer requests, Django extracts the captured values (if any) and passes them to a function of your choosing. This is the role of the callback function above. When a regular expression matches the url, Django calls the associated callback function with any captured parts as parameters. This will much clearer after the next section.
 
===Adding URLs to our urls.py===
 
When we ran <code>django-admin.py startproject mysite</code> to create the project, Django created a default URLconf file called `urls.py`.
 
* Write our URL mapping. Edit the file mysite/urls.py so it looks like this:
 
<code>urlpatterns = patterns('',<br>
(r'^questions/$', 'qandabear.views.index'),<br>
(r'^questions/(\d+)/$', 'qandabear.views.question'),<br>
(r'^questions/(\d+)/answers/(\d+)/edit/$', 'qandabear.views.edit_answer'),<br>
# Examples:<br>
# url(r'^$', 'myproject.views.home', name='home'),<br>
# url(r'^myproject/', include('myproject.foo.urls')),<br>
 
# Uncomment the admin/doc line below to enable admin documentation:<br>
# url(r'^admin/doc/', include('django.contrib.admindocs.urls')),<br>
 
# Uncomment the next line to enable the admin:<br>
# url(r'^admin/', include(admin.site.urls)),<br>
)</code>
 
Suppose a visitor goes to http://127.0.0.1:8000/questions/23/.
# which regex pattern is tripped?
# what function is then called?
# what arguments is that function called with?
 
* Save urls.py.
 
* Start the dev server and try that url out! What happens?
 
* Save and commit.
 
Review: When somebody requests a page from your Web site – say, “/questions/23/”, Django will load the urls.py Python module, because it’s pointed to by the ROOT_URLCONF setting. It finds the variable named urlpatterns and traverses the regular expressions in order. When it finds a regular expression that matches – r'^polls/(\d+)/$' – it loads the function question() from qandabear/views.py. Finally, it calls that module’s detail() function like so:
 
<code>detail(request=<HttpRequest object>, '23')</code>
 
The ‘23’ part comes from (\d+). Using parentheses around a pattern “captures” the text matched by that pattern and sends it as an argument to the view function; the \d+ is a regular expression to match a sequence of digits (i.e., a number).
 
The idea that a URL doesn’t have to map onto a file or a folder, or some other sort of static resource, is quite powerful. The URL is just a way of giving instructions to some server, somewhere.
 
(Rant: In Django, as in most modern frameworks, you have total control over the way your URLs look. People on the web won’t see cruft like .py or .php or even .html at the end of your URLs. There is no excuse for that kind of stuff in the modern era! (Though, putting .asp on the end of all your Django URLs, while pointless, is kind of hilarious and super easy.))
 
== views.py ==
Anonymous user
Cookies help us deliver our services. By using our services, you agree to our use of cookies.