MySQLdb is an thread-compatible interface to the popular MySQL database server that provides the Python database API.
The README file has complete installation instructions.
If you want to write applications which are portable across databases, use MySQLdb, and avoid using this module directly. _mysql provides an interface which mostly implements the MySQL C API. For more information, see the MySQL documentation. The documentation for this module is intentionally weak because you probably should use the higher-level MySQLdb module. If you really need it, use the standard MySQL docs and transliterate as necessary.
The MySQL C API has been wrapped in an object-oriented way. The only MySQL data structures which are implemented are the MYSQL (database connection handle) and MYSQL_RES (result handle) types. In general, any function which takes MYSQL *mysql as an argument is now a method of the connection object, and any function which takes MYSQL_RES *result as an argument is a method of the result object. Functions requiring none of the MySQL data structures are implemented as functions in the module. Functions requiring one of the other MySQL data structures are generally not implemented. Deprecated functions are not implemented. In all cases, the mysql_ prefix is dropped from the name. Most of the conn methods listed are also available as MySQLdb Connection object methods. Their use is non-portable.
C API | _mysql |
---|---|
mysql_affected_rows() | conn.affected_rows() |
mysql_autocommit() | conn.autocommit() |
mysql_character_set_name() | conn.character_set_name() |
mysql_close() | conn.close() |
mysql_commit() | conn.commit() |
mysql_connect() | _mysql.connect() |
mysql_data_seek() | result.data_seek() |
mysql_debug() | _mysql.debug() |
mysql_dump_debug_info | conn.dump_debug_info() |
mysql_escape_string() | _mysql.escape_string() |
mysql_fetch_row() | result.fetch_row() |
mysql_get_character_set_info() | conn.get_character_set_info() |
mysql_get_client_info() | _mysql.get_client_info() |
mysql_get_host_info() | conn.get_host_info() |
mysql_get_proto_info() | conn.get_proto_info() |
mysql_get_server_info() | conn.get_server_info() |
mysql_info() | conn.info() |
mysql_insert_id() | conn.insert_id() |
mysql_num_fields() | result.num_fields() |
mysql_num_rows() | result.num_rows() |
mysql_options() | various options to _mysql.connect() |
mysql_ping() | conn.ping() |
mysql_query() | conn.query() |
mysql_real_connect() | _mysql.connect() |
mysql_real_query() | conn.query() |
mysql_real_escape_string() | conn.escape_string() |
mysql_rollback() | conn.rollback() |
mysql_row_seek() | result.row_seek() |
mysql_row_tell() | result.row_tell() |
mysql_select_db() | conn.select_db() |
mysql_set_character_set() | conn.set_character_set() |
mysql_ssl_set() | ssl option to _mysql.connect() |
mysql_stat() | conn.stat() |
mysql_store_result() | conn.store_result() |
mysql_thread_id() | conn.thread_id() |
mysql_thread_safe_client() | conn.thread_safe_client() |
mysql_use_result() | conn.use_result() |
mysql_warning_count() | conn.warning_count() |
CLIENT_* | MySQLdb.constants.CLIENT.* |
CR_* | MySQLdb.constants.CR.* |
ER_* | MySQLdb.constants.ER.* |
FIELD_TYPE_* | MySQLdb.constants.FIELD_TYPE.* |
FLAG_* | MySQLdb.constants.FLAG.* |
Okay, so you want to use _mysql anyway. Here are some examples.
The simplest possible database connection is:
import _mysql
db=_mysql.connect()
This creates a connection to the MySQL server running on the local machine using the standard UNIX socket (or named pipe on Windows), your login name (from the USER environment variable), no password, and does not USE a database. Chances are you need to supply more information.:
db=_mysql.connect("localhost","joebob","moonpie","thangs")
This creates a connection to the MySQL server running on the local machine via a UNIX socket (or named pipe), the user name "joebob", the password "moonpie", and selects the initial database "thangs".
We haven't even begun to touch upon all the parameters connect() can take. For this reason, I prefer to use keyword parameters:
db=_mysql.connect(host="localhost",user="joebob",
passwd="moonpie",db="thangs")
This does exactly what the last example did, but is arguably easier to read. But since the default host is "localhost", and if your login name really was "joebob", you could shorten it to this:
db=_mysql.connect(passwd="moonpie",db="thangs")
UNIX sockets and named pipes don't work over a network, so if you specify a host other than localhost, TCP will be used, and you can specify an odd port if you need to (the default port is 3306):
db=_mysql.connect(host="outhouse",port=3307,passwd="moonpie",db="thangs")
If you really had to, you could connect to the local host with TCP by specifying the full host name, or 127.0.0.1.
Generally speaking, putting passwords in your code is not such a good idea:
db=_mysql.connect(host="outhouse",db="thangs",read_default_file="~/.my.cnf")
This does what the previous example does, but gets the username and password and other parameters from ~/.my.cnf (UNIX-like systems). Read about option files for more details.
So now you have an open connection as db and want to do a query. Well, there are no cursors in MySQL, and no parameter substitution, so you have to pass a complete query string to db.query():
db.query("""SELECT spam, eggs, sausage FROM breakfast
WHERE price < 5""")
There's no return value from this, but exceptions can be raised. The exceptions are defined in a separate module, _mysql_exceptions, but _mysql exports them. Read DB API specification PEP-249 to find out what they are, or you can use the catch-all MySQLError.
At this point your query has been executed and you need to get the results. You have two options:
r=db.store_result()
# ...or...
r=db.use_result()
Both methods return a result object. What's the difference? store_result() returns the entire result set to the client immediately. If your result set is really large, this could be a problem. One way around this is to add a LIMIT clause to your query, to limit the number of rows returned. The other is to use use_result(), which keeps the result set in the server and sends it row-by-row when you fetch. This does, however, tie up server resources, and it ties up the connection: You cannot do any more queries until you have fetched all the rows. Generally I recommend using store_result() unless your result set is really huge and you can't use LIMIT for some reason.
Now, for actually getting real results:
>>> r.fetch_row()
(('3','2','0'),)
This might look a little odd. The first thing you should know is, fetch_row() takes some additional parameters. The first one is, how many rows (maxrows) should be returned. By default, it returns one row. It may return fewer rows than you asked for, but never more. If you set maxrows=0, it returns all rows of the result set. If you ever get an empty tuple back, you ran out of rows.
The second parameter (how) tells it how the row should be represented. By default, it is zero which means, return as a tuple. how=1 means, return it as a dictionary, where the keys are the column names, or table.column if there are two columns with the same name (say, from a join). how=2 means the same as how=1 except that the keys are always table.column; this is for compatibility with the old Mysqldb module.
OK, so why did we get a 1-tuple with a tuple inside? Because we implicitly asked for one row, since we didn't specify maxrows.
The other oddity is: Assuming these are numeric columns, why are they returned as strings? Because MySQL returns all data as strings and expects you to convert it yourself. This would be a real pain in the ass, but in fact, _mysql can do this for you. (And MySQLdb does do this for you.) To have automatic type conversion done, you need to create a type converter dictionary, and pass this to connect() as the conv keyword parameter.
The keys of conv should be MySQL column types, which in the C API are FIELD_TYPE_*. You can get these values like this:
from MySQLdb.constants import FIELD_TYPE
By default, any column type that can't be found in conv is returned as a string, which works for a lot of stuff. For our purposes, we probably want this:
my_conv = { FIELD_TYPE.LONG: int }
This means, if it's a FIELD_TYPE_LONG, call the builtin int() function on it. Note that FIELD_TYPE_LONG is an INTEGER column, which corresponds to a C long, which is also the type used for a normal Python integer. But beware: If it's really an UNSIGNED INTEGER column, this could cause overflows. For this reason, MySQLdb actually uses long() to do the conversion. But we'll ignore this potential problem for now.
Then if you use db=_mysql.connect(conv=my_conv...), the results will come back ((3, 2, 0),), which is what you would expect.
MySQLdb is a thin Python wrapper around _mysql which makes it compatible with the Python DB API interface (version 2). In reality, a fair amount of the code which implements the API is in _mysql for the sake of efficiency.
The DB API specification PEP-249 should be your primary guide for using this module. Only deviations from the spec and other database-dependent things will be documented here.
Only a few top-level functions and attributes are defined within MySQLdb.
Constructor for creating a connection to the database. Returns a Connection Object. Parameters are the same as for the MySQL C API. In addition, there are a few additional keywords that correspond to what you would pass mysql_options() before connecting. Note that some parameters must be specified as keyword arguments! The default value for each parameter is NULL or zero, as appropriate. Consult the MySQL documentation for more details. The important parameters are:
If True, CHAR and VARCHAR and TEXT columns are returned as Unicode strings, using the configured character set. It is best to set the default encoding in the server configuration, or client configuration (read with read_default_file). If you change the character set after connecting (MySQL-4.1 and later), you'll need to put the correct character set name in connection.charset.
If False, text-like columns are returned as normal strings, but you can always write Unicode strings.
This must be a keyword parameter.
If present, the connection character set will be changed to this character set, if they are not equal. Support for changing the character set requires MySQL-4.1 and later server; if the server is too old, UnsupportedError will be raised. This option implies use_unicode=True, but you can override this with use_unicode=False, though you probably shouldn't.
If not present, the default character set is used.
This must be a keyword parameter.
If present, the session SQL mode will be set to the given string. For more information on sql_mode, see the MySQL documentation. Only available for 4.1 and newer servers.
If not present, the session SQL mode will be unchanged.
This must be a keyword parameter.
Integer constant stating the level of thread safety the interface supports. This is set to 1, which means: Threads may share the module.
The MySQL protocol can not handle multiple threads using the same connection at once. Some earlier versions of MySQLdb utilized locking to achieve a threadsafety of 2. While this is not terribly hard to accomplish using the standard Cursor class (which uses mysql_store_result()), it is complicated by SSCursor (which uses mysql_use_result(); with the latter you must ensure all the rows have been read before another query can be executed. It is further complicated by the addition of transactions, since transactions start when a cursor execute a query, but end when COMMIT or ROLLBACK is executed by the Connection object. Two threads simply cannot share a connection while a transaction is in progress, in addition to not being able to share it during query execution. This excessively complicated the code to the point where it just isn't worth it.
The general upshot of this is: Don't share connections between threads. It's really not worth your effort or mine, and in the end, will probably hurt performance, since the MySQL server runs a separate thread for each connection. You can certainly do things like cache connections in a pool, and give those connections to one thread at a time. If you let two threads use a connection simultaneously, the MySQL client library will probably upchuck and die. You have been warned.
For threaded applications, try using a connection pool. This can be done using the Pool module.
String constant stating the type of parameter marker formatting expected by the interface. Set to 'format' = ANSI C printf format codes, e.g. '...WHERE name=%s'. If a mapping object is used for conn.execute(), then the interface actually uses 'pyformat' = Python extended format codes, e.g. '...WHERE name=%(name)s'. However, the API does not presently allow the specification of more than one style in paramstyle.
Note that any literal percent signs in the query string passed to execute() must be escaped, i.e. %%.
Parameter placeholders can only be used to insert column values. They can not be used for other parts of SQL, such as table names, statements, etc.
A dictionary or mapping which controls how types are converted from MySQL to Python and vice versa.
If the key is a MySQL type (from FIELD_TYPE.*), then the value can be either:
If the key is a Python type or class, then the value is a callable Python object (usually a function) taking two arguments (value to convert, and the conversion dictionary) which converts values of this type to a SQL literal string value.
This is initialized with reasonable defaults for most types. When creating a Connection object, you can pass your own type converter dictionary as a keyword parameter. Otherwise, it uses a copy of MySQLdb.converters.conversions. Several non-standard types are returned as strings, which is how MySQL returns all columns. For more details, see the built-in module documentation.
Connection objects are returned by the connect() function.
There are many more methods defined on the connection object which are MySQL-specific. For more information on them, consult the internal documentation using pydoc.
Calls stored procedure procname with the sequence of arguments in args. Returns the original arguments. Stored procedure support only works with MySQL-5.0 and newer.
Compatibility note: PEP-249 specifies that if there are OUT or INOUT parameters, the modified values are to be returned. This is not consistently possible with MySQL. Stored procedure arguments must be passed as server variables, and can only be returned with a SELECT statement. Since a stored procedure may return zero or more result sets, it is impossible for MySQLdb to determine if there are result sets to fetch before the modified parmeters are accessible.
The parameters are stored in the server as @_*procname*_*n*, where n is the position of the parameter. I.e., if you cursor.callproc('foo', (a, b, c)), the parameters will be accessible by a SELECT statement as @_foo_0, @_foo_1, and @_foo_2.
Compatibility note: It appears that the mere act of executing the CALL statement produces an empty result set, which appears after any result sets which might be generated by the stored procedure. Thus, you will always need to use nextset() to advance result sets.
Advances the cursor to the next result set, discarding the remaining rows in the current result set. If there are no additional result sets, it returns None; otherwise it returns a true value.
Note that MySQL doesn't support multiple result sets until 4.1.
The connect() method works nearly the same as with _mysql:
import MySQLdb
db=MySQLdb.connect(passwd="moonpie",db="thangs")
To perform a query, you first need a cursor, and then you can execute queries on it:
c=db.cursor()
max_price=5
c.execute("""SELECT spam, eggs, sausage FROM breakfast
WHERE price < %s""", (max_price,))
In this example, max_price=5 Why, then, use %s in the string? Because MySQLdb will convert it to a SQL literal value, which is the string '5'. When it's finished, the query will actually say, "...WHERE price < 5".
Why the tuple? Because the DB API requires you to pass in any parameters as a sequence. Due to the design of the parser, (max_price) is interpreted as using algebraic grouping and simply as max_price and not a tuple. Adding a comma, i.e. (max_price,) forces it to make a tuple.
And now, the results:
>>> c.fetchone()
(3L, 2L, 0L)
Quite unlike the _mysql example, this returns a single tuple, which is the row, and the values are properly converted by default... except... What's with the L's?
As mentioned earlier, while MySQL's INTEGER column translates perfectly into a Python integer, UNSIGNED INTEGER could overflow, so these values are converted to Python long integers instead.
If you wanted more rows, you could use c.fetchmany(n) or c.fetchall(). These do exactly what you think they do. On c.fetchmany(n), the n is optional and defaults to c.arraysize, which is normally 1. Both of these methods return a sequence of rows, or an empty sequence if there are no more rows. If you use a weird cursor class, the rows themselves might not be tuples.
Note that in contrast to the above, c.fetchone() returns None when there are no more rows to fetch.
The only other method you are very likely to use is when you have to do a multi-row insert:
c.executemany(
"""INSERT INTO breakfast (name, spam, eggs, sausage, price)
VALUES (%s, %s, %s, %s, %s)""",
[
("Spam and Sausage Lover's Plate", 5, 1, 8, 7.95 ),
("Not So Much Spam Plate", 3, 2, 0, 3.95 ),
("Don't Wany ANY SPAM! Plate", 0, 4, 3, 5.95 )
] )
Here we are inserting three rows of five values. Notice that there is a mix of types (strings, ints, floats) though we still only use %s. And also note that we only included format strings for one row. MySQLdb picks those out and duplicates them for each row.
In general, it is probably wise to not directly interact with the DB API except for small applicatons. Databases, even SQL databases, vary widely in capabilities and may have non-standard features. The DB API does a good job of providing a reasonably portable interface but some methods are non-portable. Specifically, the parameters accepted by connect() are completely implementation-dependent.
If you believe your application may need to run on several different databases, the author recommends the following approach, based on personal experience: Write a simplified API for your application which implements the specific queries and operations your application needs to perform. Implement this API as a base class which should be have few database dependencies, and then derive a subclass from this which implements the necessary dependencies. In this way, porting your application to a new database should be a relatively simple matter of creating a new subclass, assuming the new database is reasonably standard.
Because MySQLdb's Connection and Cursor objects are written in Python, you can easily derive your own subclasses. There are several Cursor classes in MySQLdb.cursors:
CursorDictRowsMixIn
Causes the cursor to return rows as a dictionary, where the keys are column names and the values are column values. Note that if the column names are not unique, i.e., you are selecting from two tables that share column names, some of them will be rewritten as table.column. This can be avoided by using the SQL AS keyword. (This is yet-another reason not to use * in SQL queries, particularly where JOIN is involved.)
Instead of connecting to a stand-alone server over the network, the embedded server support lets you run a full server right in your Python code or application server.
If you have built MySQLdb with embedded server support, there are two additional functions you will need to make use of:
- server_init(args, groups)
Initialize embedded server. If this client is not linked against the embedded server library, this function does nothing.
- args
- sequence of command-line arguments
- groups
- sequence of groups to use in defaults files
- server_end()
- Shut down embedded server. If not using an embedded server, this does nothing.
See the MySQL documentation for more information on the embedded server.
Title: | MySQLdb: a Python interface for MySQL |
---|---|
Author: | Andy Dustman |
Version: | $Revision: 421 $ |
class PersonForm(forms.Form):
name = forms.CharField()
website = forms.URLField()
location = forms.CharField(widget=GMapInput(attrs={'width':'600', 'height':'400'}))
Here’s the code for the GMapInput class (sorry for the docs in Spanish, but I’m in Mexico):
from django.forms.widgets import Input
from django.utils.safestring import mark_safe
class GMapInput(Input):
"""
Widget para seleccionar un punto en un mapa de Google
"""
def render(self, name, value, attrs=None):
"""
Atributos extras:
- width: ancho del mapa en pixeles
- height: alto del mapa en pixeles
- center: latitud,longitud del punto central del mapa
- zoom: zoom inicial del mapa, 1 - 17
"""
final_attrs = self.build_attrs(attrs)
width = final_attrs['width'] if 'width' in final_attrs else '500'
height = final_attrs['height'] if 'height' in final_attrs else '300'
center = final_attrs['center'] if 'center' in final_attrs else '21.983801,-100.964355' # Centro de México
zoom = final_attrs['zoom'] if 'zoom' in final_attrs else '4' # Zoom amplio, se ve todo un país
widget = u'''<div style="margin-left:7em; padding-left:30px;">
<input type="hidden" value="%(value)s" name="%(name)s" id="%(id)s" />
<div id="%(id)s_map" style="width: %(width)spx; height: %(height)spx"></div></div>
<script type="text/javascript">
var %(id)s_map = new GMap2(document.getElementById("%(id)s_map"));
%(id)s_map.addControl(new GLargeMapControl3D());
var %(id)s_marker;
function %(id)s_updateField() {
document.getElementById("%(id)s").value = %(id)s_marker.getLatLng().toUrlValue() + "|" + %(id)s_map.getZoom();
%(id)s_map.panTo(%(id)s_marker.getLatLng(), true);
}
''' % { 'value': value, 'name': name, 'id': final_attrs['id'], 'width': width, 'height': height }
if value is None or value == '':
widget = widget + u'''
%(id)s_map.setCenter(new GLatLng(%(center)s), %(zoom)s);
var %(id)s_clickListener = GEvent.addListener(%(id)s_map, "click", function(overlay, latlng) {
if(latlng) {
%(id)s_marker = new GMarker(latlng, {draggable: true});
%(id)s_map.addOverlay(%(id)s_marker);
%(id)s_updateField();
GEvent.addListener(%(id)s_marker, "dragend", %(id)s_updateField);
GEvent.addListener(%(id)s_map, "zoomend", %(id)s_updateField);
GEvent.addListener(%(id)s_map, "dblclick", function (overlay, latlng) { %(id)s_marker.setLatLng(latlng); %(id)s_updateField(); });
GEvent.removeListener(%(id)s_clickListener);
}
});
</script>''' % { 'id': final_attrs['id'], 'center': center, 'zoom': zoom }
else:
values = value.partition('|')
widget = widget + u'''
%(id)s_map.setCenter(new GLatLng(%(coords)s), %(zoom)s);
%(id)s_marker = new GMarker(new GLatLng(%(coords)s), {draggable: true});
%(id)s_map.addOverlay(%(id)s_marker);
GEvent.addListener(%(id)s_marker, "dragend", %(id)s_updateField);
GEvent.addListener(%(id)s_map, "zoomend", %(id)s_updateField);
GEvent.addListener(%(id)s_map, "dblclick", function (overlay, latlng) { %(id)s_marker.setLatLng(latlng); %(id)s_updateField(); });
''' % { 'id': final_attrs['id'], 'coords': values[0], 'zoom': values[2] }
return mark_safe(widget)
Don’t forget to add the <script> tag linking to the Google Maps API.
It is yet far from perfect, but I still hope it helps someone out there.
LBForum 用django開發的論壇系統,演示地址為:http://vik.haoluobo.com/lbforum/
項目的地址為:http://github.com/vicalloy/LBForum
界面部分抄的 FluxBB(一個開源的PHP論壇 http://fluxbb.org/ )。
雖然Django寫的論壇也不少,不過還真沒什么好用的。
大多Django論壇都是獨立的app,而且不少還缺模板,想我這樣有經驗的Django用戶要跑起來都覺得麻煩,其他普通用戶就更別說了。
LBForum主要注重部署的方便性和易用性,功能方面目前還比較簡單。
LBForum一開始就是以整站的形式提供,所以以LBForum做為基礎項目進行二次開發是很容易的。
同時LBForum的開發盡量遵照Django可復用app原則,因此即使需要將LBForum做為獨立的app集成到其他項目也并不會太難。
目前功能還比較簡單,而且還有些小問題有待修正。
|+lbforum_env/#lbforum運行的python虛擬環境,運行create_lbforum_env.py后自動創建
|+requirements/#lbforum用的第三方庫和app,運行的時候會將該目錄加到python路徑
|~scripts/#工程相關腳本
| |-create_lbforum_env.py#初始化python虛擬環境,并自動安裝easy_install/django依賴庫
| |-helper.py#提供其他腳本所需的輔助函數
| `-lbforum_env.bat*#啟動lbforum運行的虛擬環境及,并為lbforum的manage.py提供快捷方式%mg%,比如初始化數據庫%mg%
syncdb
|~sites/#站點配置/模板/靜態文件
| `~default/#默認站點
| |+static/#靜態資源文件,如css等
| |+templates/#Django模板目錄
| |+templates_plus/#Django模板目錄,用戶將自己重寫過的目標放到該目錄
| `-……
|~src/#django的app目錄
| |+account/#account相關app。具體站點通常會對用戶中心進行定制,所以該app在實際應用中很可能需要針對實際情況進行修改。
| |+djangohelper/#一些django的輔助函數等,
| |+lbforum/#lbforum的主app,論壇功能都在改app中
| |+lbregistration/#registration app的lbforum擴展,主要去掉郵件地址認證功能
| |+onlineuser/#顯示在線用戶的app(可復用的django app,可脫離lbforum單獨使用)
| `+simpleavatar/#頭像功能的app(可復用的django app,可脫離lbforum單獨使用,依賴djangohelper)
|+tools/#工程用到的輔助工具,目前只有一個virtualenv的腳本
不過,wingIDE對中文的支持好像有問題,在我這里,中文全部顯示成了方框。
激活的過程還有些麻煩:
1、將解壓后的WingIDE.exe 和Python25.dll Copy到安裝目錄的Bin下;
2、運行wing3.X,出現license窗口,輸入類似這樣的字符CNxxx-xxxxx-xxxxx-xxxxx (x =1-9);點擊“continus”,如下圖(圖中最后多了一個數字3);
3、copy wingIDE License文件提示中的request No,如下圖:
4、打開cmd,cd到wingIDE安裝目錄下的bin目錄,運行wingide.exe,按照提示輸入CNxxx-xxxxx-xxxxx-xxxxx(步驟2中輸入的序列號)和步驟3中的request code,并按照提示輸入你使用的操作系統,如下圖:
5、將步驟4中生成的activation code:填入步驟3的提示框中,就成功破解了wingIDE
wingIDE professional下載地址:
http://wingware.com/downloads/wingide/
wingIDE professional破解文件:
The SelectTimeWidget supports both 24-hr and 12-hr formats, and flexible time increments for hours, minutes and seconds. Sample usage is illustrated below:
# Specify a basic 24-hr time Widget (the default)
t = forms.TimeField(widget=SelectTimeWidget())
# Force minutes and seconds to be displayed in increments of 10
t = forms.TimeField(widget=SelectTimeWidget(minute_step=10, second_step=10))
# Use a 12-hr time format, which will display a 4th select
# element containing a.m. and p.m. options)
t = forms.TimeField(widget=SelectTimeWidget(twelve_hr=True))
UPDATE: Changed the time pattern to a more precise regular expression, and added the sample usage above.
A widget is Django’s representation of a HTML input element. The widget handles the rendering of the HTML, and the extraction of data from a GET/POST dictionary that corresponds to the widget.
Django provides a representation of all the basic HTML widgets, plus some commonly used groups of widgets:
Password input: <input type='password' ...>
Takes one optional argument:
Date input as a simple text box: <input type='text' ...>
Takes one optional argument:
If no format argument is provided, the default format is '%Y-%m-%d'.
Date/time input as a simple text box: <input type='text' ...>
Takes one optional argument:
If no format argument is provided, the default format is '%Y-%m-%d %H:%M:%S'.
Time input as a simple text box: <input type='text' ...>
Takes one optional argument:
If no format argument is provided, the default format is '%H:%M:%S'.
Checkbox: <input type='checkbox' ...>
Takes one optional argument:
Select widget: <select><option ...>...</select>
Requires that your field provides choices.
Select widget allowing multiple selection: <select multiple='multiple'>...</select>
Requires that your field provides choices.
A list of radio buttons:
<ul>
<li><input type='radio' ...></li>
...
</ul>
Requires that your field provides choices.
A list of checkboxes:
<ul>
<li><input type='checkbox' ...></li>
...
</ul>
Wrapper around two widgets: DateInput for the date, and TimeInput for the time.
Takes two optional arguments, date_format and time_format, which work just like the format argument for DateInput and TimeInput.
Wrapper around three select widgets: one each for month, day, and year. Note that this widget lives in a separate file from the standard widgets.
from django.forms.extras.widgets import SelectDateWidget
date = forms.DateField(widget=SelectDateWidget())
Whenever you specify a field on a form, Django will use a default widget that is appropriate to the type of data that is to be displayed. To find which widget is used on which field, see the documentation for the built-in Field classes.
However, if you want to use a different widget for a field, you can - just use the 'widget' argument on the field definition. For example:
from django import forms
class CommentForm(forms.Form):
name = forms.CharField()
url = forms.URLField()
comment = forms.CharField(widget=forms.Textarea)
This would specify a form with a comment that uses a larger Textarea widget, rather than the default TextInput widget.
When Django renders a widget as HTML, it only renders the bare minimum HTML - Django doesn't add a class definition, or any other widget-specific attributes. This means that all 'TextInput' widgets will appear the same on your web page.
If you want to make one widget look different to another, you need to specify additional attributes for each widget. When you specify a widget, you can provide a list of attributes that will be added to the rendered HTML for the widget.
For example, take the following simple form:
class CommentForm(forms.Form):
name = forms.CharField()
url = forms.URLField()
comment = forms.CharField()
This form will include three default TextInput widgets, with default rendering - no CSS class, no extra attributes. This means that the input boxes provided for each widget will be rendered exactly the same:
>>> f = CommentForm(auto_id=False)
>>> f.as_table()
<tr><th>Name:</th><td><input type="text" name="name" /></td></tr>
<tr><th>Url:</th><td><input type="text" name="url"/></td></tr>
<tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>
On a real web page, you probably don't want every widget to look the same. You might want a larger input element for the comment, and you might want the 'name' widget to have some special CSS class. To do this, you use the attrs argument when creating the widget:
For example:
class CommentForm(forms.Form):
name = forms.CharField(
widget=forms.TextInput(attrs={'class':'special'}))
url = forms.URLField()
comment = forms.CharField(
widget=forms.TextInput(attrs={'size':'40'}))
Django will then include the extra attributes in the rendered output:
>>> f = CommentForm(auto_id=False)
>>> f.as_table()
<tr><th>Name:</th><td><input type="text" name="name" class="special"/></td></tr>
<tr><th>Url:</th><td><input type="text" name="url"/></td></tr>
<tr><th>Comment:</th><td><input type="text" name="comment" size="40"/></td></tr>
I recently discovered a neat way of displaying data retrieved using jquery AJAX in concert with Django’s template engine. You can create a view in Django which simply uses the render_to_response shortcut function to render the results server-side and then just use jquery.load to dynamically fetch the results.
Eventhough, returning some raw JSON data is much more efficient as far as bandwidth is concerned, method is a lot simpler.
I have been using jquery for over a year now. I have found that its built-in DOM manipulation features are a bit limited, especially for manipulating tables (e.g., adding rows dynamically). This method is much cleaner than doing all that DOM manipulation.
Here is all the jQuery code to handle the search and AJAX spinner display:
01.
$( document ).ready(
function
() {
02.
$(
'#searchSubmit'
).click(
function
() {
03.
q = $(
'#q'
).val();
04.
$(
'#results'
).html(
' '
).load(
05.
'{% url demo_user_search %}?q='
+ q );
06.
});
07.
});
08.
09.
$( document ).ajaxStart(
function
() {
10.
$(
'#spinner'
).show();
11.
}).ajaxStop(
function
() {
12.
$(
'#spinner'
).hide();
13.
});
Here is the Django view function that does the heavy lifting on the server-side:
01.
def
ajax_user_search( request ):
02.
if
request.is_ajax():
03.
q
=
request.GET.get(
'q'
)
04.
if
q
is
not
None
:
05.
results
=
User.objects.filter(
06.
Q( first_name__contains
=
q ) |
07.
Q( last_name__contains
=
q ) |
08.
Q( username__contains
=
q ) ).order_by(
'username'
)
09.
10.
template
=
'results.html'
11.
data
=
{
12.
'results'
: results,
13.
}
14.
return
render_to_response( template, data,
15.
context_instance
=
RequestContext( request ) )
Here are some screenshots of the results:
The sample Django project is included for your perusal and is released under the MIT license. I used the excellent Aptana Studio IDE when working on this demo so it can be imported straight into it as an Aptana project.
原因和解決辦法是:
分析django的源代碼中關于國際化方面的(makemessages)就知道,上述命令最終調用的是os.cmd之類調用命令行的東西,而
windows的path路徑列表中沒有xgettext.exe,這是因為windows上沒有gettext,所以要安裝
gettext(python有gettext,但是好像不行,它沒有xgettext)
下載地址是:http://sourceforge.net/projects/gettext
下載這三個:
gettext-runtime-X.bin.woe32.zip
gettext-tools-X.bin.woe32.zip
libiconv-X.bin.woe32.zip
解壓這3個zip文件到同一個文件夾,比如 C:"Program Files"gettext-utils
然后添加到系統變量的PATH中:
控制面板 > 系統 > 高級 > 環境變量
在系統變量列表中, 選中Path, 然后單擊編輯
添加 ;C:"Program Files"gettext-utils"bin 到結尾后一直點確定就行了
那3個文件全部選中后,直接用winrar解壓,選擇一個目錄后解壓即可
Django comes with an optional “flatpages” application. It lets you store simple “flat” HTML content in a database and handles the management for you via Django’s admin interface and a Python API.
A flatpage is a simple object with a URL, title and content. Use it for one-off, special-case pages, such as “About” or “Privacy Policy” pages, that you want to store in a database but for which you don’t want to develop a custom Django application.
A flatpage can use a custom template or a default, systemwide flatpage template. It can be associated with one, or multiple, sites.
The content field may optionally be left blank if you prefer to put your content in a custom template.
Here are some examples of flatpages on Django-powered sites:
To install the flatpages app, follow these steps:
Install the sites framework by adding 'django.contrib.sites' to your INSTALLED_APPS setting, if it’s not already in there.
Also make sure you’ve correctly set SITE_ID to the ID of the site the settings file represents. This will usually be 1 (i.e. SITE_ID = 1, but if you’re not using the sites framework to manage multiple sites, it could be the ID of a different site.
Add 'django.contrib.flatpages' to your INSTALLED_APPS setting.
Add 'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware' to your MIDDLEWARE_CLASSES setting.
Run the command manage.py syncdb.
manage.py syncdb creates two tables in your database: django_flatpage and django_flatpage_sites. django_flatpage is a simple lookup table that simply maps a URL to a title and bunch of text content. django_flatpage_sites associates a flatpage with a site.
The FlatpageFallbackMiddleware does all of the work. Each time any Django application raises a 404 error, this middleware checks the flatpages database for the requested URL as a last resort. Specifically, it checks for a flatpage with the given URL with a site ID that corresponds to the SITE_ID setting.
If it finds a match, it follows this algorithm:
If it doesn’t find a match, the request continues to be processed as usual.
The middleware only gets activated for 404s – not for 500s or responses of any other status code.
Note that the order of MIDDLEWARE_CLASSES matters. Generally, you can put FlatpageFallbackMiddleware at the end of the list, because it’s a last resort.
For more on middleware, read the middleware docs.
Ensure that your 404 template works
Note that the FlatpageFallbackMiddleware only steps in once another view has successfully produced a 404 response. If another view or middleware class attempts to produce a 404 but ends up raising an exception instead (such as a TemplateDoesNotExist exception if your site does not have an appropriate template to use for HTTP 404 responses), the response will become an HTTP 500 (“Internal Server Error”) and the FlatpageFallbackMiddleware will not attempt to serve a flat page.
If you’ve activated the automatic Django admin interface, you should see a “Flatpages” section on the admin index page. Edit flatpages as you edit any other object in the system.
By default, flatpages are rendered via the template flatpages/default.html, but you can override that for a particular flatpage.
Creating the flatpages/default.html template is your responsibility; in your template directory, just create a flatpages directory containing a file default.html.
Flatpage templates are passed a single context variable, flatpage, which is the flatpage object.
Here’s a sample flatpages/default.html template:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
"http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head>
<title>{{ flatpage.title }}</title>
</head>
<body>
{{ flatpage.content }}
</body>
</html>
Since you're already entering raw HTML into the admin page for a flatpage, both flatpage.title and flatpage.content are marked as not requiring automatic HTML escaping in the template.
{% for %} 標簽在循環中設置了一個特殊的 forloop 模板變量。這個變量能提供一些當前循環進展的信息:
forloop.counter 總是一個表示當前循環的執行次數的整數計數器。這個計數器是從1開始的,所以在第一次循環時 forloop.counter 將會被設置為1。例子如下:
{% for item in todo_list %}
<p>{{ forloop.counter }}: {{ item }}</p>
{% endfor %}
forloop.counter0 類似于 forloop.counter ,但是它是從0計數的。第一次執行循環時這個變量會被設置為0。
forloop.revcounter 是表示循環中剩余項的整型變量。在循環初次執行時 forloop.revcounter 將被設置為序列中項的總數。最后一次循環執行中,這個變量將被置1。
forloop.revcounter0 類似于 forloop.revcounter ,但它以0做為結束索引。在第一次執行循環時,該變量會被置為序列的項的個數減1。在最后一次迭代時,該變量為0。
forloop.first 是一個布爾值。在第一次執行循環時該變量為True,在下面的情形中這個變量是很有用的。
{% for object in objects %}
{% if forloop.first %}<li class="first">{% else %}<li>{% endif %}
{{ object }}
</li>
{% endfor %}
forloop.last 是一個布爾值;在最后一次執行循環時被置為True。一個常見的用法是在一系列的鏈接之間放置管道符(|)
{% for link in links %}{{ link }}{% if not forloop.last %} | {% endif %}{% endfor %}
The above template code might output something like this::
Link1 | Link2 | Link3 | Link4
3.
forloop.parentloop 是一個指向當前循環的上一級循環的 forloop 對象的引用(在嵌套循環的情況下)。例子在此:
{% for country in countries %}
<table>
{% for city in country.city_list %}
<tr>
<td>Country #{{ forloop.parentloop.counter }}</td>
<td>City #{{ forloop.counter }}</td>
<td>{{ city }}</td>
</tr>
{% endfor %}
</table>
{% endfor %}
forloop 變量僅僅能夠在循環中使用,在模板解析器碰到 {% endfor %} 標簽時, forloop 就不可訪問了。
Context和forloop變量
在一個 {% for %} 塊中,已存在的變量會被移除,以避免 forloop 變量被覆蓋。Django會把這個變量移動到 forloop.parentloop 中。通常我們不用擔心這個問題,但是一旦我們在模板中定義了 forloop 這個變量(當然我們反對這樣做),在 {% for %} 塊中它會在 forloop.parentloop 被重新命名。Note
This document primarily focuses on FastCGI. Other protocols, such as SCGI and AJP, are also supported, through the flup Python package. See the Protocols section below for specifics about SCGI and AJP.
Essentially, FastCGI is an efficient way of letting an external application serve pages to a Web server. The Web server delegates the incoming Web requests (via a socket) to FastCGI, which executes the code and passes the response back to the Web server, which, in turn, passes it back to the client’s Web browser.
Like mod_python, FastCGI allows code to stay in memory, allowing requests to be served with no startup time. Unlike mod_python (or mod_perl), a FastCGI process doesn’t run inside the Web server process, but in a separate, persistent process.
Why run code in a separate process?
The traditional mod_* arrangements in Apache embed various scripting languages (most notably PHP, Python and Perl) inside the process space of your Web server. Although this lowers startup time – because code doesn’t have to be read off disk for every request – it comes at the cost of memory use. For mod_python, for example, every Apache process gets its own Python interpreter, which uses up a considerable amount of RAM.
Due to the nature of FastCGI, it’s even possible to have processes that run under a different user account than the Web server process. That’s a nice security benefit on shared systems, because it means you can secure your code from other users.
Before you can start using FastCGI with Django, you’ll need to install flup, a Python library for dealing with FastCGI. Version 0.5 or newer should work fine.
FastCGI operates on a client-server model, and in most cases you’ll be starting the FastCGI process on your own. Your Web server (be it Apache, lighttpd, or otherwise) only contacts your Django-FastCGI process when the server needs a dynamic page to be loaded. Because the daemon is already running with the code in memory, it’s able to serve the response very quickly.
Note
If you’re on a shared hosting system, you’ll probably be forced to use Web server-managed FastCGI processes. See the section below on running Django with Web server-managed processes for more information.
A Web server can connect to a FastCGI server in one of two ways: It can use either a Unix domain socket (a “named pipe” on Win32 systems), or it can use a TCP socket. What you choose is a manner of preference; a TCP socket is usually easier due to permissions issues.
To start your server, first change into the directory of your project (wherever your manage.py is), and then run the runfcgi command:
./manage.py runfcgi [options]
If you specify help as the only option after runfcgi, it'll display a list of all the available options.
You'll need to specify either a socket, a protocol or both host and port. Then, when you set up your Web server, you'll just need to point it at the host/port or socket you specified when starting the FastCGI server. See the examples, below.
Django supports all the protocols that flup does, namely fastcgi, SCGI and AJP1.3 (the Apache JServ Protocol, version 1.3). Select your preferred protocol by using the protocol=<protocol_name> option with ./manage.py runfcgi -- where <protocol_name> may be one of: fcgi (the default), scgi or ajp. For example:
./manage.py runfcgi protocol=scgi
Running a threaded server on a TCP port:
./manage.py runfcgi method=threaded host=127.0.0.1 port=3033
Running a preforked server on a Unix domain socket:
./manage.py runfcgi method=prefork socket=/home/user/mysite.sock pidfile=django.pid
Run without daemonizing (backgrounding) the process (good for debugging):
./manage.py runfcgi daemonize=false socket=/tmp/mysite.sock maxrequests=1
If you have the process running in the foreground, it's easy enough to stop it: Simply hitting Ctrl-C will stop and quit the FastCGI server. However, when you're dealing with background processes, you'll need to resort to the Unix kill command.
If you specify the pidfile option to runfcgi, you can kill the running FastCGI daemon like this:
kill `cat $PIDFILE`
...where $PIDFILE is the pidfile you specified.
To easily restart your FastCGI daemon on Unix, try this small shell script:
#!/bin/bash
# Replace these three settings.
PROJDIR="/home/user/myproject"
PIDFILE="$PROJDIR/mysite.pid"
SOCKET="$PROJDIR/mysite.sock"
cd $PROJDIR
if [ -f $PIDFILE ]; then
kill `cat -- $PIDFILE`
rm -f -- $PIDFILE
fi
exec /usr/bin/env - \
PYTHONPATH="../python:.." \
./manage.py runfcgi socket=$SOCKET pidfile=$PIDFILE
To use Django with Apache and FastCGI, you'll need Apache installed and configured, with mod_fastcgi installed and enabled. Consult the Apache documentation for instructions.
Once you've got that set up, point Apache at your Django FastCGI instance by editing the httpd.conf (Apache configuration) file. You'll need to do two things:
The FastCGIExternalServer directive tells Apache how to find your FastCGI server. As the FastCGIExternalServer docs explain, you can specify either a socket or a host. Here are examples of both:
# Connect to FastCGI via a socket / named pipe.
FastCGIExternalServer /home/user/public_html/mysite.fcgi -socket /home/user/mysite.sock
# Connect to FastCGI via a TCP host/port.
FastCGIExternalServer /home/user/public_html/mysite.fcgi -host 127.0.0.1:3033
In either case, the file /home/user/public_html/mysite.fcgi doesn't actually have to exist. It's just a URL used by the Web server internally -- a hook for signifying which requests at a URL should be handled by FastCGI. (More on this in the next section.)
The second step is telling Apache to use FastCGI for URLs that match a certain pattern. To do this, use the mod_rewrite module and rewrite URLs to mysite.fcgi (or whatever you specified in the FastCGIExternalServer directive, as explained in the previous section).
In this example, we tell Apache to use FastCGI to handle any request that doesn't represent a file on the filesystem and doesn't start with /media/. This is probably the most common case, if you're using Django's admin site:
<VirtualHost 12.34.56.78>
ServerName example.com
DocumentRoot /home/user/public_html
Alias /media /home/user/python/django/contrib/admin/media
RewriteEngine On
RewriteRule ^/(media.*)$ /$1 [QSA,L,PT]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^/(.*)$ /mysite.fcgi/$1 [QSA,L]
</VirtualHost>
Django will automatically use the pre-rewrite version of the URL when constructing URLs with the {% url %} template tag (and similar methods).
lighttpd is a lightweight Web server commonly used for serving static files. It supports FastCGI natively and, thus, is a good choice for serving both static and dynamic pages, if your site doesn't have any Apache-specific needs.
Make sure mod_fastcgi is in your modules list, somewhere after mod_rewrite and mod_access, but not after mod_accesslog. You'll probably want mod_alias as well, for serving admin media.
Add the following to your lighttpd config file:
server.document-root = "/home/user/public_html"
fastcgi.server = (
"/mysite.fcgi" => (
"main" => (
# Use host / port instead of socket for TCP fastcgi
# "host" => "127.0.0.1",
# "port" => 3033,
"socket" => "/home/user/mysite.sock",
"check-local" => "disable",
)
),
)
alias.url = (
"/media" => "/home/user/django/contrib/admin/media/",
)
url.rewrite-once = (
"^(/media.*)$" => "$1",
"^/favicon\.ico$" => "/media/favicon.ico",
"^(/.*)$" => "/mysite.fcgi$1",
)
lighttpd lets you use "conditional configuration" to allow configuration to be customized per host. To specify multiple FastCGI sites, just add a conditional block around your FastCGI config for each site:
# If the hostname is 'www.example1.com'...
$HTTP["host"] == "www.example1.com" {
server.document-root = "/foo/site1"
fastcgi.server = (
...
)
...
}
# If the hostname is 'www.example2.com'...
$HTTP["host"] == "www.example2.com" {
server.document-root = "/foo/site2"
fastcgi.server = (
...
)
...
}
You can also run multiple Django installations on the same site simply by specifying multiple entries in the fastcgi.server directive. Add one FastCGI host for each.
Cherokee is a very fast, flexible and easy to configure Web Server. It supports the widespread technologies nowadays: FastCGI, SCGI, PHP, CGI, SSI, TLS and SSL encrypted connections, Virtual hosts, Authentication, on the fly encoding, Load Balancing, Apache compatible log files, Data Base Balancer, Reverse HTTP Proxy and much more.
The Cherokee project provides a documentation to setting up Django with Cherokee.
Many shared-hosting providers don't allow you to run your own server daemons or edit the httpd.conf file. In these cases, it's still possible to run Django using Web server-spawned processes.
Note
If you're using Web server-spawned processes, as explained in this section, there's no need for you to start the FastCGI server on your own. Apache will spawn a number of processes, scaling as it needs to.
In your Web root directory, add this to a file named .htaccess:
AddHandler fastcgi-script .fcgi
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ mysite.fcgi/$1 [QSA,L]
Then, create a small script that tells Apache how to spawn your FastCGI program. Create a file mysite.fcgi and place it in your Web directory, and be sure to make it executable:
#!/usr/bin/python
import sys, os
# Add a custom Python path.
sys.path.insert(0, "/home/user/python")
# Switch to the directory of your project. (Optional.)
# os.chdir("/home/user/myproject")
# Set the DJANGO_SETTINGS_MODULE environment variable.
os.environ['DJANGO_SETTINGS_MODULE'] = "myproject.settings"
from django.core.servers.fastcgi import runfastcgi
runfastcgi(method="threaded", daemonize="false")
If you change any Python code on your site, you'll need to tell FastCGI the code has changed. But there's no need to restart Apache in this case. Rather, just reupload mysite.fcgi, or edit the file, so that the timestamp on the file will change. When Apache sees the file has been updated, it will restart your Django application for you.
If you have access to a command shell on a Unix system, you can accomplish this easily by using the touch command:
touch mysite.fcgi
Regardless of the server and configuration you eventually decide to use, you will also need to give some thought to how to serve the admin media files. The advice given in the modpython documentation is also applicable in the setups detailed above.
Because many of these fastcgi-based solutions require rewriting the URL at some point inside the webserver, the path information that Django sees may not resemble the original URL that was passed in. This is a problem if the Django application is being served from under a particular prefix and you want your URLs from the {% url %} tag to look like the prefix, rather than the rewritten version, which might contain, for example, mysite.fcgi.
Django makes a good attempt to work out what the real script name prefix should be. In particular, if the webserver sets the SCRIPT_URL (specific to Apache's mod_rewrite), or REDIRECT_URL (set by a few servers, including Apache + mod_rewrite in some situations), Django will work out the original prefix automatically.
In the cases where Django cannot work out the prefix correctly and where you want the original value to be used in URLs, you can set the FORCE_SCRIPT_NAME setting in your main settings file. This sets the script name uniformly for every URL served via that settings file. Thus you'll need to use different settings files if you want different sets of URLs to have different script names in this case, but that is a rare situation.
As an example of how to use it, if your Django configuration is serving all of the URLs under '/' and you wanted to use this setting, you would set FORCE_SCRIPT_NAME = '' in your settings file.
Having trouble? We'd like to help!
下載后解壓,將plugins目錄下所有文件挪到Eclipse的相應目錄下,將feature目錄下所有文件挪到Eclipse的相應目錄下,最后啟動 Eclipse,在Help-》Software Upates-》Manage Configuration,然后彈出的界面即可看到pydev的插件。
另一種安裝插件的方法是:Help-》Software Upates-》Find and Install-》Search for new features to install-》New remote site-》隨便起個name如pydev,url填 http://pydev.sf.net/updates/ -》然后照著提示下載安裝即可。
配置Pydev:
在Eclipse IDE 下, 打開 Window->Preferences 對話框,從右側的樹形列表中選擇“ PyDev”->“Interpreter Python”, 點擊New按鈕,從Python的安裝路徑下選擇Python.exe,然后會彈出一個對話框讓你勾選System PYTHONPATH。最后點Ok,退出。
tar xfz jpegsrc.v6b.tar.gz
cd jpeg-6b
./configure
make
make test
make install
make install-lib
mod_python is similar to (and inspired by) mod_perl : It embeds Python within Apache and loads Python code into memory when the server starts. Code stays in memory throughout the life of an Apache process, which leads to significant performance gains over other server arrangements.
Django requires Apache 2.x and mod_python 3.x, and you should use Apache’s prefork MPM, as opposed to the worker MPM.
You may also be interested in How to use Django with FastCGI, SCGI or AJP (which also covers SCGI and AJP).
To configure Django with mod_python, first make sure you have Apache installed, with the mod_python module activated.
Then edit your httpd.conf file and add the following:
<Location "/mysite/">
SetHandler python-program
PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE mysite.settings
PythonOption django.root /mysite
PythonDebug On
</Location>
...and replace mysite.settings with the Python import path to your Django project's settings file.
This tells Apache: "Use mod_python for any URL at or under '/mysite/', using the Django mod_python handler." It passes the value of DJANGO_SETTINGS_MODULE so mod_python knows which settings to use.
Because mod_python does not know we are serving this site from underneath the /mysite/ prefix, this value needs to be passed through to the mod_python handler in Django, via the PythonOption django.root ... line. The value set on that line (the last item) should match the string given in the <Location ...> directive. The effect of this is that Django will automatically strip the /mysite string from the front of any URLs before matching them against your URLConf patterns. If you later move your site to live under /mysite2, you will not have to change anything except the django.root option in the config file.
When using django.root you should make sure that what's left, after the prefix has been removed, begins with a slash. Your URLConf patterns that are expecting an initial slash will then work correctly. In the above example, since we want to send things like /mysite/admin/ to /admin/, we need to remove the string /mysite from the beginning, so that is the django.root value. It would be an error to use /mysite/ (with a trailing slash) in this case.
Note that we're using the <Location> directive, not the <Directory> directive. The latter is used for pointing at places on your filesystem, whereas <Location> points at places in the URL structure of a Web site. <Directory> would be meaningless here.
Also, if your Django project is not on the default PYTHONPATH for your computer, you'll have to tell mod_python where your project can be found:
<Location "/mysite/">
SetHandler python-program
PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE mysite.settings
PythonOption django.root /mysite
PythonDebug On
PythonPath "['/path/to/project'] + sys.path"
</Location>
The value you use for PythonPath should include the parent directories of all the modules you are going to import in your application. It should also include the parent directory of the DJANGO_SETTINGS_MODULE location. This is exactly the same situation as setting the Python path for interactive usage. Whenever you try to import something, Python will run through all the directories in sys.path in turn, from first to last, and try to import from each directory until one succeeds.
An example might make this clearer. Suppose you have some applications under /usr/local/django-apps/ (for example, /usr/local/django-apps/weblog/ and so forth), your settings file is at /var/www/mysite/settings.py and you have specified DJANGO_SETTINGS_MODULE as in the above example. In this case, you would need to write your PythonPath directive as:
PythonPath "['/usr/local/django-apps/', '/var/www'] + sys.path"
With this path, import weblog and import mysite.settings will both work. If you had import blogroll in your code somewhere and blogroll lived under the weblog/ directory, you would also need to add /usr/local/django-apps/weblog/ to your PythonPath. Remember: the parent directories of anything you import directly must be on the Python path.
Note
If you're using Windows, we still recommended that you use forward slashes in the pathnames, even though Windows normally uses the backslash character as its native separator. Apache knows how to convert from the forward slash format to the native format, so this approach is portable and easier to read. (It avoids tricky problems with having to double-escape backslashes.)
This is valid even on a Windows system:
PythonPath "['c:/path/to/project'] + sys.path"
You can also add directives such as PythonAutoReload Off for performance. See the mod_python documentation for a full list of options.
Note that you should set PythonDebug Off on a production server. If you leave PythonDebug On, your users would see ugly (and revealing) Python tracebacks if something goes wrong within mod_python.
Restart Apache, and any request to /mysite/ or below will be served by Django. Note that Django's URLconfs won't trim the "/mysite/" -- they get passed the full URL.
When deploying Django sites on mod_python, you'll need to restart Apache each time you make changes to your Python code.
It's entirely possible to run multiple Django installations on the same Apache instance. Just use VirtualHost for that, like so:
NameVirtualHost *
<VirtualHost *>
ServerName www.example.com
# ...
SetEnv DJANGO_SETTINGS_MODULE mysite.settings
</VirtualHost>
<VirtualHost *>
ServerName www2.example.com
# ...
SetEnv DJANGO_SETTINGS_MODULE mysite.other_settings
</VirtualHost>
If you need to put two Django installations within the same VirtualHost (or in different VirtualHost blocks that share the same server name), you'll need to take a special precaution to ensure mod_python's cache doesn't mess things up. Use the PythonInterpreter directive to give different <Location> directives separate interpreters:
<VirtualHost *>
ServerName www.example.com
# ...
<Location "/something">
SetEnv DJANGO_SETTINGS_MODULE mysite.settings
PythonInterpreter mysite
</Location>
<Location "/otherthing">
SetEnv DJANGO_SETTINGS_MODULE mysite.other_settings
PythonInterpreter othersite
</Location>
</VirtualHost>
The values of PythonInterpreter don't really matter, as long as they're different between the two Location blocks.
If you use mod_python for your development server, you can avoid the hassle of having to restart the server each time you make code changes. Just set MaxRequestsPerChild 1 in your httpd.conf file to force Apache to reload everything for each request. But don't do that on a production server, or we'll revoke your Django privileges.
If you're the type of programmer who debugs using scattered print statements, note that print statements have no effect in mod_python; they don't appear in the Apache log, as one might expect. If you have the need to print debugging information in a mod_python setup, either do this:
assert False, the_value_i_want_to_see
Or add the debugging information to the template of your page.
Django doesn't serve media files itself; it leaves that job to whichever Web server you choose.
We recommend using a separate Web server -- i.e., one that's not also running Django -- for serving media. Here are some good choices:
If, however, you have no option but to serve media files on the same Apache VirtualHost as Django, here's how you can turn off mod_python for a particular part of the site:
<Location "/media">
SetHandler None
</Location>
Just change Location to the root URL of your media files. You can also use <LocationMatch> to match a regular expression.
This example sets up Django at the site root but explicitly disables Django for the media subdirectory and any URL that ends with .jpg, .gif or .png:
<Location "/">
SetHandler python-program
PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE mysite.settings
</Location>
<Location "/media">
SetHandler None
</Location>
<LocationMatch "".(jpg|gif|png)$">
SetHandler None
</LocationMatch>
Note that the Django development server automagically serves admin media files, but this is not the case when you use any other server arrangement. You're responsible for setting up Apache, or whichever media server you're using, to serve the admin files.
The admin files live in (django/contrib/admin/media) of the Django distribution.
Here are two recommended approaches:
If you installed Django from a Python egg or are using eggs in your Django project, some extra configuration is required. Create an extra file in your project (or somewhere else) that contains something like the following:
import os
os.environ['PYTHON_EGG_CACHE'] = '/some/directory'
Here, /some/directory is a directory that the Apache webserver process can write to. It will be used as the location for any unpacking of code the eggs need to do.
Then you have to tell mod_python to import this file before doing anything else. This is done using the PythonImport directive to mod_python. You need to ensure that you have specified the PythonInterpreter directive to mod_python as described above (you need to do this even if you aren't serving multiple installations in this case). Then add the PythonImport line in the main server configuration (i.e., outside the Location or VirtualHost sections). For example:
PythonInterpreter my_django
PythonImport /path/to/my/project/file.py my_django
Note that you can use an absolute path here (or a normal dotted import path), as described in the mod_python manual. We use an absolute path in the above example because if any Python path modifications are required to access your project, they will not have been done at the time the PythonImport line is processed.
When you use Apache/mod_python, errors will be caught by Django -- in other words, they won't propagate to the Apache level and won't appear in the Apache error_log.
The exception for this is if something is really wonky in your Django setup. In that case, you'll see an "Internal Server Error" page in your browser and the full Python traceback in your Apache error_log file. The error_log traceback is spread over multiple lines. (Yes, this is ugly and rather hard to read, but it's how mod_python does things.)
If Apache causes a segmentation fault, there are two probable causes, neither of which has to do with Django itself.
If you continue to have problems setting up mod_python, a good thing to do is get a barebones mod_python site working, without the Django framework. This is an easy way to isolate mod_python-specific problems. Getting mod_python Working details this procedure.
The next step should be to edit your test code and add an import of any Django-specific code you're using -- your views, your models, your URLconf, your RSS configuration, etc. Put these imports in your test handler function and access your test URL in a browser. If this causes a crash, you've confirmed it's the importing of Django code that causes the problem. Gradually reduce the set of imports until it stops crashing, so as to find the specific module that causes the problem. Drop down further into modules and look into their imports, as necessary.
File "/tmp/easy_install-nHSsgl/MySQL-python-1.2.2/setup_posix.py", line 26, in mysql_config
EnvironmentError: mysql_config not found
后來發現是由于Mysql編譯安裝后沒有 mysql_config這個值,解決方法:
打開 setup_posix.py, 將其中line:26手動改成系統中對應的Mysql選項(這里我的是/usr/local/mysql):
mysql_config = /usr/local/mysql/bin/mysql_config
重新執行 :python setup.py build,沒有了剛才的錯誤,但是出現了另外一個錯誤:
error: /usr/bin/ld: cannot find -lmysqlclient
網上搜索了一下這個錯誤,發現有幾種不同的情況,主要有以下幾個原因:
1.沒有安裝mysqlclient。解決方法:找到對應的版本進行安裝。
2.安裝的mysqlclient的版本不匹配。對應鏈接: http://www.hao32.com/webserver/258.html
3.已經安裝了對應的mysqlclient但是找不到對應的鏈接。這是在一個國外的網站上看到的,具體網址已經找不到了,后來那位仁兄將對應的
mysql_home/lib/mysql文件夾下面libmysqlclient對應的文件全部拷貝到/usr/local/lib下面才解決了問題。
按照對應方案,問題解決。
重新執行:
python setup.py build
python setup.py install
安裝完成。
This article is not about teaching you how to program in Python, nor how to use the Django framework. It’s about showing how to promote your Django applications onto an existing Apache or Lighttpd environment.
We will conclude with a simple way that you can improve the performance of your Django application by using caching to speed up access time. This article also assumes that you are running Fedora as your web application server, but all the packages mentioned in this article are also available under the Extra Packages for Enterprise Linux repository , which means these instructions should also be valid under Red Hat Enterprise Linux or CentOS servers.
You must have Django installed:
# yum install Django
If you want to serve Django apps under Apache:
# yum install httpd
# yum install mod_python
If you want to serve Django apps under Lighttpd:
# yum install lighttpd
# yum install lighttpd-fastcgi
# yum install python-flup
Installing memcached to ’speed up’ Django apps:
# yum install memcached
# yum install python-memcached
1. Create a development workspace.
$ mkdir -p $LOCATION_TO_YOUR_DEV_AREA
$ cd $LOCATION_TO_YOUR_DEV_AREA
2. Start a new base Django project. This creates the boiler plate project structure.
$ django-admin.py startproject my_app
3. Start the Django development web server on port 8080 (or whatever other port you’d like).
Note: The development web server is just for testing and verification. Do not use it as a production application server!
$ python manage.py runserver 8080
4. Run your Django project under Apache with mod_python by enabling mod_python on httpd.conf (/etc/httpd/conf/httpd.conf).
After installing mod_python, a file called python.conf should already be placed in /etc/httpd/conf.d/, which enables mod_python on your system.
5. Create virtual hosts by creating a new file at /etc/httpd/conf.d/myapp.conf.
DocumentRoot /var/www/html/
ServerName your_domain_name
ErrorLog logs/my_app-error.log
CustomLog logs/my_app-access_log common
SetHandler python-program
PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE my_app.settings
PythonDebug On
PythonPath “[’/var/www/django/’] + sys.path”
The first thing you must do is start up your FastCGI server.
./manage.py runfcgi method=prefork socket=/var/www/myapp.sock pidfile=django_myapp.pid
Then modify your lighttpd.conf file to use the FastCGI server.
server.document-root = "/var/www/django/"
fastcgi.server = (
"/my_app.fcgi" => (
"main" => (
# Use host / port instead of socket for TCP fastcgi
# "host" => "127.0.0.1",
# "port" => 3033,
"socket" => "/var/www/my_app.sock",
"check-local" => "disable",
)
),
)
alias.url = (
"/media/" => "/var/www/django/media/",
)
url.rewrite-once = (
"^(/media.*)$" => "$1",
"^/favicon.ico$" => "/media/favicon.ico",
"^(/.*)$" => "/my_app.fcgi$1",
)
Setting up caching in Django
Django has many different caching backends, including database, memory, filesystem, and the ever popular memcached. According to http://www.danga.com/memcached/, memcached is “a high-performance, distributed memory object caching system, generic in nature, but intended for use in speeding up dynamic web applications by alleviating database load.” It’s used by high traffic sites such as Slashdot and Wikipedia. This makes it a prime candidate for caching in your cool new web app.
First, verify that memcached is running using the memcached’s init script.
$ /etc/init.d/memcached status
memcached (pid 6771) is running...
If it’s not running, you can manually start it.
$ /sbin/service memcached start
If you want to make sure it will automatically start every time after a reboot:
$ /sbin/chkconfig --level 35 memcached on
Now that you have verified that memcached is running, you will want to tell your Django application to use memcached as it’s caching backend. You can do this by adding a CACHE_BACKEND entry to your settings.py file.
CACHE_BACKEND = 'memcached://127.0.0.1:11211/'
The format is “backend://host:port/” or “backend:///path” depending on the backend chosen. Since we are using memcached, we have the option to run multiple daemons on different servers and share the cache across multiple machines. If you want to do this all you must do is add in the servers:port combinations in the CACHE_BACKEND and separate them by semicolons. In this example we share the cache across three different memcached servers:
CACHE_BACKEND = 'memcached://127.0.0.1:11211;192.168.0.10:11211;192.168.0.11/'
For more information on the different types of caching that can be performed in the Django framework, please refer to their official documentation.
For the record, I'm running all of this off of OpenSuSE 10.1 - so obligatory YMMV. Please comment with suggestions or problems if so, though.
First off, make sure you've got Apache up and running. ps aux | grep httpd can tell ya for the most part. If you don't know how to do this much, though, I'm afraid you're reading the wrong tutorial.
This will vary pretty widely amongst distributions, but our goal was to have a package manager do it. One of the below will probably work for you:
So with mod_python installed, now we can get to Django. We have been tracking along with Subversion up until now, but since we're getting ready to put a large (for us) site into production, we are planning on sticking with numbered releases, but it remains to be seen if we'll change our minds on that one in order to take advantage of the enhancements that continue to stream in. If you want to live closer to the edge, you can get the development trunk through subversion.
Note that the last command will automatically download and install 'setuptools' if you don't already have it installed.
So assuming everything went well, (It did, didn't it?), we're ready to start our first django project. Start your first project by going into the directory you want to hold your django projects (preferably outside of your web document root), and typing:
As the djangoproject.com tutorial says…
django-admin.py should be on your system path if you installed Django via python setup.py. If it's not on your path, you can find it in site-packages/django/bin, where site-packages is a directory within your Python installation. Consider symlinking to django-admin.py from some place on your path, such as /usr/local/bin.
This will start you off with the basic settings and files needed for your django project. But we're not done quite yet! We have to tell apache what to do to handle mod_python requests.
To get apache to handle python requests, we first need to activate mod_python. Again, this is one of those things that will vary pretty widely through distributions, but essentially you'll need this command in Apache's httpd.conf file:
(note: Purportedly on debian this is done for you automatically - so you will likely be able to skip this step)
In OpenSuSE the best way to do this is to go into YaST-> Sysconfig
Editor-> Network-> WWW-> Apache2, and append 'python' onto the
APACHE_MODULES
setting. There may be other ways to do this more painlessly than file
editing in other distro's, as well. Let me know if there are and I will
update this section.
Now that apache knows about python, we have to tell it where to -use- python. So go into your httpd.conf file (if you're using virtual hosts, pick the appropriate virtual host config file) and add this location directive:
Now save, restart apache, and browse to your server + /myProject (i.e., http://www.yourhost.com/myProject).
Did it come up with a special looking 404 error? If so, you've got Django installed, man! Better go follow the more informative and better written Django Tutorial to see how to really get rolling with it - you're ready to start developing!
1、下載需要模塊。
a、apache (httpd-2.0.54.tar.gz or later)
b、mod_python (mod_python-3.3.1.tgz)
c、Django (Django-0.96.tar.gz)
默認已安裝 Python (http://www.python.org)
2、安裝配置環境。
首先,正常安裝 apache 和 mod_python (http://www.modpython.org/),注意要打開 apache 的 DSO 功能,執行:
#...
#tar -zxvf httpd-2.0.54.tar.gz
#cd httpd-2.0.54
#./configure --prefix=/usr/local/apache2 --enable-so --enable-mods-shared=all
#make install clean
#...
#tar -zxvf mod_python-3.3.1.tgz
#cd mod_python-3.3.1
#./configure --with-apxs=/usr/local/apache2/bin/apxs --with-python=/usr/local/bin/python
#make install clean
#...
#tar -zxvf Django-0.96.tar.gz
#cd Django-0.96
#python setup.py install (If
you installed Django using setup.py install, uninstalling is as simple
as deleting the django directory from your Python site-packages.)
#...
這
樣我們就安裝好 Apache + mod_python + Django 了,你可以執行 apachectl start
測試一下能不能成功。然后我們開始配置環境,首先配置 httpd.conf 加入 LoadModule python_module
modules/mod_python.so (在安裝 mod_python 的時候安裝程序會自動把 mod_python.so 拷貝到
apache 的 modules 目錄下),接著配置虛擬主機。
到這里你就可以利用 mod_python
來進行編程了,然后我們來配置一下 Django 并通過一個實例來讓大家對這個現今最 HOT 的 python web
框架有一個大體的了解:首先,我們來學習一下用 django-admin.py 工具來簡化你的工作 (當我們安裝 Django
的時候,安裝程序會自動把 django-admin.py 拷貝到 系統 PATH 下,所以我們可以直接使用它)。首先進入到我們的 python
程序目錄 (我用的是:{DOCUMENT_ROOT}/python),執行:
#django-admin.py startproject newtest
這樣就可以生成我們的測試工程了默認情況下會生成 {DOCUMENT_ROOT}/python/newtest 目錄,該目錄下會有如下文件:
__init__.py (表示這是一個 Python 的包)
manage.py (提供簡單化的 django-admin.py 命令,特別是可以自動進行 DJANGO_SETTINGS_MODULES 和 PYTHONPATH 的處理,而沒有這個命令,處理上面環境變量是件麻煩的事情)
settings.py (它是django的配置文件)
uls.py (url映射處理文件, Karrigell 沒有這種機制,它通過目錄/文件/方法來自動對應,而 Django 的url映射是url對于某個模塊方法的映射,目前不能自動完成)
然后我們在 apache 的虛擬主機配置文件里面加上:
<Location "/newtest/">
SetHandler python-program
PythonPath "sys.path+['{DOCUMENT_ROOT}/python']"
PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE newtest.settings
#PythonInterpreter mysite
PythonDebug On
</Location>
這
里要注意的是對于 PythonPath,必須設置成工程目錄 ({DOCUMENT_ROOT}/python/newtest)
的上一級目錄!這樣我們就完成了 Django 和 apache 的整合了,趕快試一下吧,我們寫一個 action 來測試一下 Django
的功能:
3、編寫測試程序。
1> 首先,創建 ./list.py :
#coding=utf-8
from django.shortcuts import render_to_response
address = [
{'name':'張三', 'address':'地址一'},
{'name':'李四', 'address':'地址二'}
]
def index(request):
return render_to_response('list.html', {'address': address})
2> 然后,創建一個模版文件 ./templates/list.html :
<h2>通訊錄</h2>
<table border="1">
<tr><th>姓名</th><th>地址</th></tr>
{% for user in address %}
<tr>
<td>{{ user.name }}</td>
<td>{{ user.address }}</td>
</tr>
{% endfor %}
</table>
3> 設置模版目錄 (編輯 ./settings.py) :
TEMPLATE_DIRS = (
# Put strings here, like "/home/html/django_templates".
# Always use forward slashes, even on Windows.
'./templates',
)
4> 修改 urls.py :
from django.conf.urls.defaults import *
urlpatterns = patterns('',
# Example:
# (r'^newtest/', include('newtest.foo.urls')),
(r'^newtest/list/$', 'newtest.list.index'),
# Uncomment this for admin:
# (r'^admin/', include('django.contrib.admin.urls')),
)
5> 重啟 Apache 并訪問相應 url (http://localhost/newtest/list/) 即可看到結果頁面了:
通訊錄
姓名 地址
張三 地址一
李四 地址二
到這里,你已經掌握了 Django 框架的基本內容了,就可以進一步學習 Django 的其他內容了,Enjoy It :)
2. 安裝python 2.5
從官網上下載2.5版本,Python-2.5.2.tgz,解壓縮后./configure, make , make install.就可以完成安裝。默認安裝目錄為/usr/local/lib/python2.5/
3. 安裝mod_python.
./configure –with-apxs=/usr/local/apache2/bin/apxs
–with-python=/usr/bin/python2.5,再make, make install
即可。安裝完畢后會在目錄/usr/local/apache2/modules下有文件mod_python.so,這個在后面要使用到。
4. 安裝django 1.0
從官網下
載1.0版本Django-1.0.tar.gz,解壓縮,使用命令python setup.py install
安裝,注意,如果機器里有以前的版本,一定要把以前的版本文件完全卸載活刪除,django
不會覆蓋以前的文件。默認安裝目錄為/usr/local/lib/python2.5/site-packages/django/
5.安裝sqlite
這里使用到的數據庫為sqlite3,所以要安裝相應的包,這里 從官網下載pysqlite-2.3.5.tar.gz,安裝很容易。
6.配置文件.
這里使用了最簡單的配置方法,直接修改/usr/local/apache2/conf/httpd.conf
(1) ,默認端口,80,可以不修改。
(2) 在有LoadModule example字樣的下面添加一下一行
LoadModule python_module modules/mod_python.so
(3) 配置ServerName,在有 #ServerName www.example.com:80字樣的下面添加一下行:
ServerName yourIP:80
(4) 這是最重要的一步了。在有字樣# This should be changed to whatever you set
DocumentRoot to.的后面,修改<Directory> … </Directory>中間的內容為:
<Directory “/home/af/af“>
#
# Possible values for the Options directive are “None”, “All”,
# or any combination of:
# Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews
#
# Note that “MultiViews” must be named *explicitly* — “Options All”
# doesn’t give it to you.
#
# The Options directive is both complicated and important. Please see
# http://httpd.apache.org/docs/2.2/mod/core.html#options
# for more information.
#
#Options Indexes FollowSymLinks
#PythonHandler django.core.handlers.modpython
PythonPath “['/home/af/af','/usr/local/lib/python2.5/site-packages'] + sys.path”
PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE aftest.settings
SetHandler python-program
PythonDebug On
#
# AllowOverride controls what directives may be placed in .htaccess files.
# It can be “All”, “None”, or any combination of the keywords:
# Options FileInfo AuthConfig Limit
#
#AllowOverride None
#
# Controls who can get stuff from this server.
#
#Order allow,deny
Allow from all
</Directory>
其中藍色部分為要修改和添加的部分,/home/af/af是Django 工程所在的目錄,aftest為項目名稱。
(5)添加media。這里以安裝Django自己提供的admin為例。
在上一步的</Directory>下面再添加
Alias /media /usr/local/lib/python2.5/site-packages/django/contrib/admin/media
<Location “/media”>
Options None
SetHandler None
Allow from all
</Location>
即可。
配置完畢。
from django.utils.httpwrappers import HttpResponse
from PIL import Image
import random
INK = "red", "blue", "green", "yellow"
def image(request):
# ... create/load image here ...
image = Image.new("RGB", (800, 600), random.choice(INK))
# serialize to HTTP response
response = HttpResponse(mimetype="image/png")
image.save(response, "PNG")
return response
To draw things on the fly, you can use either PIL’s ImageDraw module, or the aggdraw module:
from django.utils.httpwrappers import HttpResponse
from PIL import Image
from aggdraw import Draw, Pen, Brush, Font
import random
def graphics(request):
image = Image.new("RGB", (800, 600), "white")
draw = Draw(image)
# ... draw graphics here ...
for i in range(20):
x0 = random.randint(0, image.size[0])
y0 = random.randint(0, image.size[1])
x1 = random.randint(0, image.size[0])
y1 = random.randint(0, image.size[1])
draw.rectangle((x0, y0, x1, y1), Pen(random.choice(INK), 5))
draw.flush()
response = HttpResponse(mimetype="image/png")
image.save(response, "PNG")
return response