python - gregg roetengreggroeten.com/pub-doc-soft/python-django-pycharm-designer-doc.pdfdjango (web...
Post on 26-Mar-2018
244 Views
Preview:
TRANSCRIPT
pg 1
Python
Django
(Web Application Framework - WAF)
PyCharm (Integration Development Environment - IDE)
Compiled and condensed notes from various online sources
Gregg Roeten
pg 2
Build Environment as of 09/10/2015
Windows 7
JetBrains PyCharm Community Edition 4.5.4 Build #PC0141.2569 Aug 28, 2015 JRE 1.8.0-51-b16x86 JVM: Java Hotspotserver Django 1.8.4 Python 3.4.3 Python SDKs, list of the interpreters available on your machine. PyCharm supports: Standard Python interpreters, IronPython, PyPy, Jython, Cpython Settings Project: MysiteProject Project Interpreter Package Version Latest Django 1.8 1.84 Pygments 2.0.2 2.0.2 pip 6.1.1 7.1.2 pudb 2015.2 2015.3 pytz 2015.2 2015.4 setuptools 15.2 18.3.1 urwid 1.3.0 1.3.0
pg 3
TABLE OF CONTENTS
PYTHON ............................................................................................ ERROR! BOOKMARK NOT DEFINED.
PYTHON GENERAL NOTES ..................................................................................................................... 6
PYTHON CODING STYLE FOR DJANGO............................................................................................. 9
Python style ........................................................................................................................................................................ 9
Template style ..................................................................................................................................................................... 9
View style ............................................................................................................................................................................ 9
Model style ......................................................................................................................................................................... 9
Use of django.conf.settings ............................................................................................................................................... 11
Miscellaneous ................................................................................................................................................................... 11
DJANGO .......................................................................................................................................................... 1
DJANGO WORKFLOW FOR URLS, TEMPLATES AND APPS ..................................................... 12
.......................................................................................................................................................................................... 12
DJANGO PROCESS FLOW - BRIEF ..................................................................................................... 13
PROCESS FLOW - DETAILED ............................................................................................................... 14
User requests a page - How does Django process a request? ........................................................................................... 14
Request reaches Request Middlewares .............................................................................................................................. 14
handler send dispatcher signal request_started ............................................................................................................... 14 handler’s _request_middleware ...................................................................................................................................... 14
ROOT_URLCONF .......................................................................................................................................................... 14 _view_middleware ......................................................................................................................................................... 15
Django template structure ............................................................................................................................................... 15 render template .............................................................................................................................................................. 15
view - create an instance of django.http.HttpResponse. ...................................................................................... 15 exception ....................................................................................................................................................................... 15 Still no HttpResponse ..................................................................................................................................................... 15
handler fires the dispatcher signal request_finished, ............................................................................................. 15
GIT SETUP ................................................................................................................................................... 16
pg 4
WSGI WEB SERVER GATEWAY INTERFACE .................................................................................. 17 urls.py and views.py....................................................................................................................................................... 17
M = Model = data ............................................................................................................................................................. 18
V = View = window on screen........................................................................................................................................... 18
C = Controller .................................................................................................................................................................. 18
CMS .................................................................................................................................................................................. 18
DATABASES ................................................................................................................................................ 19
SQLite............................................................................................................................................................................... 19 Substring matching and case sensitivity .......................................................................................................................... 19 Old SQLite and CASE expressions ................................................................................................................................. 20 Using newer versions of the SQLite DB-API 2.0 driver .................................................................................................. 20 “Database is locked” errors ............................................................................................................................................ 20 QuerySet.select_for_update() not supported.................................................................................................................... 20 “pyformat” parameter style in raw queries not supported ................................................................................................ 20 Parameters not quoted in connection.queries ................................................................................................................... 20
MODELS ....................................................................................................................................................... 22
Define Model .................................................................................................................................................................... 22
Using Models .................................................................................................................................................................... 22
ADMIN .......................................................................................................................................................... 23
View .................................................................................................................................................................................. 23
DJANGO - HOW TO START AND DESIGN WITH DJANGO.......................................................... 24
Normal Start Django ........................................................................................................................................................ 24
DB Web app - Setup ......................................................................................................................................................... 25
Configure and Create Database ....................................................................................................................................... 26
Create Python model ........................................................................................................................................................ 29
Synchronizing the Database ............................................................................................................................................. 30
Configuring the Admin Interface ..................................................................................................................................... 30
API.................................................................................................................................................................. 33
CUSTOMIZE USERS ................................................................................................................................. 36
Creating an admin user .................................................................................................................................................... 36
Customize admin form ..................................................................................................................................................... 36
TEMPLATES ............................................................................................................................................... 38 Web site /polls/34 ........................................................................................................................................................ 39
How to return an HttpResponse object............................................................................................................................ 40 How to differentiate the URL names between Multiple applications in a Django project .................................................. 41
pg 5
USE GENERIC VIEWS: LESS CODE IS BETTER ............................................................................. 44
pg 6
1. Why PyCharm
A. Python Code Editor
1. Syntax highlighting
2. auto indent, code reformat
3. code completion
4. go to declaration, find usages
5. code analysis, inspection
6. realtime error highlighting
7. Rename refactoring allows to perform global code changes safely and instantly. Local changes
within a file are performed in-place. Refactorings work in plain Python and Django projects.
8. Extract Method to break up longer methods, Extract Superclass, Push Up, Pull Down and
Move to move the methods and classes.
9.
B. Django IDE +JavaScript
1. IDE provides high-class capabilities for professional Web development with Django framework
and Google App Engine.
2. coding assistance, navigation
3. breakpoints inside Django templates. Stop web appl where you need
4. Javascript debugger
C. Run, Debug, Test
1. execute tasks from your manage.py file. Use 'Run manage.py task' action, enter a task name or
event part of it and select the one you need. Debugger is started the same way.
2. Test Your Code: a test file, a single test class, a method, or all tests in a folder.
3. Create setup.py quickly using a special dialog and easily launch tasks defined inside setup.py
4. Python testing frameworks: Unittest, Doctest, Nosetest, py.test and Attest.
5. embedded local terminal
6. version control integration, Mercurial, Subversion, Git, CVS
7. Univided UI
8. Customizable UI
9. Issue Trackers integration, GitHub tracker
10. Plugins
11. SQL support for (Django, Flask) etc, SQL statements into source code.
12. PyCharm does not enable you to create databases, but provides facilities to manage and query
them.
13. deployment servers-deploy your local applications to some remote server.
https://confluence.jetbrains.com/display/PYH/PyCharm+IDE+and+Python+Plugin+for+IntelliJ+IDEA
2. Deployment in PyCharm
Don’t be fooled “Deployment in PyCharm” is to deploy existing project on remote server. Upload project to a remote server. Running a copy on a separate server.
pg 7
Supported Languages
Python (Versions: 2.x, 3.x)
Jython
Cython
IronPython
PyPy
Javascript
CoffeScript
TypeScript
HTML/CSS
Django/Jinja2 templates
web2py templates
Chameleon templates
Gql
LESS/SASS/SCSS/HAML
Mako
Puppet
RegExp
Rest
SQL
XML
YAML
Frameworks & Libraries supported
Django
Flask
Google App Engine
web2py
Pyramid
wxPython, PyQt, PyGTK
SQLAlchemy
...
3. Python general notes Multithreading: No - single threaded: there are “threads”, but Global Interpreter Lock
(GIL) allows just one Python thread to execute at any given moment of time (except the case when one of threads awaits for IO completion).
everything is dynamic so Python doesn’t need generics.
dd your own “tags” (fields or methods) to nearly any object to change the behavior of third-party code.
Python’s decorators are definitely unbeatable in simplicity and flexibility.
use *args, **kwargs - for static languages to enumerate/pass call arguments.
“with” contexts in Python can process exceptions: __exit__ method there gets
pg 8
information about thrown exception.
pg 9
4. Python Coding style for Django
A. Python style
Use four spaces for indentation.
Use underscores, for variable, function and method names (i.e. poll.get_unique_voters(), not poll.getUniqueVoters).
Use InitialCaps for class names (or for factory functions that return classes).
Use convenience imports whenever available. For example, do this: from django.views.generic import View
Don’t do this:
from django.views.generic.base import View
B. Template style
In Django template code, put one (and only one) space between the curly brackets and the tag contents.
Do this:
{{ foo }}
Don’t do this:
{{foo}}
C. View style
In Django views, the first parameter in a view function should be called request.
Do this:
def my_view(request, foo):
# ...
Don’t do this:
def my_view(req, foo):
# ...
D. Model style
Field names should be all lowercase, using underscores instead of camelCase.
Do this:
class Person(models.Model):
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=40)
Don’t do this:
class Person(models.Model):
FirstName = models.CharField(max_length=20)
Last_Name = models.CharField(max_length=40)
The class Meta should appear after the fields are defined, with a single blank line separating the fields and the class definition.
Do this:
class Person(models.Model):
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=40)
class Meta:
verbose_name_plural = 'people'
pg 10
Don’t do this:
class Person(models.Model):
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=40)
class Meta:
verbose_name_plural = 'people'
Don’t do this, either:
class Person(models.Model):
class Meta:
verbose_name_plural = 'people'
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=40)
If you define a __str__ method (previously __unicode__ before Python 3 was supported), decorate the model class with python_2_unicode_compatible().
The order of model inner classes and standard methods should be as follows (noting that these are not all required):
All database fields
Custom manager attributes
class Meta
def __str__()
def save()
def get_absolute_url()
Any custom methods
If choices is defined for a given model field, define each choice as a tuple of tuples, with an all-uppercase name as a class attribute on the model. Example: class MyModel(models.Model):
DIRECTION_UP = 'U'
DIRECTION_DOWN = 'D'
DIRECTION_CHOICES = (
(DIRECTION_UP, 'Up'),
(DIRECTION_DOWN, 'Down'),
)
pg 11
E. Use of django.conf.settings
Modules should not in general use settings stored in django.conf.settings at the top level (i.e.
evaluated when the module is imported). The explanation for this is as follows:
Manual configuration of settings (i.e. not relying on the DJANGO_SETTINGS_MODULE
environment variable) is allowed and possible as follows:
from django.conf import settings
settings.configure({}, SOME_SETTING='foo')
However, if any setting is accessed before the settings.configure line, this will not work. (Internally,
settings is a LazyObject which configures itself automatically when the settings are accessed if it has not already been configured).
So, if there is a module containing some code as follows:
from django.conf import settings
from django.core.urlresolvers import get_callable
default_foo_view = get_callable(settings.FOO_VIEW)
...then importing this module will cause the settings object to be configured. That means that the
ability for third parties to import the module at the top level is incompatible with the ability to configure the settings object manually, or makes it very difficult in some circumstances.
Instead of the above code, a level of laziness or indirection must be used, such as
django.utils.functional.LazyObject,
django.utils.functional.lazy() or
lambda.
F. Miscellaneous
Mark all strings for internationalization;.
Remove import statements that are no longer used when you change code. flake8 will identify these imports for you. If an unused import needs to remain for backwards-compatibility, mark the end of with # NOQA to silence the flake8 warning.
Systematically remove all trailing whitespaces from your code as those add unnecessary bytes, add visual clutter to the patches and can also occasionally cause unnecessary merge conflicts. Some IDE’s can be configured to automatically remove them and most VCS tools can be set to highlight them in diff outputs.
Please don’t put your name in the code you contribute. Our policy is to keep contributors’ names in the AUTHORS file distributed with Django – not scattered throughout the codebase itself. Feel free to include a change to the AUTHORS file in your patch if you make more than a single trivial change.
pg 12
Django workflow for Urls, Templates and Apps
HttpRequest from user
Apps layer models.py and views.py in folder Application/template modifies content
MVC = View*
Templates layer DIRS TEMPLATES in settings.py files .html in templates/admin information layout MVC =View (Python definition*)
Database
Project uses SQLite could use MySQL, etc
MVC = Model
Use WSGI (Web Server Gateway Interface) wsgi.py
Dynamic info from customer
Static info from customer
urls layer
url resolution - uses regular expressions to route requests file urls.py in folders MysiteProject, Application/templates
MVC = Controller
Customer input PC Browser
HttpResponse to user
WSGI
Apache/ mod_python server, therefore Django handles
pg 13
5. Django process flow - brief 1. User requests a page, running on Apache/mod_python therefore Django handles
2. HttpRequest sent to Request Middlewares (request function) which could manipulate or answer the HttpRequest
3. If no answer, then resolve URL with ROOT URLCONF in settings.py, match = MysiteProject.urls and send view function.
4. If match, handler calls View Middlewares (view function), which could manipulate or answer the HttpRequest
5. The view function may access data through models, must return HttpResponse or exception.
6. All model-to-DB interactions are done via a manager
7. Views passed to the Template (base_site.html or index.html) for rendering
8. Template uses Filters and Tags (logic with html tags) to render the output
9. HttpResponse is sent to the Response Middlewares (get_response function)
10. The response is sent to the user’s browser.
For details of each step see below
pg 14
6. Process flow - detailed
A. User requests a page - How does Django process a request? If Apache/mod_python is the server setup, in which case the request is handed to Django by
mod_python creating an instance of django.core.handlers.modpython.ModPythonHandler.
The handler imports your Django settings file.
B. Request reaches Request Middlewares 4 possible actions process: request, view, response and exception.
_request_middleware is a list of the process_request methods (in each case these will be
the actual methods, so they are directly callable) from any middleware classes which
defined them.
_view_middleware is a list of the process_view methods from any middleware classes,
which defined them.
_response_middleware is a list of the process_response methods from any middleware
classes, which defined them.
_exception_middleware is a list of the process_exception methods from any middleware
classes, which defined them.
C. handler send dispatcher signal request_started
Then it instantiates a subclass of django.http.HttpRequest.
Once an HttpRequest of some sort exists, the handler calls its own get_response method,
passing the HttpRequest as the only argument.
handler’s _request_middleware
does is loop through the handler’s _request_middleware instance variable and call each
method in that list, passing in the HttpRequest instance as an argument.
get_response to return instance of django.http.HttpResponse, to handler’s _request_middleware
More commonly, though, the middleware methods applied here simply do some processing
and decide whether to add, remove or supplement attributes of the request.
D. ROOT_URLCONF
if Middlewares didn’t send a response, the handler next tries to resolve the requested URL.
It looks in the settings file for a setting called ROOT_URLCONF, and hands that, along with
a base URL of /, as arguments to create an instance of
django.core.urlresolvers.RegexURLResolver, then calls the RegexURLResolver‘s resolve
method with the requested URL path.
The URL resolver follows a simple pattern. For each item in the urlpatterns list generated by
the URL configuration file specified by the ROOT_URLCONF setting, it checks whether
the requested URL path matches that item’s regular expression; if so , there are
two options:
If the item has a call to include, the resolver chops off the bit of the URL that matched,
moves to the URL configuration file specified by the include and begins iterating over
the items in its urlpatterns list. Depending on the depth and modularity of your
URL hierarchy, this may be repeated several times.
Otherwise, the resolver returns three items: the view function specified by the matched
item, a list of non-named matched groups from the URL (to be used as positional
arguments for the view) and a dictionary of keyword arguments, built from a
combination of any named matched groups in the URL and any extra keyword
arguments specified in that line in the URLConf.
pg 15
If no matches are found, the resolver raises the exception
django.core.urlresolvers.Resolver404, a subclass of the exception django.http.Http404.
We’ll get to how that’s handled a little later on.
_view_middleware
knows the view function and what arguments to pass to it,
the handler looks at its _view_middleware list, and calls each method in that list, passing the
HttpRequest, the view function, the list of positional arguments for the view and the
dictionary of keyword arguments for the view.
Again, it’s possible for middleware to intervene at this stage and force the handler to
return immediately.
E. Django template structure
base_site.html extends admin/base_site.html, which is in PROJECT_DIR/template path
index.html extends admin/base_site.html, which is in
PROJECT_DIR/PoolsApplications/template path
render template
Loading the template to be rendered; is handled by the function
django.template.loader.get_template,
The get_template function returns an instance of django.template.Template, which is an
object containing the parsed template and methods for using it.
The return value of the Template‘s render method is a string, which is the concatenation of
the return values of the render methods of all the Template‘s constituent Nodes, called
in the order in which they occur in the Template.
F. view - create an instance of django.http.HttpResponse.
exception
get_response passing the HttpRequest and the exception as arguments.
one of those methods may instantiate and returns an HttpResponse.
Still no HttpResponse
The view might not have returned a value.
The view might have raised an exception that none of the middleware was able to deal with.
A middleware method that was trying to deal with an exception might have raised a new
exception itself.
Default get_response sends Http404
If DEBUG is False, page_not_found,
If the DEBUG setting is True, technical_500_response,
G. handler fires the dispatcher signal request_finished,
which is the absolute last call for anything that wanted to execute during the current request?
clean up
free any resources
pg 16
Git setup
create a working directory & navigate to it
$ mkdir custom-reg-tutorial
$ cd custom-reg-tutorial
download the git repo
# don't forget the . at the end!
$ git clone https://github.com/launchsaas/custom-reg-tutorial.
git for version control
GitHub for project management
1. GitHub's "Issues" for the following:
1. bug tracking
2. feature requests
3. planned features
4. release/version management
git-flow for git workflow
py.test for unit testing
https://www.jeffknupp.com/blog/2013/08/16/open-sourcing-a-python-project-the-right-way/
pg 17
WSGI Web Server Gateway Interface
WSGI is the Web Server Gateway Interface. A specification describes how a web server communicates with web applications, and how web applications can be chained together to process one request.
WSGI is a Python standard
Use a Web app framework. They all support WSGI at this point, which means you need to worry about configuration and deployment of your app, and nothing else.
urls.py and views.py
focus on urls.py and views.py that will process your urls and return the info you want as an http response.
e.g. urls.py
urlpatterns += patterns ('myapp.views',
url (r'^getstuff/$', ‘getstuff’),
)
in views.py
def getstuff (request):
do whatever in python
return HttpResponse (stuff to return)
pg 18
Python’s web service framework is based on MVC
1. Django uses MVC (Model View Controller) MVC (Model View Controller) used as the Design pattern, for definitions see below.
different from standard MVC definition
Framework itself, mechanism that sends a request to the appropriate view
M = Model = data
Database layer
Encapsulates application state
Responds to state queries
Notifies view of changes
V = View = window on screen
Different Django View and standard MVC view
selects which data to display and how to display it
renders the models
Requests updates
Allows controller to select view
handled by views.py and templates directory
C = Controller
Defines application behavior, based on user input, access model as needed
by following the URLConf and calling the appropriate Python function for the given URL
Isolates logic (Model) from the user interface(View)
CMS
Django is not a CMS, or any sort of “turnkey product” in and of itself. It’s a Web framework; it’s a programming tool that lets you build Web sites.
Django version Python versions 1.4 2.5, 2.6, 2.7 1.7, 1.8 2.7 and 3.2, 3.3, 3.4 1.9 2.7, 3.3, 3.4, 3.5
pg 19
2. Databases
You don't need to use database in Django projects. Django comes with some standardized architecture that follows MVC pattern (or MVT as sometimes described). This includes models, views, url dispatching, templates, etc.
Probably you need to do following things to accomplish your task:
create url definition in urls.py to some Django view
write Django view that call somehow your API and displays result as a web page
you don't need models and database at all
Small project usually consists of the web server and "back-end" code will run on the same system (initially, Windows system) as the UI.
creation of a basic poll application.
It’ll consist of two parts:
A public site that lets people view and vote in them.
An admin site that lets you add, change and delete polls.
If you plan to use Django’s manage.py migrate command to automatically create database tables for your models (after first installing Django and creating a project), you’ll need to ensure that Django has permission to create and alter tables in the database you’re using; if you plan to manually create the tables, you can simply grant Django SELECT, INSERT, UPDATE and DELETE permissions. After creating a database user with these permissions, you’ll specify the details in your project’s settings file, see DATABASES for details.
If you’re using Django’s testing framework to test database queries, Django will need permission to create a test database.
H. SQLite
SQLite provides an excellent development alternative for applications that are predominantly
read-only or require a smaller installation footprint. As with all database servers, though, there
are some differences that are specific to SQLite that you should be aware of.
Substring matching and case sensitivity
For all SQLite versions, there is some slightly counter-intuitive behavior when attempting to
match some types of strings. These are triggered when using the iexact or contain filters in Querysets. The behavior splits into two cases:
1. For substring matching, all matches are done case-insensitively. That is a filter such as
filter (name__contains="aa") will match a name of "Aabb".
2. For strings containing characters outside the ASCII range, all exact string matches are
performed case-sensitively, even when the case-insensitive options are passed into the query.
Therefore, the iexact filter will behave exactly the same as the exact filter in these cases.
Some possible workarounds for this are documented at sqlite.org, but they aren’t utilized by
the default SQLite backend in Django, as incorporating them would be fairly difficult to do
robustly. Thus, Django exposes the default SQLite behavior and you should be aware of this when doing case-insensitive or substring filtering.
pg 20
Old SQLite and CASE expressions
SQLite 3.6.23.1 and older contains a bug when handling query parameters in a CASE
expression that contains an ELSE and arithmetic.
SQLite 3.6.23.1 was released in March 2010, and most current binary distributions for
different platforms include a newer version of SQLite, with the notable exception of the Python 2.7 installers for Windows.
Using newer versions of the SQLite DB-API 2.0 driver
Django will use a pysqlite2 module in preference to sqlite3 as shipped with the Python
standard library if it finds one is available.
This provides the ability to upgrade both the DB-API 2.0 interface and SQLite 3 itself to
versions newer than the ones included with your particular Python binary distribution, if needed.
“Database is locked” errors
SQLite is meant to be a lightweight database, and thus can’t support a high level of
concurrency. OperationalError: database is locked errors indicate that your application is
experiencing more concurrency than SQLite can handle in default configuration. This error
means that one thread or process has an exclusive lock on the database connection and
another thread timed out waiting for the lock the be released.
Python’s SQLite wrapper has a default timeout value that determines how long the second
thread is allowed to wait on the lock before it times out and raises the OperationalError: database is locked error.
If you’re getting this error, you can solve it by:
Switching to another database backend. At a certain point SQLite becomes too “lite” for
real-world applications, and these sorts of concurrency errors indicate you’ve reached
that point.
Rewriting your code to reduce concurrency and ensure that database transactions are
short-lived.
Increase the default timeout value by setting the timeout database option: 'OPTIONS': {
# ...
'timeout': 20,
# ...
}
This will simply make SQLite wait a bit longer before throwing “database is locked” errors; it won’t really do anything to solve them.
QuerySet.select_for_update() not supported
SQLite does not support the SELECT ... FOR UPDATE syntax. Calling it will have no effect.
“pyformat” parameter style in raw queries not supported
For most backends, raw queries (Manager.raw() or cursor.execute()) can use the “pyformat”
parameter style, where placeholders in the query are given as '%(name)s' and the parameters are passed as a dictionary rather than a list. SQLite does not support this.
Parameters not quoted in connection.queries
sqlite3 does not provide a way to retrieve the SQL after quoting and substituting the
parameters. Instead, the SQL in connection.queries is rebuilt with a simple string
pg 21
interpolation. It may be incorrect. Make sure you add quotes where necessary before copying a query into an SQLite shell.
pg 22
3. Models single, definitive source of information about your data.
contains
essential fields
behaviors of the data you’re storing.
model maps to a single database table.
A. Define Model
ex. application named polls, contains file models.py
This example model defines a Person, which has a first_name and last_name:
from django.db import models
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
first_name and last_name are fields of the model.
Each field is specified as a class attribute,
each attributes maps to a database column.
model would create a database table like this:
CREATE TABLE myapp_person (
"id" serial NOT NULL PRIMARY KEY,
"first_name" varchar(30) NOT NULL,
"last_name" varchar(30) NOT NULL
);
B. Using Models
Tell Django how to use models
mysite\mysite\settings.py
function INSTALLED_APPS
add name of module that contains your models.py
ex ‘polls’,
run manage.py migrate
run manage.py makemigrations
C. Fields
Example: polls\models.py file
from django.db import models
class Musician(models.Model):
first_name = models.CharField(max_length=50)
pg 23
last_name = models.CharField(max_length=50)
instrument = models.CharField(max_length=100)
class Album(models.Model):
artist = models.ForeignKey(Musician)
name = models.CharField(max_length=100)
release_date = models.DateField()
num_stars = models.IntegerField()
4. Admin
Select an object then change it
let’s you write and register actions, simple functions that get called with a list of objects
A. View
All Django wants is that HttpResponse. Alternatively, an exception.
Each view is responsible for doing one of two things:
returning an HttpResponse object containing the content for the requested page, or
raising an exception such as Http404. The rest is up to you.
Your view can
read records from a database, or not.
use a template system such as Django’s – or
a third-party Python template system – or not.
generate a PDF file,
output XML,
create a ZIP file on the fly,
anything you want, using whatever Python libraries you want.
view is a “type” of Web page in your Django application that generally serves a specific function
and has a specific template. For example, in a blog application, you might have the following views:
Blog homepage – displays the latest few entries.
Entry “detail” page – permalink page for a single entry.
Year-based archive page – displays all months with entries in the given year.
Month-based archive page – displays all days with entries in the given month.
Day-based archive page – displays all entries in the given day.
Comment action – handles posting comments to a given entry.
In our poll application, we’ll have the following four views:
Question “index” page – displays the latest few questions.
Question “detail” page – displays a question text, with no results but with a form to vote.
Question “results” page – displays results for a particular question.
Vote action – handles voting for a particular choice in a particular question.
In Django, web pages and other content are delivered by views. Each view is represented by a
simple Python function (or method, in the case of class-based views). Django will choose a view
by examining the URL that’s requested (to be precise, the part of the URL after the domain name).
pg 24
Python - 2 methods to start and design with Python
Method 1
Use wordpad for editing .py files
Use Windows command prompt to run python commands, like server, etc
Method 2 - PyCharm Preferred method
PyCharm background and setup
PyCharm supports Django including
Dedicated project type
ability to run tasks from the manage.py utility
Django templates support (syntax and error highlighting, code completion, navigation, completion for block names, resolve and completion for custom tags and filters, and quick documentation for tags and filters).
Ability to create templates from usage.
Ability to debug Django templates.
Live templates (snippets) for the quick development of Django templates.
Run/debug configuration for Django server.
Navigation between views and templates.
Code insight support for Django ORM.
Code completion and resolve in
Start JetBrains - PyCharm Community Edition 4.0.6
Open project
pg 25
Normal Start for Django in PyCharm
open Terminal part of window and startup server
python manage.py runserver
project directory has manage.py
Django Python web server address http://127.0.0.1:8000/
DB Web app - Setup python -c "import Django; print(django.get_version())"
Python 3.3 latest release, Django 1.7, 1.8 is beta
pg 26
django-admin startproject mysite creates project mysite and directory structure
mysite/
manage.py
mysite/
__init__.py
settings.py
urls.py
wsgi.py
File Definitions in the Project view
mysite directory is a container for your project. In the Project view it is denoted with
bold font.
manage.py: This is a command-line utility that lets you interact with your Django
project.
The nested directory mysite is the actual Python package for your project.
mysite/_init_.py: This empty file tells Python that this directory should be considered a
Python package.
mysite/settings.py: This file contains configuration for your Django project.
mysite/urls.py: This file contains the URL declarations for your Django project. a
“table of contents” of your Django-powered site.
mysite/wsgi.py: This file defines an entry-point for WSGI-compatible web servers
to serve your project. See Appendix How to deploy with WSGI for more details.
polls/models.py: In this file, we'll create models for our application.
polls/views.py: In this file, we'll create views.
templates directory is by now empty. It should contain the template files.
The nested directory migrations contains by now only the package file _init_.py, but
will be used to propagate the changes you make to your models (adding a field, deleting a
model, etc.) into your database schema. Read the migrations description here.
Always remember we have two mysites, designated “inner” and “outer”
The outer mysite/ root directory is just a container for your project. rename it to anything
you like.
The inner mysite/ directory are the actual Python package for your project. Used to import anything inside it (e.g. mysite.urls).
Configure and Create Database edit mysite/settings.py
select the project tool window and press F4.
select DATABASES var click Ctrl+F,
ENGINE - add name of DB
set TIME_ZONE to your time zone.
Database Setup if you want a DB other than SQLite
If you wish to use another database, install the appropriate database bindings, and change the following keys in the DATABASES 'default' item to match your database connection settings:
ENGINE – Either 'django.db.backends.sqlite3', 'django.db.backends.postgresql_psycopg2', 'django.db.backends.mysql', or 'django.db.backends.oracle'. Other backends are also available.
NAME – The name of your database. If you’re using SQLite, the database will be a file on your computer; in that case, NAME should be the full absolute path, including filename, of that file. The default value, os.path.join(BASE_DIR, 'db.sqlite3'), will
pg 27
store the file in your project directory.
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': DATABASE_PATH,
}
}
If you are not using SQLite as your database, additional settings such as USER, PASSWORD, HOST must be added.
Note
If you’re using PostgreSQL or MySQL, make sure you’ve created a database by this point.
Do that with “CREATE DATABASE database_name”; within your database’s interactive prompt.
If you’re using SQLite, you don’t need to create anything beforehand - the database file will
be created automatically when it is needed. Used in this example.
DATABASE_PATH = os.path.join(PROJECT_PATH, 'rango.db')
Here, we have defined the default database to use the SQLite Django backend. This provides us
with access to the lightweight python database, SQLite, which is great for development purposes.
Set is the NAME key/value pair, which we have set to DATABASE_PATH. For SQLite databases, the
remaining keys of USER, PASSWORD, HOST and PORT are not required and can thus be safely
removed.
python manage.py migrate creates DB
python manage.py runserver starts development server, lightweight web server written in Python, incl
in Django for rapid dev, no need to config Apache
no cursor until you stop server
Launch Django Server in PyCharm python manage.py startapp polls Actually creates app
If you choose sqlite3,
just verify auto user credentials, port and host
just launch the runserver task of the manage.py utility:
press Ctrl+Alt+R, and enter task name in the pop-up frame:
add an application to a project,
run the startapp task of the manage.py utility
pg 28
(Tools→Run manage.py task - startapp on the main menu).
in browser http://127.0.0.1:8000/
works
Each application you write in Django consists of a Python package
Diff Projects vs. apps
app is a Web application that does something – e.g., a Weblog system, a database of
public records or a simple poll app.
project is a collection of configuration and apps for a particular Web site. A project can
contain multiple apps. An app can be in multiple projects.
Performing administrative functions
First thing, create a superuser. To do that, type the superuser command in the manage.py console,
specify your email address, and password:
server not running
python manage.py createsuperuser
smooth
smooth@smooth.com
smooth
pg 29
smooth
Create Python model Change your models (in models.py).
Run python manage.py makemigrations to create migrations for those changes
Run python manage.py migrate to apply those changes to the database.
Use separate commands to make and apply migrations to make your development easier,
they’re also useable by other developers and in production.
Create the two initial data models for the Mysite application.
Django’s object relational mapping (ORM) functions
Django encapsulates databases tables through models.
Essentially, a model is a Python object that describes your data model/table.
Instead of directly working on the database table via SQL, all you have to do is manipulate
the corresponding Python object.
Edit polls/models.py
In mysite/models.py, we will define two classes -
both of which must inherit from django.db.models.Model.
The two Python classes will be the definitions for models representing Questions and
Choices.
Define the Question and Choice models fields as follows:
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
def __unicode__(self):
return self.name
class Choice(models.Model):
question = models.ForeignKey(Question)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
ForeignKey, a field type that allows us to create a one-to-many relationship.
Some of the most commonly used are listed below.
pg 30
CharField, a field for storing character data (e.g. strings). Specify max_length to
provide a maximum number of characters the field can store.
URLField, much like a CharField, but designed for storing resource URLs. You may
also specify a max_length parameter.
IntegerField, which stores integers.
DateField, which stores a Python datetime.date.
Synchronizing the Database
Our models are defined, Django needs to create table in our database SQLlite.
$ python manage.py syncdb
Synchronize the DB, converts the Django models into SQL tables.
$ python manage.py shell
run from within your Django project’s root directory
aid for debugging purposes
This will start an instance of the Python interpreter and load in your project’s settings for
you.
Configuring the Admin Interface Activate Model
web-based administrative interface that allows us to browse and edit data stored within our
models and corresponding database tables.
configure the admin interface
then access it.
mysite/settings.py
change the INSTALLED_APPS setting to include the 'polls'
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'polls',
]
Now Django knows to include the polls app.
table django_admin_log is created
urls.py file.
URL pattern /admin/ points to the admin.site.urls module
pg 31
from django.conf.urls import patterns, include, url
from django.conf import settings
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
url(r'^rango/', include('rango.urls')),
url(r'^admin/', include(admin.site.urls)), # ADD THIS LINE
)
Django admin application needs to know which models we wish to make available to the admin interface.
admin.py
create a new python file in mysite application directory called admin.py.
Add
from django.contrib import admin
from mysite.models import Question, Choice
admin.site.register(Question)
admin.site.register(Choice)
This will register the models with the admin interface. I
start or restart the Django development server and visit:
Terminal
python manage.py runserver
smooth
smooth
http://127.0.0.1:8000/admin/.
Enter the superuser username and password (created when setting up database)
Following should be displayed
pg 32
The Django admin interface. Note the Mysite category, and the two models contained within.
python manage.py syncdb
python manage.py makemigrations polls
Django now sees changes or additions made
stored as a migration. To be physically migrated later
python manage.py sqlmigrate polls 0001
sqlmigrate doesn’t run the migration on your DB,
Only prints to the screen
Double check what Django will do.
The sqlmigrate command takes migration names and returns their SQL
Migrations for 'polls':
0001_initial.py:
- Create model Choice
- Create model Question
- Add field question to choice
output after command
BEGIN;
--
pg 33
-- Create model Choice
--
CREATE TABLE "polls_choice" (
"id" serial NOT NULL PRIMARY KEY,
"choice_text" varchar(200) NOT NULL,
"votes" integer NOT NULL
);
--
-- Create model Question
--
CREATE TABLE "polls_question" (
"id" serial NOT NULL PRIMARY KEY,
"question_text" varchar(200) NOT NULL,
"pub_date" timestamp with time zone NOT NULL
);
--
-- Add field question to choice
--
ALTER TABLE "polls_choice" ADD COLUMN "question_id" integer NOT NULL;
ALTER TABLE "polls_choice" ALTER COLUMN "question_id" DROP DEFAULT;
CREATE INDEX "polls_choice_7aa0f6ee" ON "polls_choice" ("question_id");
ALTER TABLE "polls_choice"
ADD CONSTRAINT "polls_choice_question_id_246c99a640fbbd72_fk_polls_question_id"
FOREIGN KEY ("question_id")
REFERENCES "polls_question" ("id")
DEFERRABLE INITIALLY DEFERRED;
COMMIT;
sqlmigrate
table names auto generated combining name of app- polls and lower case name of the
models - question and choice
primary keys auto gen
database field types auto set
python manage.py migrate
Actual migrate command,
Migrate any changes/tables created to DB
synchronizes the changes you made to your models with the schema in the database.
python manage.py check Check DB for errors
API
python manage.py shell
manage.py shell sets the DJANGO_SETTINGS_MODULE environment variable,
gives Django the Python import path to your mysite/settings.py file.
> from polls.models import Question, Choice
no information printed after entry
# Import the model classes we just wrote.
# No questions are in the system yet.
> Question.objects.all()
[]
# Create a new Question.
# Support for time zones is enabled in the default settings file, so
pg 34
# Django expects a datetime with tzinfo for pub_date. Use timezone.now()
# instead of datetime.datetime.now() and it will do the right thing.
> from django.utils import timezone
> q = Question(question_text="What's new?", pub_date=timezone.now())
> q.save()
# Save the object into the database. You have to call save() explicitly.
# Now it has an ID. Note that this might say "1L" instead of "1", depending
# on which database you're using. That's no biggie; it just means your
# database backend prefers to return integers as Python long integer
# objects.
> q.id
1
> q.question_text
# Access model field values via Python attributes.
"What's new?"
> q.pub_date
datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=<UTC>)
> q.question_text = "What's up?"
# Change values by changing the attributes, then calling save().
> q.save()
> Question.objects.all()
[<Question: Question object>]
# objects.all() displays all the questions in the database.
Wait a minute. <Question: Question object> is, utterly, an unhelpful representation of
this object. Let’s fix that by editing the Question model (in the polls/models.py file)
and adding a __unicode__() method to both Question and Choice:
It’s important to add __unicode__() methods to your models, not only for your own
convenience when dealing with the interactive prompt, but also because objects’ representations are used throughout Django’s automatically generated admin.
polls/models.py
import datetime
from django.db import models
from django.utils import timezone
class Question(models.Model):
# ...
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
python manage.py shell
new Python interactive shell
pg 35
> from polls.models import Question, Choice
# Make sure our __str__() addition worked.
> Question.objects.all()
[<Question: What's up?>]
# Django provides a rich database lookup API that's entirely driven by
# keyword arguments.
> Question.objects.filter(id=1)
[<Question: What's up?>]
> Question.objects.filter(question_text__startswith='What')
[<Question: What's up?>]
> from django.utils import timezone # Get the question that was published this year
> current_year = timezone.now().year
> Question.objects.get(pub_date__year=current_year)
<Question: What's up?>
> Question.objects.get(id=2) # Request an ID that doesn't exist, this will raise an exception
Traceback (most recent call last):
...
DoesNotExist: Question matching query does not exist.
> Question.objects.get(pk=1)
<Question: What's up?>
# Lookup by a primary key is the most common case, so Django provides a
# shortcut for primary-key exact lookups.
# The following is identical to Question.objects.get(id=1).
> q = Question.objects.get(pk=1) # Make sure our custom method worked.
> q.was_published_recently()
True
> q = Question.objects.get(pk=1)
# Give the Question a couple of Choices. The create call constructs a new
# Choice object, does the INSERT statement, adds the choice to the set
# of available choices and returns the new Choice object. Django creates
# a set to hold the "other side" of a ForeignKey relation
# (e.g. a question's choice) which can be accessed via the API.
> q.choice_set.all() Display any choices from the related object set -- none so far.
[]
# Create three choices.
> q.choice_set.create(choice_text='Not much', votes=0)
<Choice: Not much>
> q.choice_set.create(choice_text='The sky', votes=0)
<Choice: The sky>
pg 36
> c = q.choice_set.create(choice_text='Just hacking again', votes=0)
Choice objects have API access to their related Question objects.
> c.question
<Question: What's up?>
# And vice versa: Question objects get access to Choice objects.
> q.choice_set.all()
[<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]
> q.choice_set.count()
# The API automatically follows relationships as far as you need.
# Use double underscores to separate relationships.
# This works as many levels deep as you want; there's no limit.
# Find all Choices for any question whose pub_date is in this year
# (reusing the 'current_year' variable we created above).
> Choice.objects.filter(question__pub_date__year=current_year)
[<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]
# Let's delete one of the choices. Use delete() for that.
> c = q.choice_set.filter(choice_text__startswith='Just hacking')
> c.delete()
5. Customize Users
A. Creating an admin user
Django entirely automates creation of admin interfaces for models
python manage.py createsuperuser
already done
Tell the admin that Question objects have an admin interface.
open the polls/admin.py file, and edit it to look like this:
from django.contrib import admin
from .models import Question
admin.site.register(Question)
Forms automatically generated from the Question Model
B. Customize admin form
re-ordering the fields on the edit form.
Change admin.site.register(Question) line with:
open file polls/admin.py
from django.contrib import admin
pg 37
from .models import Question
class QuestionAdmin(admin.ModelAdmin):
fieldsets = [
(None, {'fields': ['question_text']}),
('Date information', {'fields': ['pub_date']}),
]
admin.site.register(Question, QuestionAdmin)
You’ll follow this pattern – create a model admin object, then pass it as the second
argument to admin.site.register() – any time you need to change the admin options
for an object.
This particular change above makes the “Publication date” come before the “Question” field:
collapse- long form need to hide fields. click (show) to see fields
class QuestionAdmin(admin.ModelAdmin):
fieldsets = [
(None, {'fields': ['question_text']}),
('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
]
Adding related objects
Add choices to Question admin page
Register Choice with admin like Question was registered in polls/admin.py
from django.contrib import admin
from .models import Choice, Question
# ...
admin.site.register(Choice)
python manage.py runserver
now have choice and question in admin page
ForeignKey is represented in the admin as a <select> box.
“Add Another” link next to “Question.” Every object with a ForeignKey relationship to
another gets this for free. When you click “Add Another,” you’ll get a popup window with
the “Add question” form. If you add a question in that window and click “Save,” Django will
save the question to the database and dynamically add it as the selected choice on the “Add choice” form you’re looking at
Add several Choices directly instead of one at a time
admin.py
Remove register() call, add ChoiceInline
pg 38
admin.site.register(Question)
admin.site.register(Choice)
class ChoiceInline(admin.StackedInline):
model = Choice
extra = 3
class QuestionAdmin(admin.ModelAdmin):
fieldsets = [
(None, {'fields': ['question_text']}),
('Date information', {'fields': ['pub_date'], 'classes':
['collapse']}),
]
inlines = [ChoiceInline]
admin.site.register(Question, QuestionAdmin)
more compact form polls/admin.py
class ChoiceInline(admin.TabularInline):
display individual fields.
By default, Django displays the str() of each object. But sometimes it’d be more helpful if we
could display individual fields. To do that, use the list_display admin option, which is a tuple
of field names to display, as columns, on the change list page for the object:
To do that, use the list_display admin option, which is a tuple of field names to display, as columns, on the change list page for the object:
polls/admin.py
class QuestionAdmin(admin.ModelAdmin):
# ...
list_display = ('question_text', 'pub_date', 'was_published_recently')
filter sidebar to filter changes list in the pub_date field:
polls/admin.py
list_filter = [‘pub_date’]
search_fields = ['question_text']
search capability
6. Templates in project directory (one with manage.py) create templates directory
mysite/settings.py change ‘DIRS’:[], to ‘DIRS’:[ os.path.join(BASE_DIR, 'templates')],
create admin directory inside templates
copy template = admin/base_site.html into the new admin directory
Customize template = Override template, change web page title to S____ K___ edit file base_site.html
H:\My Documents\- Soft langs, WAP, websites, Frameworks\- Python,
Django\mysite\templates\admin\base_site.html
note: django.contrib.admin is an application
Customize admin index page
admin/index.html. (Do the same as with admin/base_site.html in the previous section
pg 39
– copy it from the default directory to your custom template directory.)
Edit the file, and you’ll see it uses a template variable called app_list. That variable contains every installed Django app. Instead of using that, you can hard-code links to object-specific admin pages in whatever way you think is best.
polls/views.py
change HttpResponse
map it to a URL using polls/urls.py
create polls/urls.py from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.index, name='index'),
]
point the root URLConf to the polls.urls
create mysite/urls.py
from django.conf.urls import include, url
from django.contrib import admin
urlpatterns = [
url(r'^polls/', include('polls.urls')),
url(r'^admin/', include(admin.site.urls)),
]
Web site /polls/34
Django will load the mysite.urls
because it’s pointed to by the ROOT_URLCONF setting.
It finds the variable named urlpatterns and traverses the regular expressions in order.
They include() functions we are using simply reference other URLConf. Note that the regular expressions for the include() functions don’t have a $ (end-of-string match character) but rather a trailing slash. Whenever Django encounters include(), it chops off whatever part of the URL matched up to that point and sends the remaining string to the included URLConf for further processing.
The idea behind include() is to make it easy to plug-and-play URLs. Since polls are in their own URLConf (polls/urls.py), they can be placed under “/polls/”, or under “/fun_polls/”, or under “/content/polls/”, or any other path root, and the app will still work.
Here’s what happens if a user goes to “/polls/34/” in this system:
Django will find the match at '^polls/'
Then, Django will strip off the matching text ("polls/") and send the remaining text – "34/" –
to the ‘polls.urls’ URLConf for further processing which matches r'^(?P<question_id>[0-
9]+)/$' resulting in a call to the detail() view like so:
detail(request=<HttpRequest object>, question_id='34')
C. Django’s template system to separate the design from Python
use Django’s template system to separate the design from Python by creating a template that the view can use.
pg 40
First, create a directory called templates in your polls directory. Django will look for templates in there.
Your project’s TEMPLATES setting describes how Django will load and render templates. The default settings file configures a DjangoTemplates backend whose APP_DIRS option is set to True. By convention DjangoTemplates looks for a “templates” subdirectory in each of the INSTALLED_APPS. This is how Django knows to find the polls templates even though we didn’t modify the DIRS option,
reference http://django.readthedocs.org/en/latest/intro/tutorial03.html to create new folders, files, code to use new templates
Use the template system
Back to the detail() view for our poll application. Given the context variable question, here’s what the polls/detail.html template might look like:
polls/templates/polls/detail.html
<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
<li>{{ choice.choice_text }}</li>
{% endfor %}
</ul>
The template system uses dot-lookup syntax to access variable attributes. In the example of
{{ question.question_text }}, first Django does a dictionary lookup on the object question. Failing
that, it tries an attribute lookup – which works, in this case. If attribute lookup had failed, it
would’ve tried a list-index lookup.
Method-calling happens in the {% for %} loop: question.choice_set.all is interpreted as the
Python code question.choice_set.all(), which returns an iterable of Choice objects and is suitable
for use in the {% for %} tag.
D. How to return an HttpResponse object
A shortcut: render()
It’s a very common idiom to load a template, fill a context and return an HttpResponse object
with the result of the rendered template. Django provides a shortcut. Here’s the full index() view, rewritten:
Removing hardcoded URLs in templates
initial URL link in polls/index.html template:
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
because previously defined the name argument in the url() functions in the polls.urls
module, you can remove a reliance on specific URL paths defined in your url configurations by
using the {% url %} template tag:
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
The way this works is by looking up the URL definition as specified in the polls.urls module. You can see exactly where the URL name of ‘detail’ is defined below:
...
# the 'name' value as called by the {% url %} template tag
url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
...
If you want to change the URL of the polls detail view to something else, perhaps to something
like polls/specifics/12/ instead of doing it in the template (or templates) you would change
pg 41
it in polls/urls.py:
...
# added the word 'specifics'
url(r'^specifics/(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
...
How to differentiate the URL names between Multiple applications in a Django project
answer add namespaces to the root URLConf in mysite/urls.py with {% url %} tag
E. Template updates
open
polls/templates/polls/detail.html
<h1>{{ question.question_text }}</h1>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
{% for choice in question.choice_set.all %}
<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{
choice.id }}" />
<label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br />
{% endfor %}
<input type="submit" value="Vote" />
</form>
A quick rundown:
The above template displays a radio button for each question choice. The value of each radio button is the associated question choice’s ID. The name of each radio button is "choice". That means, when somebody selects one of the radio buttons and submits the form, it’ll send the POST data choice=# where # is the ID of the selected choice. This is the basic concept of HTML forms.
We set the form’s action to {% url 'polls:vote' question.id %}, and we set method="post". Using method="post" (as opposed to method="get") is very important, because the act of submitting this form will alter data server-side. Whenever you create a form that alters data server-side, use method="post". This tip isn’t specific to Django; it’s just good Web development practice.
forloop.counter indicates how many times the for tag has gone through its loop
Since we’re creating a POST form (which can have the effect of modifying data), we need to worry about Cross Site Request Forgeries. Thankfully, you don’t have to worry too hard, because Django comes with a very easy-to-use system for protecting against it. In short, all POST forms that are targeted at internal URLs should use the {% csrf_token %} template tag.
Need to create a Django view that handles the submitted data and does something with it. Add
the following:
polls/views.py
from django.shortcuts import get_object_or_404, render
from django.http import HttpResponseRedirect, HttpResponse
from django.core.urlresolvers import reverse
from .models import Choice, Question
# ...
def vote(request, question_id):
p = get_object_or_404(Question, pk=question_id)
try:
selected_choice = p.choice_set.get(pk=request.POST['choice'])
except (KeyError, Choice.DoesNotExist):
pg 42
# Redisplay the question voting form.
return render(request, 'polls/detail.html', {
'question': p,
'error_message': "You didn't select a choice.",
})
else:
selected_choice.votes += 1
selected_choice.save()
# Always return an HttpResponseRedirect after successfully dealing
# with POST data. This prevents data from being posted twice if a
# user hits the Back button.
return HttpResponseRedirect(reverse('polls:results', args=(p.id,)))
request.POST is a dictionary-like object that lets you access submitted data by key name. In this case, request.POST['choice'] returns the ID of the selected choice, as a string. request.POST values are always strings.
Note that Django also provides request.GET for accessing GET data in the same way – but we’re explicitly using request.POST in our code, to ensure that data is only altered via a POST call.
request.POST['choice'] will raise KeyError if choice wasn’t provided in POST data. The above code checks for KeyError and redisplays the question form with an error message if choice isn’t given.
After incrementing the choice count, the code returns an HttpResponseRedirect rather than a normal HttpResponse. HttpResponseRedirect takes a single argument: the URL to which the user will be redirected (see the following point for how we construct the URL in this case).
As the Python comment above points out, you should always return an HttpResponseRedirect after successfully dealing with POST data. This tip isn’t specific to Django; it’s just good Web development practice.
We are using the reverse() function in the HttpResponseRedirect constructor in this example. This function helps avoid having to hardcode a URL in the view function. It is given the name of the view that we want to pass control to and the variable portion of the URL pattern that points to that view. In this case, using the URLConf we set up in Tutorial 3, this reverse() call will return a string like
'/polls/3/results/'
... where the 3 is the value of p.id. This redirected URL will then call the 'results' view to display the final page.
request is a HttpRequest object.
After somebody votes in a question, the vote() view redirects to the results page for the
question. Let’s write that view:
polls/views.py
from django.shortcuts import get_object_or_404, render
def results(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/results.html', {'question': question})
This is almost exactly the same as the detail() view from Tutorial 3. The only difference is the
pg 43
template name. We’ll fix this redundancy later.
Now, create a polls/results.html template:
polls/templates/polls/results.html
<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
<li>{{ choice.choice_text }} -- {{ choice.votes }} vote{{
choice.votes|pluralize }}</li>
{% endfor %}
</ul>
<a href="{% url 'polls:detail' question.id %}">Vote again?</a>
Now, go to /polls/1/ in your browser and vote in the question. You should see a results page
that gets updated each time you vote. If you submit the form without having chosen a choice,
you should see the error message.
pg 44
7. Use generic views: Less code is better
These views represent a common case of basic Web development: getting data from the database according to a parameter passed in the URL, loading a template and returning the rendered template. Because this is so common, Django provides a shortcut, called the “generic views” system.
Generic views abstract common patterns to the point where you don’t even need to write Python code to write an app.
Let’s convert our poll app to use the generic views system, so we can delete a bunch of our own code. We’ll just have to take a few steps to make the conversion. We will:
Convert the URLConf.
Delete some of the old, unneeded views.
Introduce new views based on Django’s generic views.
Read on for details.
Why the code-shuffle?
Generally, when writing a Django app, you’ll evaluate whether generic views are a good fit for your problem, and you’ll use them from the beginning, rather than refactoring your code halfway through. But this tutorial intentionally has focused on writing the views “the hard way” until now, to focus on core concepts.
You should know basic math before you start using a calculator.
F. Amend URLConf
First, open the polls/urls.py URLConf and change it like so:
polls/urls.py from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.IndexView.as_view(), name='index'),
url(r'^(?P<pk>[0-9]+)/$', views.DetailView.as_view(), name='detail'),
url(r'^(?P<pk>[0-9]+)/results/$', views.ResultsView.as_view(), name='results'),
url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),
]
Note that the name of the matched pattern in the regexes of the second and third
patterns has changed from <question_id> to <pk>.
Amend views
Next, we’re going to remove our old index, detail, and results views and use Django’s
generic views instead. To do so, open the polls/views.py file and change it like so:
polls/views.py from django.shortcuts import get_object_or_404, render
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from django.views import generic
from .models import Choice, Question
class IndexView(generic.ListView):
template_name = 'polls/index.html'
context_object_name = 'latest_question_list'
def get_queryset(self):
pg 45
"""Return the last five published questions."""
return Question.objects.order_by('-pub_date')[:5]
class DetailView(generic.DetailView):
model = Question
template_name = 'polls/detail.html'
class ResultsView(generic.DetailView):
model = Question
template_name = 'polls/results.html'
def vote(request, question_id):
... # same as above
We’re using two generic views here: ListView and DetailView. Respectively, those two views
abstract the concepts of “display a list of objects” and “display a detail page for a particular type
of object.”
Each generic view needs to know what model it will be acting upon. This is provided using the
model attribute.
The DetailView generic view expects the primary key value captured from the URL to be called
"pk", so we’ve changed question_id to pk for the generic views.
By default, the DetailView generic view uses a template called <app name>/<model
name>_detail.html. In our case, it would use the template "polls/question_detail.html".
The template_name attribute is used to tell Django to use a specific template name instead of
the autogenerated default template name. We also specify the template_name for the results
list view – this ensures that the results view and the detail view have a different appearance when
rendered, even though they’re both a DetailView behind the scenes.
Similarly, the ListView generic view uses a default template called <app name>/<model
name>_list.html; we use template_name to tell ListView to use our existing
"polls/index.html" template.
In previous parts of the tutorial, the templates have been provided with a context that contains
the question and latest_question_list context variables. For DetailView the question variable is
provided automatically – since we’re using a Django model (Question), Django is able to
determine an appropriate name for the context variable. However, for ListView, the
automatically generated context variable is question_list. To override this we provide the
context_object_name attribute, specifying that we want to use latest_question_list instead. As an
alternative approach, you could change your templates to match the new default context variables – but it’s a lot easier to just tell Django to use the variable you want.
Run the server, and use your new polling app based on generic views.
pg 46
Standalone installers
Use pip to install Pyinstaller
PyCharm
Terminal
python --version
= 3.4.3
pip --version
= pip 7.1.2 from
C:\Program Files\Python
type pip install pyinstaller
H:\My Documents\Soft\Python\MysiteProject>pip install pyinstaller
You are using pip version 6.1.1, however version 7.1.2 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
Collecting pyinstaller
Downloading PyInstaller-2.1.tar.gz (4.8MB)
100% |################################| 4.8MB 70kB/s eta 0:00:011
Complete output from command python setup.py egg_info:
Traceback (most recent call last):
File "<string>", line 20, in <module>
File "C:\Users\owner\AppData\Local\Temp\pip-build-qmyqrcnm\pyinstaller\set
from PyInstaller import get_version
File "C:\Users\owner\AppData\Local\Temp\pip-build-qmyqrcnm\pyinstaller\PyI
from PyInstaller import compat
----------------------------------------
Command "python setup.py egg_info" failed with error code 1 in C:\Users
Start PyCharm run as Administrator
Terminal
Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation. All rights reserved.
H:\My Documents\Soft\Python\MysiteProject>pip install --upgrade pip
Requirement already up-to-date: pip in c:\program files\python\lib\site-packages
H:\My Documents\Soft\Python\MysiteProject>
H:\My Documents\Soft\Python\MysiteProject>pip install pyinstaller
Collecting pyinstaller
Using cached PyInstaller-2.1.tar.gz
Complete output from command python setup.py egg_info:
Traceback (most recent call last):
File "<string>", line 20, in <module>
File "C:\Users\owner\AppData\Local\Temp\pip-build-
z2ojb2f4\pyinstaller\setup.py", line 18, in <module>
from PyInstaller import get_version
File "C:\Users\owner\AppData\Local\Temp\pip-build-
z2ojb2f4\pyinstaller\PyInstaller\__init__.py", line 32, in <module>
from PyInstaller import compat
File "C:\Users\owner\AppData\Local\Temp\pip-build-
z2ojb2f4\pyinstaller\PyInstaller\compat.py", line 129
if sys.maxint > 2L ** 32:
^
SyntaxError: invalid syntax
----------------------------------------
Command "python setup.py egg_info" failed with error code 1 in
C:\Users\owner\AppData\Local\Temp\pip-build-z2ojb2f4\pyinstaller
pg 47
pyinstaller incompatible with python 3 so use newest
use pyinstaller python3 branch on github
pip3 install https://github.com/pyinstaller/pyinstaller/archive/python3.zip
H:\My Documents\Soft\Python\MysiteProject>pip3 install
https://github.com/pyinstaller/pyinstaller/archive/python3.zip
Collecting https://github.com/pyinstaller/pyinstaller/archive/python3.zip
Downloading https://github.com/pyinstaller/pyinstaller/archive/python3.zip
\ 3.1MB 682kB/ss
Requirement already satisfied (use --upgrade to upgrade): setuptools in c:\program
files\python\lib\site-packages\setuptools-18.3.1-py3.4.egg (from
PyInstaller==3.0.dev1)
Collecting pypiwin32 (from PyInstaller==3.0.dev1)
Downloading pypiwin32-219-cp34-none-win_amd64.whl (8.6MB)
100% |################################| 8.6MB 43kB/s eta 0:00:01
Installing collected packages: pypiwin32, PyInstaller
Running setup.py install for PyInstaller
Successfully installed PyInstaller-3.0.dev1 pypiwin32-219
H:\My Documents\Soft\Python\MysiteProject>
PyInstaller - Successfully installed PyInstaller-3.0.dev1 pypiwin32-219
pip is the preferred installer program. Starting with Python 2.7.9, it is included by default with the Python binary installers.
distutils is the original build and distribution system first added to the Python standard library in 1998. While direct use of distutils is being phased out, it still laid the foundation for the current packaging and distribution infrastructure, and it not only remains part of the standard library, but its name lives on in other ways (such as the name of the mailing list used to coordinate Python packaging standards development).
Create a simple app.py file, prints hello world
Python Console, working commands
Pycharm run command, green triangle or run menu option
output to Python Console
from app.py import *
ran perfect 1st time in Python Console, doesn’t work if tried again
highlight code, rt click, run selection
ran perfect in Python Console
Python Console, not commands working
pg 48
noticed pyCharm 4.5.4\helpers\pydev\pydevconsole.py
PyDev Console: starting
64 bit AMD64 on win32
Pyinstaller installed
pyinstaller.exe --onefile --windowed app.py
1. Distutils
A. An Introduction ¶
https://docs.python.org/3.5/distutils/introduction.html#concepts-terminology
ex. distribute a module ( source distribution , not executable) for this module, you would called
foo, contained in a file called foo.py then write your setup script thus:
create a setup script, setup.py,
from distutils.core import setup
setup(name='foo',
version='1.0',
py_modules=['foo'],
)
Windows, open a command prompt window (Start ‣ Accessories) and enter:
setup.py sdist
Or, from the PyCharm Terminal :
python setup.py sdist
sdist will create an archive file (e.g., tarball on Unix, ZIP file on Windows) containing your setup
script setup.py, and your module foo.py. The archive file will be named foo-1.0.tar.gz (or .zip), and will unpack into a directory foo-1.0.
If an end-user wishes to install your foo module, all she has to do is download foo-1.0.tar.gz (or
.zip), unpack it, and—from the foo-1.0 directory—run
python setup.py install
which will ultimately copy foo.py to the appropriate directory for third-party modules in their
Python installation.
B. Concepts & Terminology
Using the Distutils is quite simple, both for module developers and for users/administrators
installing third-party modules. As a developer, your responsibilities (apart from writing solid,
well-documented and well-tested code, of course!) are:
pg 49
write a setup script (setup.py by convention)
(optional) write a setup configuration file
create a source distribution
(optional) create one or more built (binary) distributions
C. A Simple Example
If all you want to do is distribute a module called foo, contained in a file foo.py, then your
setup script can be as simple as this:
from distutils.core import setup
setup(name='foo',
version='1.0',
py_modules=['foo'],
)
those keyword arguments fall into two categories: package metadata (name, version number) and information about what’s in the package (a list of pure Python modules, in this case)
modules are specified by module name, not filename (the same will hold true for packages and extensions)
To create a source distribution for this module, you would create a setup script, setup.py, containing the above code, and run this command from a terminal:
python setup.py sdist
For Windows, open a command prompt window (Start ‣ Accessories) and change the command
to:
setup.py sdist
sdist will create an archive file (e.g., tarball on Unix, ZIP file on Windows) containing your
setup script setup.py, and your module foo.py. The archive file will be named foo-
1.0.tar.gz (or .zip), and will unpack into a directory foo-1.0.
If an end-user wishes to install your foo module, all she has to do is download foo-1.0.tar.gz
(or .zip), unpack it, and—from the foo-1.0 directory—run
python setup.py install
which will ultimately copy foo.py to the appropriate directory for third-party modules in their Python installation.
This simple example demonstrates some fundamental concepts of the Distutils. First, both
developers and installers have the same basic user interface, i.e. the setup script. The difference
is which Distutils commands they use: the sdist command is almost exclusively for module
developers, while install is more often for installers (although most developers will want to
install their own code occasionally).
If you want to make things really easy for your users, you can create one or more built
distributions for them. For instance, if you are running on a Windows machine, and want to make
things easy for other Windows users, you can create an executable installer (the most appropriate
type of built distribution for this platform) with the bdist_wininst command. For example:
python setup.py bdist_wininst
pg 50
will create an executable installer, foo-1.0.win32.exe, in the current directory.
Other useful built distribution formats are RPM, implemented by the bdist_rpm command,
Solaris pkgtool (bdist_pkgtool), and HP-UX swinstall (bdist_sdux). For example, the
following command will create an RPM file called foo-1.0.noarch.rpm:
python setup.py bdist_rpm
(The bdist_rpm command uses the rpm executable, therefore this has to be run on an RPM-
based system such as Red Hat Linux, SuSE Linux, or Mandrake Linux.)
You can find out what distribution formats are available at any time by running
python setup.py bdist --help-formats
D. General Python terminology
If you’re reading this document, you probably have a good idea of what modules, extensions,
and so forth are. Nevertheless, just to be sure that everyone is operating from a common starting point, we offer the following glossary of common Python terms:
1. module
the basic unit of code reusability in Python: a block of code imported by some other code.
Three types of modules concern us here: pure Python modules, extension modules, and
packages.
2. pure Python module
a module written in Python and contained in a single .py file (and possibly associated .pyc
files). Sometimes referred to as a “pure module.”
3. extension module
a module written in the low-level language of the Python implementation: C/C++ for Python,
Java for Jython. Typically contained in a single dynamically loadable pre-compiled file, e.g. a
shared object (.so) file for Python extensions on Unix, a DLL (given the .pyd extension) for
Python extensions on Windows, or a Java class file for Jython extensions. (Note that
currently, the Distutils only handles C/C++ extensions for Python.)
4. package
a module that contains other modules; typically contained in a directory in the filesystem and
distinguished from other directories by the presence of a file __init__.py.
5. root package
the root of the hierarchy of packages. (This isn’t really a package, since it doesn’t have an
__init__.py file. But we have to call it something.) The vast majority of the standard
library is in the root package, as are many small, standalone third-party modules that don’t
belong to a larger module collection. Unlike regular packages, modules in the root package
can be found in many directories: in fact, every directory listed in sys.path contributes modules to the root package.
E. Distutils-specific terminology
The following terms apply more specifically to the domain of distributing Python modules using
the Distutils:
1. module distribution
a collection of Python modules distributed together as a single downloadable resource and
pg 51
meant to be installed en masse. Examples of some well-known module distributions are
NumPy, SciPy, PIL (the Python Imaging Library), or mxBase. (This would be called a
package, except that term is already taken in the Python context: a single module distribution may contain zero, one, or many Python packages.)
2. pure module distribution
a module distribution that contains only pure Python modules and packages. Sometimes
referred to as a “pure distribution.”
3. non-pure module distribution
a module distribution that contains at least one extension module. Sometimes referred to as a
“non-pure distribution.”
4. distribution root
the top-level directory of your source tree (or source distribution); the directory where
setup.py exists. Generally setup.py will be run from this directory.
2. Create Built Distributions
Python organization recommends https://docs.python.org/3.5/distutils/builtdist.html
“built distribution” is the term used because
not “binary package” because not necessarily binary, it might contain only Python source or byte code.
not package, because that word is already spoken for in Python.
not “installer” is a term specific to the world of mainstream desktop systems.
therefore use build distribution
RPM-based Linux systems, it’s a binary RPM;
Windows users, it’s an executable installer;
Debian-based Linux users, it’s a Debian package;
and so forth.
Distutils are designed to enable module developers to concentrate on their specialty—writing
code and creating source distributions—while an intermediary species called packagers springs
up to turn source distributions into built distributions for as many platforms as there are packagers.
a packager uses the setup script and the bdist command family to generate built distributions.
As a simple example, if I run the following command in the Distutils source tree:
python setup.py bdist
then the Distutils builds my module distribution (the Distutils itself in this case), does a “fake”
installation (also in the build directory), and creates the default type of built distribution for my
platform. The default format for built distributions is a tar file on Unix, and a simple executable
installer on Windows.
Thus, the above command on a Unix system creates Distutils-1.0.plat.tar.gz; unpacking
this tarball from the right place installs the Distutils just as though you had downloaded the
source distribution and run python setup.py install. (The “right place” is either the root of
the filesystem or Python’s prefix directory, depending on the options given to the bdist_dumb
command; the default is to make dumb distributions relative to prefix.)
Obviously, for pure Python distributions, this isn’t any simpler than just running python
setup.py install—but for non-pure distributions, which include extensions that would need
to be compiled, it can mean the difference between someone being able to use your extensions or
pg 52
not. And creating “smart” built distributions, such as an RPM package or an executable installer
for Windows, is far more convenient for users even if your distribution doesn’t include any
extensions.
The bdist command has a --formats option, similar to the sdist command, which you can use to
select the types of built distribution to generate: for example,
pg 53
python setup.py bdist --format=zip
would, when run on a Unix system, create Distutils-1.0.plat.zip—again, this archive
would be unpacked from the root directory to install the Distutils.
The available formats for built distributions are:
Format Description Notes
gztar gzipped tar file (.tar.gz) (1)
bztar bzipped tar file (.tar.bz2)
xztar xzipped tar file (.tar.xz)
ztar compressed tar file (.tar.Z) (3)
tar tar file (.tar)
zip zip file (.zip) (2),(4)
rpm RPM (5)
pkgtool Solaris pkgtool
sdux HP-UX swinstall
wininst self-extracting ZIP file for Windows (4)
msi Microsoft Installer.
Changed in version 3.5: Added support for the xztar format.
Notes:
1. default on Unix
2. default on Windows
3. requires external compress utility.
4. requires either external zip utility or zipfile module (part of the standard Python library since
Python 1.6)
5. requires external rpm utility, version 3.0.4 or better (use rpm --version to find out which version
you have)
You don’t have to use the bdist command with the --formats option; you can also use the
command that directly implements the format you’re interested in. Some of these bdist “sub-
commands” actually generate several similar formats; for instance, the bdist_dumb
command generates all the “dumb” archive formats (tar, gztar, bztar, xztar, ztar, and
zip), and bdist_rpm generates both binary and source RPMs. The bdist sub-commands, and
the formats generated by each, are:
Command Formats
bdist_dumb tar, gztar, bztar, xztar, ztar, zip
bdist_rpm rpm, srpm
bdist_wininst wininst
bdist_msi msi
The following sections give details on the individual bdist_* commands.
5. Creating RPM packages
The RPM format is used by many popular Linux distributions, including Red Hat, SuSE, and
Mandrake. If one of these (or any of the other RPM-based Linux distributions) is your usual
environment, creating RPM packages for other users of that same distribution is trivial.
Depending on the complexity of your module distribution and differences between Linux
pg 54
distributions, you may also be able to create RPMs that work on different RPM-based distributions.
The usual way to create an RPM of your module distribution is to run the bdist_rpm
command:
python setup.py bdist_rpm
or the bdist command with the --format option:
python setup.py bdist --formats=rpm
The former allows you to specify RPM-specific options; the latter allows you to easily
specify multiple formats in one run. If you need to do both, you can explicitly specify
multiple bdist_* commands and their options:
python setup.py bdist_rpm --packager="John Doe <jdoe@example.org>" \
bdist_wininst --target-version="2.0"
Creating RPM packages is driven by a .spec file, much as using the Distutils is driven by the
setup script. To make your life easier, the bdist_rpm command normally creates a .spec file
based on the information you supply in the setup script, on the command line, and in any
Distutils configuration files. Various options and sections in the .spec file are derived from options in the setup script as follows:
Additionally, there are many options in .spec files that don’t have corresponding options in
the setup script. Most of these are handled through options to the bdist_rpm command as follows:
RPM .spec file
option or section bdist_rpm option default value
Release release “1”
Group group “Development/Libraries”
Vendor vendor (see above)
Packager packager (none)
Provides provides (none)
Requires requires (none)
Conflicts conflicts (none)
RPM .spec file option or
section Distutils setup script option
Name name
Summary (in preamble) description
Version version
Vendor author and author_email, or — & maintainer
and maintainer_email
Copyright license
Url url
%description (section) long_description
pg 55
RPM .spec file
option or section bdist_rpm option default value
Obsoletes obsoletes (none)
Distribution distribution_name (none)
BuildRequires build_requires (none)
Icon icon (none)
Obviously, supplying even a few of these options on the command-line would be tedious and
error-prone, so it’s usually best to put them in the setup configuration file, setup.cfg—see
section Writing the Setup Configuration File. If you distribute or package many Python
module distributions, you might want to put options that apply to all of them in your personal
Distutils configuration file (~/.pydistutils.cfg). If you want to temporarily disable this
file, you can pass the --no-user-cfg option to setup.py.
There are three steps to building a binary RPM package, all of which are handled automatically by the Distutils:
6. create a .spec file, which describes the package (analogous to the Distutils setup script; in fact,
much of the information in the setup script winds up in the .spec file)
7. create the source RPM
8. create the “binary” RPM (which may or may not contain binary code, depending on whether your
module distribution contains Python extensions)
Normally, RPM bundles the last two steps together; when you use the Distutils, all three
steps are typically bundled together.
If you wish, you can separate these three steps. You can use the --spec-only option to make
bdist_rpm just create the .spec file and exit; in this case, the .spec file will be written to
the “distribution directory”—normally dist/, but customizable with the --dist-dir option.
(Normally, the .spec file winds up deep in the “build tree,” in a temporary directory created by bdist_rpm.)
6. Creating Windows Installers
Executable installers are the natural format for binary distributions on Windows. They
display a nice graphical user interface, display some information about the module
distribution to be installed taken from the metadata in the setup script, let the user select a few options, and start or cancel the installation.
Since the metadata is taken from the setup script, creating Windows installers is usually as
easy as running:
python setup.py bdist_wininst
or the bdist command with the --formats option:
python setup.py bdist --formats=wininst
If you have a pure module distribution (only containing pure Python modules and packages),
the resulting installer will be version independent and have a name like foo-1.0.win32.exe. These installers can even be created on Unix platforms or Mac OS X.
If you have a non-pure distribution, the extensions can only be created on a Windows
platform, and will be Python version dependent. The installer filename will reflect this and
now has the form foo-1.0.win32-py2.0.exe. You have to create a separate installer for every Python version you want to support.
The installer will try to compile pure modules into bytecode after installation on the target
system in normal and optimizing mode. If you don’t want this to happen for some reason,
pg 56
you can run the bdist_wininst command with the --no-target-compile and/or the --no-target-optimize option.
By default the installer will display the cool “Python Powered” logo when it is run, but you
can also supply your own 152x261 bitmap which must be a Windows .bmp file with the --bitmap option.
The installer will also display a large title on the desktop background window when it is run,
which is constructed from the name of your distribution and the version number. This can be changed to another text by using the --title option.
The installer file will be written to the “distribution directory” — normally dist/, but customizable with the --dist-dir option.
7. Cross-compiling on Windows
Starting with Python 2.6, distutils is capable of cross-compiling between Windows platforms.
In practice, this means that with the correct tools installed, you can use a 32bit version of
Windows to create 64bit extensions and vice-versa.
To build for an alternate platform, specify the --plat-name option to the build command.
Valid values are currently ‘win32’, ‘win-amd64’ and ‘win-ia64’. For example, on a 32bit
version of Windows, you could execute:
python setup.py build --plat-name=win-amd64
to build a 64bit version of your extension. The Windows Installers also support this option, so the command:
python setup.py build --plat-name=win-amd64 bdist_wininst
would create a 64bit installation executable on your 32bit version of Windows.
To cross-compile, you must download the Python source code and cross-compile Python
itself for the platform you are targeting - it is not possible from a binary installation of
Python (as the .lib etc file for other platforms are not included.) In practice, this means the
user of a 32 bit operating system will need to use Visual Studio 2008 to open the
PCBuild/PCbuild.sln solution in the Python source tree and build the “x64” configuration of the ‘pythoncore’ project before cross-compiling extensions is possible.
Note that by default, Visual Studio 2008 does not install 64bit compilers or tools. You may
need to reexecute the Visual Studio setup process and select these tools (using Control Panel-
>[Add/Remove] Programs is a convenient way to check or modify your existing install.)
8. The Postinstallation script
Starting with Python 2.3, a postinstallation script can be specified with the --install-script
option. The basename of the script must be specified, and the script filename must also be
listed in the scripts argument to the setup function.
This script will be run at installation time on the target system after all the files have been
copied, with argv[1] set to -install, and again at uninstallation time before the files are
removed with argv[1] set to -remove.
The installation script runs embedded in the windows installer, every output (sys.stdout,
sys.stderr) is redirected into a buffer and will be displayed in the GUI after the script has
finished.
Some functions especially useful in this context are available as additional built-in functions
in the installation script.
directory_created(path)
pg 57
file_created(path)
These functions should be called when a directory or file is created by the postinstall script at
installation time. It will register path with the uninstaller, so that it will be removed when the
distribution is uninstalled. To be safe, directories are only removed if they are empty.
get_special_folder_path(csidl_string)
This function can be used to retrieve special folder locations on Windows like the Start Menu
or the Desktop. It returns the full path to the folder. csidl_string must be one of the following
strings:
"CSIDL_APPDATA"
"CSIDL_COMMON_STARTMENU"
"CSIDL_STARTMENU"
"CSIDL_COMMON_DESKTOPDIRECTORY"
"CSIDL_DESKTOPDIRECTORY"
"CSIDL_COMMON_STARTUP"
"CSIDL_STARTUP"
"CSIDL_COMMON_PROGRAMS"
"CSIDL_PROGRAMS"
"CSIDL_FONTS"
If the folder cannot be retrieved, OSError is raised.
Which folders are available depends on the exact Windows version, and probably also the
configuration. For details refer to Microsoft’s documentation of the
SHGetSpecialFolderPath() function.
create_shortcut(target, description, filename[, arguments[, workdir[,
iconpath[, iconindex]]]])
This function creates a shortcut. target is the path to the program to be started by the shortcut.
description is the description of the shortcut. filename is the title of the shortcut that the user
will see. arguments specifies the command line arguments, if any. workdir is the working
directory for the program. iconpath is the file containing the icon for the shortcut, and
iconindex is the index of the icon in the file iconpath. Again, for details consult the Microsoft
documentation for the IShellLink interface.
Major problem upgrading to Python 3.5.0a2
python.exe - Entry Point Not Found
“The procedure entry point ucrtbase.abort could not be located in the dynamic link library
api-ms-crt-runtime-l1-1-0.dll
few others with same error, not all python. problem in ucrtbase.abort is the problem
uninstall 3.5, restart, reinstall 3.5 (owner/appdata), restart, error
uninstall 3.5, restart, reinstall all users (program files), restart, error
pg 58
uninstall Visual C++ redist, restart, install, restart, error
download .dll, backedup existing copy, copied new .dll to windows/system32 dir, restart,
install 3.4.3, restart, WORKS Great 6 hr job!!!!!!!!
3. Setup after software delivery to client
Python 3.4.3
upgraded to 3.5.0a2 reference problems above, reinstalled 3.4
C:\Python34\ 9/14/15
from Pycharm C:\Users\owner\.PyCharm40 (5/12/15 )
to JetBrains PyCharm Community Edition 4.5.4 C:\Program Files
(x86)\JetBrains\PyCharm Community Edition 4.5.4\bin\pycharm.exe"
C:\Users\owner\PycharmProjects 9/13/15
Updated Environment Variables for Python
4. Vista User Access Control (UAC)
Starting with Python 2.6, bdist_wininst supports a --user-access-control option. The default is
‘none’ (meaning no UAC handling is done), and other valid values are ‘auto’ (meaning prompt
for UAC elevation if Python was installed for all users) and ‘force’ (meaning always prompt for
elevation).
5. WinPython and Inno Setup as a single-file .exe installer.
No dependencies, no prerequisites
installs a full standalone, isolated Python distribution, into C:\Program Files\MyApp\ like a regular program.
The end-user does not even need to know that the software is written in Python
This solution can be summarized in two words: WinPython and Inno Setup.
WinPython is a free scientific Python distribution for Windows that is portable, meaning that it is
completely isolated from the rest of the system. WinPython can be installed in a folder, which
can be moved anywhere, even on an USB stick, remaining entirely functional. WinPython is
bundled with a lot of existing Python packages, but the huge advantage is that it includes
graphical and command-line utilities to install/uninstall any Python package easily (from a zip or Windows binary installer generated by distutils).
Inno Setup is a free software for creating Windows installers. Building an installer requires to
write a plain text script that contains the instructions about what to install and where. It has a lot
of features, including desktop and start menu shortcuts, post-install scripts, etc. A wizard allows one to get started quickly and easily.
pg 59
Here is a summary of what you need to do to create an installer for your Python application.
First, create a folder with a WinPython distribution including all your Python dependencies, and
your own Python package as well. Second, create an installer that will just copy this folder
somewhere on the end-user hard drive, along with shortcuts to run your application. Then, you
can customize the installation process as you wish.
Step 1: customize your WinPython distribution
Create a folder named MyApplication somewhere on your development machine. This
folder will be copied to C:\Program Files\MyApplication by the installer.
Download and install WinPython into, say, MyApplication\WinPython-64bit-
2.7.5.0.
WinPython contains a GUI that lets you install/uninstall Python packages. There are a lot
of packages built in, but you can remove those that you don't need for your application.
You can also add new Python packages by dragging zip or exe installers (created with
distutils) into the GUI.
Step 2: create the installer
Install Inno Setup.
Use the wizard to create a new installer file (it is just a .iss text file).
Tell the wizard to copy your folder MyApplication to C:\Program
Files\MyApplication. The ISS code for this looks like this: [Files]
Source: "D:\Dev\MyApplication"; DestDir: "{app}"; Flags: ignoreversion
recursesubdirs createallsubdirs
Note the {app} variable which contains the user application path. See the list of Inno
Setup constants here.
Step 3: create the shortcuts
Create some shortcuts. Here is the ISS code to create a shorcut in the Start menu
launching a Python GUI application: [Icons]
Name: "{group}\Application"; Filename: "{app}\WinPython-64bit-
2.7.5.0\python-2.7.5.amd64\pythonw.exe"; WorkingDir: "{app}"; Parameters:
"""{app}\WinPython-64bit-2.7.5.0\python-2.7.5.amd64\Lib\site-
packages\myapplication\scripts\runmyapp.py"""; IconFilename:
"{app}\favicon.ico"
This code snippet assumes that the Python script running your application is in
myapplication\scripts\runmyapp.py. You could also have this script somewhere directly
in your application folder and not necessarily in your Python package. You can also specify
an icon as a .ico file.
You can create shortcuts on the desktop too. See more details here.
Step 4: customize the installation process
Inno Setup allows you to customize the installation process as you wish. Together with
Python scripts, you can really achieve anything. For instance, here is how you can run a
Python script at the end of the installation process.
[Run]
Filename: "{app}\WinPython-64bit-2.7.5.0\python-2.7.5.amd64\python.exe";
WorkingDir: "{app}"; Parameters: """{app}\postinstall.py"""; Flags:
runhidden
Here are a few directives that you can use to customize some aspects of the installation
wizard (icon, images, colors...):
pg 60
[Setup]
SetupIconFile=D:\Dev\myapp\favicon.ico
WizardImageFile=wizard.bmp
WizardImageStretch=no
WizardSmallImageFile=wizard-small.bmp
WizardImageBackColor=$ffffff
Python code to install packages
You can create Python scripts that the user runs by clicking on an icon (see the [Icons]
section above). You can for instance create a small utility that updates automatically your
application by checking the last installer version on a server, and downloading and executing
it automatically. Here is some Python code snippet that installs or updates a Python package in the user's WinPython distribution, from a zip or a Windows package created with distutils.
import sys
from winpython import wppm, utils
try:
dist = wppm.Distribution(sys.prefix)
package = wppm.Package(pathtoexefile)
dist.install(package)
except:
raise Exception("Unable to install the package.")
Conclusion
This solution may not be adapted to everyone. But I think it is best for regular Windows users
who are used to do everything with the mouse and who are scared by command line
interfaces. It allows any Python developer to create and distribute a graphical application as
easily as for a more standard C++ program. I imagine that games for Windows could be
written with Python and be easily distributed like this. Kivy, a Python library used in media applications and games, uses a similar technique as far as I know.
Finally, do take the time to browse Inno Setup's documentation. It is clear and well
organized. And take a look to WinPython, it is nice and powerful, even if the documentation could be better. Actually I may start using it as my day-to-day Python distribution.
WinPython - it's moved to SourceForge
F. Create a package for Windows
http://kivy.org/docs/guide/packaging-windows.html
Packaging your application for the Windows platform can only be done inside the Windows OS.
The following process has been tested on Windows 7 and the portable package of Kivy.
The package will be either 32 or 64 bits depending on which version of Python you ran it with.
NOTE: Currently, packages for Windows can be generated with Python 2.7 and Python 3.3+. However, Python 3.3+ support is still experimental
1. Requirements¶
Latest Kivy (the whole portable package, not only the github sourcecode)
PyInstaller 2.1 (pip install pyinstaller) for Python 2.7, and experimental PyInstaller 3.0
(pip install https://github.com/pyinstaller/pyinstaller/archive/python3.zip) for Python
3.3+.
2. Create the spec file¶
Note The following instructions is written for python 2.7, for other versions of python one
pg 61
should replace all instances of 2.7 or 27 with the appropriate version.
For this example, we’ll package the touchtracer example and embed a custom icon. The
touchtracer example is the kivy27\examples\demo\touchtracer directory and the main file is
named main.py.
1. Double click on the Kivy-2.7.bat and a console will open.
2. Create a folder into which the packaged app will be created and create the initial spec. For example
create a TouchApp directory in the same directory as Kivy-2.7.bat and do:
3. cd TouchApp
4. pyinstaller --name touchtracer ..\kivy27\examples\demo\touchtracer\main.py
5. You can also add an icon.ico file to the application folder in order to create an icon for the executable.
If you don’t have a .ico file available, you can convert your icon.png file to ico using the web app
ConvertICO. Save the icon.ico in the touchtracer directory and type:
6. pyinstaller --name touchtracer --
icon ..\kivy27\examples\demo\touchtracer\icon.ico ..\kivy27\examples\demo\touchtracer\main.py
7. For more options, please consult the PyInstaller 2.1 Manual.
8. The spec file will be touchtracer.spec located in TouchApp. Now we need to edit the spec file to add
kivy hooks to correctly build the exe. Open the spec file with your favorite editor and add theses lines
at the beginning of the spec:
9. from kivy.tools.packaging.pyinstaller_hooks import install_hooks
10. import os
11. install_hooks(globals())
In the Analysis() function, remove the hookspath=None parameter. If you don’t do this, the kivy package hook will not be used at all.
Then you need to change the COLLECT() call to add the data for touchtracer (touchtracer.kv,
particle.png, ...). Change the line to add a Tree() object. This Tree will search and add every file found in the touchtracer directory to your final package:
coll = COLLECT( exe, Tree('../kivy27/examples/demo/touchtracer/'),
a.binaries,
#...
)
If SDL2 is used the SDL2 dlls also needs to be included; so add the
following Tree object to collect:
Tree([f for f in os.environ.get('KIVY_SDL2_PATH', '').split(';') if 'bin'
in f][0])
Note Until 1.9.0, the windows distribution used PyGame for the core providers. From 1.9.0
and on, the windows distribution uses SDL2 instead and does not come with a PyGame
installation. If you’re using the 1.8.0 package with 1.9.0 or later code, or if you’re using the
1.9.0 or later package, but downloaded and need PyGame in your packaging app, you’ll have
to add the following code to your spec file due to kivy issue #1638. After the imports add the
following:
def getResource(identifier, *args, **kwargs):
if identifier == 'pygame_icon.tiff':
raise IOError()
return _original_getResource(identifier, *args, **kwargs)
import pygame.pkgdata
_original_getResource = pygame.pkgdata.getResource
pg 62
pygame.pkgdata.getResource = getResource
12. We are done. Your spec is ready to be executed!
3. Build the spec¶
1. Double click on Kivy-2.7.bat
2. Go to the TouchApp directory, and build the spec:
3. cd TouchApp
4. pyinstaller touchtracer.spec
5. The package will be in the TouchApp\dist\touchtracer directory.
4. Including Gstreamer¶
If you wish to use Gstreamer, you’ll need to further modify the spec file.
1. Kivy does some magic when trying to find which version of gstreamer and its bindings are available.
In order for pyinstaller to find the correct gstreamer modules, you have to import core.video in the
spec file before doing anything:
from kivy.tools.packaging.pyinstaller_hooks import install_hooks
import kivy.core.video
2. You’ll need to include the gstreamer directory, found in the kivy distribution, in the COLLECT call.
You can specify the direct path, or get it from the environment. In addition, the contents of the
gstreamer/bin directory need to be included in the top level directory, otherwise the build process
may have trouble finding dlls (this will create a second copy of the contents of bin):
import os
gst_plugin_path = os.environ.get('GST_PLUGIN_PATH').split('lib')[0]
COLLECT(exe, Tree(...),
Tree(gst_plugin_path),
Tree(os.path.join(gst_plugin_path, 'bin')),
...)
Following is an example of how to bundle the videoplayer at
kivy27/examples/widgets/videoplayer.py. From kivy-2.7.bat. Create the VideoPlayer directory alongside kivy-2.7.bat:
cd VideoPlayer
pyinstaller --name gstvideo ..\kivy27\examples\widgets\videoplayer.py
Now edit the spec file. At the top of the file add:
import os
from kivy.tools.packaging.pyinstaller_hooks import install_hooks
import kivy.core.video
install_hooks(globals())
gst_plugin_path = os.environ.get('GST_PLUGIN_PATH').split('lib')[0]
Remove the hookspath=None parameter, and change:
coll = COLLECT(exe,
a.binaries,
...
to (remove the SDL2 part if SDL2 is not used):
coll = COLLECT(exe, Tree('../kivy27/examples/widgets'),
Tree([f for f in os.environ.get('KIVY_SDL2_PATH',
'').split(';') if 'bin' in f][0]),
Tree(gst_plugin_path),
Tree(os.path.join(gst_plugin_path, 'bin')),
pg 63
a.binaries,
...
This will include gstreamer and the example video files in examples/widgets. To build, run:
pyinstaller gstvideo.spec
Then you should find gstvideo.exe in VideoPlayer\dist\gstvideo, which when run will play a
video.
5. Tools/msi/msi.py.
I suggest to use the packaging tool that I also use to build the Python releases, which is in
Tools/msi/msi.py. Unpack the additional dependencies on top of the Python source (or an
installation), then adjust msi.py to pick up all additional files that you want to package. You
should adjust display strings to indicate that this is really a separate Python distribution.
6. Making executable Windows programs
https://pythonhosted.org/guiqwt/disthelpers.html
The py2exe Python library is an extension to Python distutils module which converts Python scripts into executable Windows programs, able to run without requiring a Python installation.
Making such an executable program may be a non trivial task when the script dependencies include libraries with data or extensions, such as PyQt4 or guidata and guiqwt. This task has been considerably simplified thanks to the helper functions provided by guidata.disthelpers.
G. Example
This example is included in guiqwt source package (see the py2exe_example directory).
Simple example script named simpledialog.pyw which is based on guiqwt (and implicitely on
guidata):
from guiqwt.plot import ImageDialog
from guiqwt.builder import make
class VerySimpleDialog(ImageDialog):
def set_data(self, data):
plot = self.get_plot()
item = make.trimage(data)
plot.add_item(item, z=0)
plot.set_active_item(item)
plot.replot()
if __name__ == "__main__":
import numpy as np
from guidata import qapplication
qapplication()
dlg = VerySimpleDialog()
dlg.set_data(np.random.rand(100, 100))
dlg.exec_()
The setup.py script may be written as the following:
from distutils.core import setup
import py2exe # Patching distutils setup
from guidata.disthelpers import (remove_build_dist, get_default_excludes,
get_default_dll_excludes,
create_vs2008_data_files,
add_modules)
pg 64
# Removing old build/dist folders
remove_build_dist()
# Including/excluding DLLs and Python modules
EXCLUDES = get_default_excludes()
INCLUDES = []
DLL_EXCLUDES = get_default_dll_excludes()
DATA_FILES = create_vs2008_data_files()
# Configuring/including Python modules
add_modules(('PyQt4', 'guidata', 'guiqwt'), DATA_FILES, INCLUDES,
EXCLUDES)
setup(
options={
"py2exe": {"compressed": 2, "optimize": 2, 'bundle_files':
1,
"includes": INCLUDES, "excludes": EXCLUDES,
"dll_excludes": DLL_EXCLUDES,
"dist_dir": "dist",},
},
data_files=DATA_FILES,
windows=[{
"script": "simpledialog.pyw",
"dest_base": "simpledialog",
"version": "1.0.0",
"company_name": u"CEA",
"copyright": u"Copyright © 2010 CEA - Pierre Raybaut",
"name": "Simple dialog box",
"description": "Simple dialog box",
},],
zipfile = None,
)
Make the Windows executable program with the following command:
python setup.py py2exe
pg 65
Appendix
Sources
This document was compiled from many resources including:
http://cyrille.rossant.net/create-a-standalone-windows-installer-for-your-python-application/
top related