diff options
| author | Andrew Godwin <andrew@aeracode.org> | 2012-12-18 09:02:07 +0000 |
|---|---|---|
| committer | Andrew Godwin <andrew@aeracode.org> | 2012-12-18 09:02:07 +0000 |
| commit | b62e82365ad56ca930f7abb1d1dbdf9ce5a7c7c3 (patch) | |
| tree | 76bce44f4c7ee6172dcf116be6e4a26e380ef20a /docs/topics | |
| parent | 6a632e04578776e877adc5e2dc53f008c890a0d4 (diff) | |
| parent | c64b57d16688025b2d48668d5c4cb9eda7484612 (diff) | |
Merge remote-tracking branch 'core/master' into schema-alteration
Conflicts:
django/db/models/loading.py
django/db/models/options.py
Diffstat (limited to 'docs/topics')
32 files changed, 2455 insertions, 177 deletions
diff --git a/docs/topics/_images/django_unittest_classes_hierarchy.graffle b/docs/topics/_images/django_unittest_classes_hierarchy.graffle new file mode 100644 index 0000000000..7211c0f3be --- /dev/null +++ b/docs/topics/_images/django_unittest_classes_hierarchy.graffle @@ -0,0 +1,883 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>ActiveLayerIndex</key> + <integer>0</integer> + <key>ApplicationVersion</key> + <array> + <string>com.omnigroup.OmniGrafflePro</string> + <string>139.16.0.171715</string> + </array> + <key>AutoAdjust</key> + <true/> + <key>BackgroundGraphic</key> + <dict> + <key>Bounds</key> + <string>{{0, 0}, {559.28997802734375, 782.8900146484375}}</string> + <key>Class</key> + <string>SolidGraphic</string> + <key>ID</key> + <integer>2</integer> + <key>Style</key> + <dict> + <key>shadow</key> + <dict> + <key>Draws</key> + <string>NO</string> + </dict> + <key>stroke</key> + <dict> + <key>Draws</key> + <string>NO</string> + </dict> + </dict> + </dict> + <key>BaseZoom</key> + <integer>0</integer> + <key>CanvasOrigin</key> + <string>{0, 0}</string> + <key>ColumnAlign</key> + <integer>1</integer> + <key>ColumnSpacing</key> + <real>36</real> + <key>CreationDate</key> + <string>2012-12-16 18:52:14 +0000</string> + <key>Creator</key> + <string>Aymeric Augustin</string> + <key>DisplayScale</key> + <string>1.000 cm = 1.000 cm</string> + <key>GraphDocumentVersion</key> + <integer>8</integer> + <key>GraphicsList</key> + <array> + <dict> + <key>Class</key> + <string>LineGraphic</string> + <key>Head</key> + <dict> + <key>ID</key> + <integer>8</integer> + </dict> + <key>ID</key> + <integer>29</integer> + <key>OrthogonalBarAutomatic</key> + <true/> + <key>OrthogonalBarPoint</key> + <string>{0, 0}</string> + <key>OrthogonalBarPosition</key> + <real>-1</real> + <key>Points</key> + <array> + <string>{369, 459}</string> + <string>{216, 400.5}</string> + </array> + <key>Style</key> + <dict> + <key>stroke</key> + <dict> + <key>HeadArrow</key> + <string>UMLInheritance</string> + <key>HeadScale</key> + <real>0.79999995231628418</real> + <key>Legacy</key> + <true/> + <key>LineType</key> + <integer>2</integer> + <key>TailArrow</key> + <string>0</string> + </dict> + </dict> + <key>Tail</key> + <dict> + <key>ID</key> + <integer>6</integer> + <key>Info</key> + <integer>2</integer> + </dict> + </dict> + <dict> + <key>Class</key> + <string>LineGraphic</string> + <key>Head</key> + <dict> + <key>ID</key> + <integer>12</integer> + <key>Info</key> + <integer>1</integer> + </dict> + <key>ID</key> + <integer>27</integer> + <key>OrthogonalBarAutomatic</key> + <true/> + <key>OrthogonalBarPoint</key> + <string>{0, 0}</string> + <key>OrthogonalBarPosition</key> + <real>-1</real> + <key>Points</key> + <array> + <string>{135, 270}</string> + <string>{369, 225}</string> + </array> + <key>Style</key> + <dict> + <key>stroke</key> + <dict> + <key>HeadArrow</key> + <string>UMLInheritance</string> + <key>HeadScale</key> + <real>0.79999995231628418</real> + <key>Legacy</key> + <true/> + <key>LineType</key> + <integer>2</integer> + <key>TailArrow</key> + <string>0</string> + </dict> + </dict> + <key>Tail</key> + <dict> + <key>ID</key> + <integer>26</integer> + <key>Position</key> + <real>0.5</real> + </dict> + </dict> + <dict> + <key>Class</key> + <string>LineGraphic</string> + <key>Head</key> + <dict> + <key>ID</key> + <integer>10</integer> + </dict> + <key>ID</key> + <integer>26</integer> + <key>OrthogonalBarAutomatic</key> + <true/> + <key>OrthogonalBarPoint</key> + <string>{0, 0}</string> + <key>OrthogonalBarPosition</key> + <real>-1</real> + <key>Points</key> + <array> + <string>{135, 315}</string> + <string>{135, 225}</string> + </array> + <key>Style</key> + <dict> + <key>stroke</key> + <dict> + <key>HeadArrow</key> + <string>UMLInheritance</string> + <key>HeadScale</key> + <real>0.79999995231628418</real> + <key>Legacy</key> + <true/> + <key>LineType</key> + <integer>2</integer> + <key>TailArrow</key> + <string>0</string> + </dict> + </dict> + <key>Tail</key> + <dict> + <key>ID</key> + <integer>9</integer> + </dict> + </dict> + <dict> + <key>Class</key> + <string>LineGraphic</string> + <key>Head</key> + <dict> + <key>ID</key> + <integer>9</integer> + </dict> + <key>ID</key> + <integer>25</integer> + <key>OrthogonalBarAutomatic</key> + <true/> + <key>OrthogonalBarPoint</key> + <string>{0, 0}</string> + <key>OrthogonalBarPosition</key> + <real>-1</real> + <key>Points</key> + <array> + <string>{135, 387}</string> + <string>{135, 342}</string> + </array> + <key>Style</key> + <dict> + <key>stroke</key> + <dict> + <key>HeadArrow</key> + <string>UMLInheritance</string> + <key>HeadScale</key> + <real>0.79999995231628418</real> + <key>Legacy</key> + <true/> + <key>LineType</key> + <integer>2</integer> + <key>TailArrow</key> + <string>0</string> + </dict> + </dict> + <key>Tail</key> + <dict> + <key>ID</key> + <integer>8</integer> + </dict> + </dict> + <dict> + <key>Class</key> + <string>LineGraphic</string> + <key>Head</key> + <dict> + <key>ID</key> + <integer>8</integer> + </dict> + <key>ID</key> + <integer>23</integer> + <key>OrthogonalBarAutomatic</key> + <true/> + <key>OrthogonalBarPoint</key> + <string>{0, 0}</string> + <key>OrthogonalBarPosition</key> + <real>-1</real> + <key>Points</key> + <array> + <string>{135, 459}</string> + <string>{135, 414}</string> + </array> + <key>Style</key> + <dict> + <key>stroke</key> + <dict> + <key>HeadArrow</key> + <string>UMLInheritance</string> + <key>HeadScale</key> + <real>0.79999995231628418</real> + <key>Legacy</key> + <true/> + <key>LineType</key> + <integer>2</integer> + <key>TailArrow</key> + <string>0</string> + </dict> + </dict> + <key>Tail</key> + <dict> + <key>ID</key> + <integer>7</integer> + </dict> + </dict> + <dict> + <key>Bounds</key> + <string>{{378, 252}, {81, 27}}</string> + <key>Class</key> + <string>ShapedGraphic</string> + <key>FontInfo</key> + <dict> + <key>Font</key> + <string>Helvetica</string> + <key>Size</key> + <real>12</real> + </dict> + <key>ID</key> + <integer>22</integer> + <key>Shape</key> + <string>NoteShape</string> + <key>Style</key> + <dict> + <key>stroke</key> + <dict> + <key>Color</key> + <dict> + <key>b</key> + <string>0</string> + <key>g</key> + <string>0.501961</string> + <key>r</key> + <string>0</string> + </dict> + </dict> + </dict> + <key>Text</key> + <dict> + <key>Text</key> + <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;\red0\green128\blue0;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\i\fs24 \cf2 Python < 2.7}</string> + <key>VerticalPad</key> + <integer>0</integer> + </dict> + <key>TextRelativeArea</key> + <string>{{0, 0}, {1, 1}}</string> + </dict> + <dict> + <key>Bounds</key> + <string>{{45, 252}, {81, 27}}</string> + <key>Class</key> + <string>ShapedGraphic</string> + <key>FontInfo</key> + <dict> + <key>Font</key> + <string>Helvetica</string> + <key>Size</key> + <real>12</real> + </dict> + <key>ID</key> + <integer>20</integer> + <key>Shape</key> + <string>NoteShape</string> + <key>Style</key> + <dict> + <key>stroke</key> + <dict> + <key>Color</key> + <dict> + <key>b</key> + <string>0</string> + <key>g</key> + <string>0.501961</string> + <key>r</key> + <string>0</string> + </dict> + </dict> + </dict> + <key>Text</key> + <dict> + <key>Text</key> + <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;\red0\green128\blue0;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\i\fs24 \cf2 Python \uc0\u8805 2.7}</string> + <key>VerticalPad</key> + <integer>0</integer> + </dict> + </dict> + <dict> + <key>Bounds</key> + <string>{{288, 198}, {162, 27}}</string> + <key>Class</key> + <string>ShapedGraphic</string> + <key>ID</key> + <integer>12</integer> + <key>Magnets</key> + <array> + <string>{0, 1}</string> + <string>{0, -1}</string> + <string>{1, 0}</string> + <string>{-1, 0}</string> + </array> + <key>Shape</key> + <string>Rectangle</string> + <key>Style</key> + <dict> + <key>fill</key> + <dict> + <key>FillType</key> + <integer>2</integer> + <key>GradientAngle</key> + <real>90</real> + <key>GradientColor</key> + <dict> + <key>w</key> + <string>0.666667</string> + </dict> + </dict> + <key>stroke</key> + <dict> + <key>CornerRadius</key> + <real>5</real> + </dict> + </dict> + <key>Text</key> + <dict> + <key>Text</key> + <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340 +\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 TestCase}</string> + </dict> + </dict> + <dict> + <key>Bounds</key> + <string>{{54, 198}, {162, 27}}</string> + <key>Class</key> + <string>ShapedGraphic</string> + <key>ID</key> + <integer>10</integer> + <key>Magnets</key> + <array> + <string>{0, 1}</string> + <string>{0, -1}</string> + <string>{1, 0}</string> + <string>{-1, 0}</string> + </array> + <key>Shape</key> + <string>Rectangle</string> + <key>Style</key> + <dict> + <key>fill</key> + <dict> + <key>FillType</key> + <integer>2</integer> + <key>GradientAngle</key> + <real>90</real> + <key>GradientColor</key> + <dict> + <key>w</key> + <string>0.666667</string> + </dict> + </dict> + <key>stroke</key> + <dict> + <key>CornerRadius</key> + <real>5</real> + </dict> + </dict> + <key>Text</key> + <dict> + <key>Text</key> + <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340 +\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 TestCase}</string> + </dict> + </dict> + <dict> + <key>Bounds</key> + <string>{{54, 315}, {162, 27}}</string> + <key>Class</key> + <string>ShapedGraphic</string> + <key>ID</key> + <integer>9</integer> + <key>Magnets</key> + <array> + <string>{0, 1}</string> + <string>{0, -1}</string> + <string>{1, 0}</string> + <string>{-1, 0}</string> + </array> + <key>Shape</key> + <string>Rectangle</string> + <key>Style</key> + <dict> + <key>fill</key> + <dict> + <key>FillType</key> + <integer>2</integer> + <key>GradientAngle</key> + <real>90</real> + <key>GradientColor</key> + <dict> + <key>w</key> + <string>0.666667</string> + </dict> + </dict> + <key>stroke</key> + <dict> + <key>CornerRadius</key> + <real>5</real> + </dict> + </dict> + <key>Text</key> + <dict> + <key>Text</key> + <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340 +\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 SimpleTestCase}</string> + </dict> + </dict> + <dict> + <key>Bounds</key> + <string>{{54, 387}, {162, 27}}</string> + <key>Class</key> + <string>ShapedGraphic</string> + <key>ID</key> + <integer>8</integer> + <key>Magnets</key> + <array> + <string>{0, 1}</string> + <string>{0, -1}</string> + <string>{1, 0}</string> + <string>{-1, 0}</string> + </array> + <key>Shape</key> + <string>Rectangle</string> + <key>Style</key> + <dict> + <key>fill</key> + <dict> + <key>FillType</key> + <integer>2</integer> + <key>GradientAngle</key> + <real>90</real> + <key>GradientColor</key> + <dict> + <key>w</key> + <string>0.666667</string> + </dict> + </dict> + <key>stroke</key> + <dict> + <key>CornerRadius</key> + <real>5</real> + </dict> + </dict> + <key>Text</key> + <dict> + <key>Text</key> + <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340 +\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 TransactionTestCase}</string> + </dict> + </dict> + <dict> + <key>Bounds</key> + <string>{{54, 459}, {162, 27}}</string> + <key>Class</key> + <string>ShapedGraphic</string> + <key>ID</key> + <integer>7</integer> + <key>Magnets</key> + <array> + <string>{0, 1}</string> + <string>{0, -1}</string> + <string>{1, 0}</string> + <string>{-1, 0}</string> + </array> + <key>Shape</key> + <string>Rectangle</string> + <key>Style</key> + <dict> + <key>fill</key> + <dict> + <key>FillType</key> + <integer>2</integer> + <key>GradientAngle</key> + <real>90</real> + <key>GradientColor</key> + <dict> + <key>w</key> + <string>0.666667</string> + </dict> + </dict> + <key>stroke</key> + <dict> + <key>CornerRadius</key> + <real>5</real> + </dict> + </dict> + <key>Text</key> + <dict> + <key>Text</key> + <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340 +\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 TestCase}</string> + </dict> + </dict> + <dict> + <key>Bounds</key> + <string>{{288, 459}, {162, 27}}</string> + <key>Class</key> + <string>ShapedGraphic</string> + <key>ID</key> + <integer>6</integer> + <key>Magnets</key> + <array> + <string>{0, 1}</string> + <string>{0, -1}</string> + <string>{1, 0}</string> + <string>{-1, 0}</string> + </array> + <key>Shape</key> + <string>Rectangle</string> + <key>Style</key> + <dict> + <key>fill</key> + <dict> + <key>FillType</key> + <integer>2</integer> + <key>GradientAngle</key> + <real>90</real> + <key>GradientColor</key> + <dict> + <key>w</key> + <string>0.666667</string> + </dict> + </dict> + <key>stroke</key> + <dict> + <key>CornerRadius</key> + <real>5</real> + </dict> + </dict> + <key>Text</key> + <dict> + <key>Text</key> + <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340 +\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 LiveServerTestCase}</string> + </dict> + </dict> + <dict> + <key>Bounds</key> + <string>{{18, 297}, {468, 207}}</string> + <key>Class</key> + <string>ShapedGraphic</string> + <key>ID</key> + <integer>13</integer> + <key>Shape</key> + <string>Rectangle</string> + <key>Style</key> + <dict/> + <key>Text</key> + <dict> + <key>Align</key> + <integer>2</integer> + <key>Text</key> + <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340 +\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qr + +\f0\fs24 \cf0 django.test}</string> + </dict> + <key>TextPlacement</key> + <integer>0</integer> + </dict> + <dict> + <key>Bounds</key> + <string>{{18, 153}, {225, 90}}</string> + <key>Class</key> + <string>ShapedGraphic</string> + <key>ID</key> + <integer>18</integer> + <key>Shape</key> + <string>Rectangle</string> + <key>Style</key> + <dict/> + <key>Text</key> + <dict> + <key>Align</key> + <integer>2</integer> + <key>Text</key> + <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340 +\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qr + +\f0\fs24 \cf0 django.utils.unittest\ += unittest (standard library)}</string> + </dict> + <key>TextPlacement</key> + <integer>0</integer> + </dict> + <dict> + <key>Bounds</key> + <string>{{261, 153}, {225, 90}}</string> + <key>Class</key> + <string>ShapedGraphic</string> + <key>ID</key> + <integer>19</integer> + <key>Shape</key> + <string>Rectangle</string> + <key>Style</key> + <dict/> + <key>Text</key> + <dict> + <key>Align</key> + <integer>2</integer> + <key>Text</key> + <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340 +\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qr + +\f0\fs24 \cf0 django.utils.unittest\ += unittest2 (bundled copy)}</string> + </dict> + <key>TextPlacement</key> + <integer>0</integer> + </dict> + </array> + <key>GridInfo</key> + <dict> + <key>ShowsGrid</key> + <string>YES</string> + <key>SnapsToGrid</key> + <string>YES</string> + </dict> + <key>GuidesLocked</key> + <string>NO</string> + <key>GuidesVisible</key> + <string>YES</string> + <key>HPages</key> + <integer>1</integer> + <key>ImageCounter</key> + <integer>1</integer> + <key>KeepToScale</key> + <false/> + <key>Layers</key> + <array> + <dict> + <key>Lock</key> + <string>NO</string> + <key>Name</key> + <string>Calque 1</string> + <key>Print</key> + <string>YES</string> + <key>View</key> + <string>YES</string> + </dict> + </array> + <key>LayoutInfo</key> + <dict> + <key>Animate</key> + <string>NO</string> + <key>circoMinDist</key> + <real>18</real> + <key>circoSeparation</key> + <real>0.0</real> + <key>layoutEngine</key> + <string>dot</string> + <key>neatoSeparation</key> + <real>0.0</real> + <key>twopiSeparation</key> + <real>0.0</real> + </dict> + <key>LinksVisible</key> + <string>NO</string> + <key>MagnetsVisible</key> + <string>NO</string> + <key>MasterSheets</key> + <array/> + <key>ModificationDate</key> + <string>2012-12-16 19:08:28 +0000</string> + <key>Modifier</key> + <string>Aymeric Augustin</string> + <key>NotesVisible</key> + <string>NO</string> + <key>Orientation</key> + <integer>2</integer> + <key>OriginVisible</key> + <string>NO</string> + <key>PageBreaks</key> + <string>YES</string> + <key>PrintInfo</key> + <dict> + <key>NSBottomMargin</key> + <array> + <string>float</string> + <string>41</string> + </array> + <key>NSHorizonalPagination</key> + <array> + <string>coded</string> + <string>BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFxlwCG</string> + </array> + <key>NSLeftMargin</key> + <array> + <string>float</string> + <string>18</string> + </array> + <key>NSPaperSize</key> + <array> + <string>size</string> + <string>{595.28997802734375, 841.8900146484375}</string> + </array> + <key>NSPrintReverseOrientation</key> + <array> + <string>int</string> + <string>0</string> + </array> + <key>NSRightMargin</key> + <array> + <string>float</string> + <string>18</string> + </array> + <key>NSTopMargin</key> + <array> + <string>float</string> + <string>18</string> + </array> + </dict> + <key>PrintOnePage</key> + <false/> + <key>ReadOnly</key> + <string>NO</string> + <key>RowAlign</key> + <integer>1</integer> + <key>RowSpacing</key> + <real>36</real> + <key>SheetTitle</key> + <string>Canevas 1</string> + <key>SmartAlignmentGuidesActive</key> + <string>YES</string> + <key>SmartDistanceGuidesActive</key> + <string>YES</string> + <key>UniqueID</key> + <integer>1</integer> + <key>UseEntirePage</key> + <false/> + <key>VPages</key> + <integer>1</integer> + <key>WindowInfo</key> + <dict> + <key>CurrentSheet</key> + <integer>0</integer> + <key>ExpandedCanvases</key> + <array/> + <key>Frame</key> + <string>{{9, 4}, {694, 874}}</string> + <key>ListView</key> + <true/> + <key>OutlineWidth</key> + <integer>142</integer> + <key>RightSidebar</key> + <false/> + <key>ShowRuler</key> + <true/> + <key>Sidebar</key> + <true/> + <key>SidebarWidth</key> + <integer>120</integer> + <key>VisibleRegion</key> + <string>{{0, 0}, {559, 735}}</string> + <key>Zoom</key> + <real>1</real> + <key>ZoomValues</key> + <array> + <array> + <string>Canevas 1</string> + <real>1</real> + <real>1</real> + </array> + </array> + </dict> +</dict> +</plist> diff --git a/docs/topics/_images/django_unittest_classes_hierarchy.pdf b/docs/topics/_images/django_unittest_classes_hierarchy.pdf Binary files differnew file mode 100644 index 0000000000..cedaba22ac --- /dev/null +++ b/docs/topics/_images/django_unittest_classes_hierarchy.pdf diff --git a/docs/topics/_images/django_unittest_classes_hierarchy.png b/docs/topics/_images/django_unittest_classes_hierarchy.png Binary files differdeleted file mode 100644 index 5f28b56ed6..0000000000 --- a/docs/topics/_images/django_unittest_classes_hierarchy.png +++ /dev/null diff --git a/docs/topics/_images/django_unittest_classes_hierarchy.svg b/docs/topics/_images/django_unittest_classes_hierarchy.svg new file mode 100644 index 0000000000..0482f044dd --- /dev/null +++ b/docs/topics/_images/django_unittest_classes_hierarchy.svg @@ -0,0 +1,3 @@ +<?xml version="1.0"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" version="1.1" viewBox="-2 137 508 391" width="508pt" height="391pt"><metadata xmlns:dc="http://purl.org/dc/elements/1.1/"><dc:date>2012-12-16 19:08Z</dc:date><!-- Produced by OmniGraffle Professional 5.4.2 --></metadata><defs><filter id="Shadow" filterUnits="userSpaceOnUse"><feGaussianBlur in="SourceAlpha" result="blur" stdDeviation="3.488"/><feOffset in="blur" result="offset" dx="0" dy="4"/><feFlood flood-color="black" flood-opacity=".75" result="flood"/><feComposite in="flood" in2="offset" operator="in"/></filter><font-face font-family="Courier" font-size="12" units-per-em="1000" underline-position="-178.22266" underline-thickness="57.617188" slope="0" x-height="462.40234" cap-height="594.72656" ascent="753.90625" descent="-246.09375" font-weight="500"><font-face-src><font-face-name name="Courier"/></font-face-src></font-face><linearGradient x1="0" x2="1" id="Gradient" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#aaa"/></linearGradient><linearGradient id="Obj_Gradient" xl:href="#Gradient" gradientTransform="translate(369 459) rotate(90) scale(27)"/><linearGradient id="Obj_Gradient_2" xl:href="#Gradient" gradientTransform="translate(135 459) rotate(90) scale(27)"/><linearGradient id="Obj_Gradient_3" xl:href="#Gradient" gradientTransform="translate(135 387) rotate(90) scale(27)"/><linearGradient id="Obj_Gradient_4" xl:href="#Gradient" gradientTransform="translate(135 315) rotate(90) scale(27)"/><linearGradient id="Obj_Gradient_5" xl:href="#Gradient" gradientTransform="translate(135 198) rotate(90) scale(27)"/><linearGradient id="Obj_Gradient_6" xl:href="#Gradient" gradientTransform="translate(369 198) rotate(90) scale(27)"/><font-face font-family="Helvetica" font-size="12" units-per-em="1000" underline-position="-75.683594" underline-thickness="49.316406" slope="-1e3" x-height="522.94922" cap-height="717.28516" ascent="770.01953" descent="-229.98047" font-style="italic" font-weight="500"><font-face-src><font-face-name name="Helvetica-Oblique"/></font-face-src></font-face><marker orient="auto" overflow="visible" markerUnits="strokeWidth" id="UMLInheritance_Marker" viewBox="-1 -7 12 14" markerWidth="12" markerHeight="14" color="black"><g><path d="M 9.5999994 0 L 0 -5.5999997 L 0 5.5999997 Z" fill="none" stroke="currentColor" stroke-width="1"/></g></marker></defs><g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1"><title>Canevas 1</title><rect fill="white" width="559.28998" height="782.89"/><g><title>Calque 1</title><g><use xl:href="#id19_Graphic" filter="url(#Shadow)"/><use xl:href="#id18_Graphic" filter="url(#Shadow)"/><use xl:href="#id13_Graphic" filter="url(#Shadow)"/><use xl:href="#id6_Graphic" filter="url(#Shadow)"/><use xl:href="#id7_Graphic" filter="url(#Shadow)"/><use xl:href="#id8_Graphic" filter="url(#Shadow)"/><use xl:href="#id9_Graphic" filter="url(#Shadow)"/><use xl:href="#id10_Graphic" filter="url(#Shadow)"/><use xl:href="#id12_Graphic" filter="url(#Shadow)"/><use xl:href="#id20_Graphic" filter="url(#Shadow)"/><use xl:href="#id22_Graphic" filter="url(#Shadow)"/></g><g id="id19_Graphic"><rect x="261" y="153" width="225" height="90" fill="white"/><rect x="261" y="153" width="225" height="90" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(266 158)" fill="black"><tspan font-family="Courier" font-size="12" font-weight="500" x="63.77539" y="11" textLength="151.22461">django.utils.unittest</tspan><tspan font-family="Courier" font-size="12" font-weight="500" x="27.769531" y="25" textLength="187.23047">= unittest2 (bundled copy)</tspan></text></g><g id="id18_Graphic"><rect x="18" y="153" width="225" height="90" fill="white"/><rect x="18" y="153" width="225" height="90" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(23 158)" fill="black"><tspan font-family="Courier" font-size="12" font-weight="500" x="63.77539" y="11" textLength="151.22461">django.utils.unittest</tspan><tspan font-family="Courier" font-size="12" font-weight="500" x="6.1660156" y="25" textLength="208.83398">= unittest (standard library)</tspan></text></g><g id="id13_Graphic"><rect x="18" y="297" width="468" height="207" fill="white"/><rect x="18" y="297" width="468" height="207" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(23 302)" fill="black"><tspan font-family="Courier" font-size="12" font-weight="500" x="378.7871" y="11" textLength="79.21289">django.test</tspan></text></g><g id="id6_Graphic"><path d="M 293 459 L 445 459 C 447.76142 459 450 461.23858 450 464 L 450 481 C 450 483.76142 447.76142 486 445 486 L 293 486 C 290.23858 486 288 483.76142 288 481 C 288 481 288 481 288 481 L 288 464 C 288 461.23858 290.23858 459 293 459 C 293 459 293 459 293 459 Z" fill="url(#Obj_Gradient)"/><path d="M 293 459 L 445 459 C 447.76142 459 450 461.23858 450 464 L 450 481 C 450 483.76142 447.76142 486 445 486 L 293 486 C 290.23858 486 288 483.76142 288 481 C 288 481 288 481 288 481 L 288 464 C 288 461.23858 290.23858 459 293 459 C 293 459 293 459 293 459 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(293 465.5)" fill="black"><tspan font-family="Courier" font-size="12" font-weight="500" x="11.189453" y="11" textLength="129.62109">LiveServerTestCase</tspan></text></g><g id="id7_Graphic"><path d="M 59 459 L 211 459 C 213.76142 459 216 461.23858 216 464 L 216 481 C 216 483.76142 213.76142 486 211 486 L 59 486 C 56.238576 486 54 483.76142 54 481 C 54 481 54 481 54 481 L 54 464 C 54 461.23858 56.238576 459 59 459 C 59 459 59 459 59 459 Z" fill="url(#Obj_Gradient_2)"/><path d="M 59 459 L 211 459 C 213.76142 459 216 461.23858 216 464 L 216 481 C 216 483.76142 213.76142 486 211 486 L 59 486 C 56.238576 486 54 483.76142 54 481 C 54 481 54 481 54 481 L 54 464 C 54 461.23858 56.238576 459 59 459 C 59 459 59 459 59 459 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(59 465.5)" fill="black"><tspan font-family="Courier" font-size="12" font-weight="500" x="47.195312" y="11" textLength="57.609375">TestCase</tspan></text></g><g id="id8_Graphic"><path d="M 59 387 L 211 387 C 213.76142 387 216 389.23858 216 392 L 216 409 C 216 411.76142 213.76142 414 211 414 L 59 414 C 56.238576 414 54 411.76142 54 409 C 54 409 54 409 54 409 L 54 392 C 54 389.23858 56.238576 387 59 387 C 59 387 59 387 59 387 Z" fill="url(#Obj_Gradient_3)"/><path d="M 59 387 L 211 387 C 213.76142 387 216 389.23858 216 392 L 216 409 C 216 411.76142 213.76142 414 211 414 L 59 414 C 56.238576 414 54 411.76142 54 409 C 54 409 54 409 54 409 L 54 392 C 54 389.23858 56.238576 387 59 387 C 59 387 59 387 59 387 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(59 393.5)" fill="black"><tspan font-family="Courier" font-size="12" font-weight="500" x="7.588867" y="11" textLength="136.822266">TransactionTestCase</tspan></text></g><g id="id9_Graphic"><path d="M 59 315 L 211 315 C 213.76142 315 216 317.23858 216 320 L 216 337 C 216 339.76142 213.76142 342 211 342 L 59 342 C 56.238576 342 54 339.76142 54 337 C 54 337 54 337 54 337 L 54 320 C 54 317.23858 56.238576 315 59 315 C 59 315 59 315 59 315 Z" fill="url(#Obj_Gradient_4)"/><path d="M 59 315 L 211 315 C 213.76142 315 216 317.23858 216 320 L 216 337 C 216 339.76142 213.76142 342 211 342 L 59 342 C 56.238576 342 54 339.76142 54 337 C 54 337 54 337 54 337 L 54 320 C 54 317.23858 56.238576 315 59 315 C 59 315 59 315 59 315 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(59 321.5)" fill="black"><tspan font-family="Courier" font-size="12" font-weight="500" x="25.591797" y="11" textLength="100.816406">SimpleTestCase</tspan></text></g><g id="id10_Graphic"><path d="M 59 198 L 211 198 C 213.76142 198 216 200.23858 216 203 L 216 220 C 216 222.76142 213.76142 225 211 225 L 59 225 C 56.238576 225 54 222.76142 54 220 C 54 220 54 220 54 220 L 54 203 C 54 200.23858 56.238576 198 59 198 C 59 198 59 198 59 198 Z" fill="url(#Obj_Gradient_5)"/><path d="M 59 198 L 211 198 C 213.76142 198 216 200.23858 216 203 L 216 220 C 216 222.76142 213.76142 225 211 225 L 59 225 C 56.238576 225 54 222.76142 54 220 C 54 220 54 220 54 220 L 54 203 C 54 200.23858 56.238576 198 59 198 C 59 198 59 198 59 198 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(59 204.5)" fill="black"><tspan font-family="Courier" font-size="12" font-weight="500" x="47.195312" y="11" textLength="57.609375">TestCase</tspan></text></g><g id="id12_Graphic"><path d="M 293 198 L 445 198 C 447.76142 198 450 200.23858 450 203 L 450 220 C 450 222.76142 447.76142 225 445 225 L 293 225 C 290.23858 225 288 222.76142 288 220 C 288 220 288 220 288 220 L 288 203 C 288 200.23858 290.23858 198 293 198 C 293 198 293 198 293 198 Z" fill="url(#Obj_Gradient_6)"/><path d="M 293 198 L 445 198 C 447.76142 198 450 200.23858 450 203 L 450 220 C 450 222.76142 447.76142 225 445 225 L 293 225 C 290.23858 225 288 222.76142 288 220 C 288 220 288 220 288 220 L 288 203 C 288 200.23858 290.23858 198 293 198 C 293 198 293 198 293 198 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(293 204.5)" fill="black"><tspan font-family="Courier" font-size="12" font-weight="500" x="47.195312" y="11" textLength="57.609375">TestCase</tspan></text></g><g id="id20_Graphic"><path d="M 126 259.9893 C 126 257.43159 124.9713 257.11515 117.45693 254.5839 L 117.37755 254.55771 C 109.82349 252 109.74492 252 101.99241 252 C 91.66977 252 45 252 45 252 L 45 279 L 126 279 L 126 259.9893 Z" fill="white"/><path d="M 126 259.9893 C 126 257.43159 124.9713 257.11515 117.45693 254.5839 L 117.37755 254.55771 C 109.82349 252 109.74492 252 101.99241 252 C 91.66977 252 45 252 45 252 L 45 279 L 126 279 L 126 259.9893 Z M 126 259.85754 C 126 257.43159 125.92062 257.43159 109.74492 257.43159 L 109.74492 257.43159 C 109.74492 252.02646 109.74492 252 102.46707 252" stroke="green" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(50 258.5)" fill="green"><tspan font-family="Helvetica" font-size="12" font-style="italic" font-weight="500" fill="green" x="1.8525391" y="11" textLength="67.29492">Python ≥ 2.7</tspan></text></g><g id="id22_Graphic"><path d="M 459 259.9893 C 459 257.43159 457.9713 257.11515 450.45693 254.5839 L 450.37755 254.55771 C 442.8235 252 442.74492 252 434.9924 252 C 424.66977 252 378 252 378 252 L 378 279 L 459 279 L 459 259.9893 Z" fill="white"/><path d="M 459 259.9893 C 459 257.43159 457.9713 257.11515 450.45693 254.5839 L 450.37755 254.55771 C 442.8235 252 442.74492 252 434.9924 252 C 424.66977 252 378 252 378 252 L 378 279 L 459 279 L 459 259.9893 Z M 459 259.85754 C 459 257.43159 458.92062 257.43159 442.74492 257.43159 L 442.74492 257.43159 C 442.74492 252.02646 442.74492 252 435.46707 252" stroke="green" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(383 258.5)" fill="green"><tspan font-family="Helvetica" font-size="12" font-style="italic" font-weight="500" fill="green" x="1.6416016" y="11" textLength="67.716797">Python < 2.7</tspan></text></g><path d="M 135 459 L 135 445.9 L 135 427.1 L 135 425.1" marker-end="url(#UMLInheritance_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 135 387 L 135 373.9 L 135 355.1 L 135 353.1" marker-end="url(#UMLInheritance_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 135 315 L 135 301.9 L 135 238.1 L 135 236.1" marker-end="url(#UMLInheritance_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 135 270 L 148.1 270 L 369 270 L 369 238.1 L 369 236.1" marker-end="url(#UMLInheritance_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 369 459 L 369 445.9 L 369 400.5 L 229.1 400.5 L 227.1 400.5" marker-end="url(#UMLInheritance_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/></g></g></svg> diff --git a/docs/topics/auth.txt b/docs/topics/auth.txt index 41159984f6..3e2b6bbdbf 100644 --- a/docs/topics/auth.txt +++ b/docs/topics/auth.txt @@ -408,7 +408,7 @@ installation supports. The first entry in this list (that is, ``settings.PASSWORD_HASHERS[0]``) will be used to store passwords, and all the other entries are valid hashers that can be used to check existing passwords. This means that if you want to use a different algorithm, you'll need to modify -:setting:`PASSWORD_HASHERS` to list your prefered algorithm first in the list. +:setting:`PASSWORD_HASHERS` to list your preferred algorithm first in the list. The default for :setting:`PASSWORD_HASHERS` is:: @@ -1889,7 +1889,7 @@ password resets. You must then provide some key implementation details: as the identifying field:: class MyUser(AbstractBaseUser): - identfier = models.CharField(max_length=40, unique=True, db_index=True) + identifier = models.CharField(max_length=40, unique=True, db_index=True) ... USERNAME_FIELD = 'identifier' @@ -1911,6 +1911,15 @@ password resets. You must then provide some key implementation details: ``REQUIRED_FIELDS`` must contain all required fields on your User model, but should *not* contain the ``USERNAME_FIELD``. + .. attribute:: User.is_active + + A boolean attribute that indicates whether the user is considered + "active". This attribute is provided as an attribute on + ``AbstractBaseUser`` defaulting to ``True``. How you choose to + implement it will depend on the details of your chosen auth backends. + See the documentation of the :attr:`attribute on the builtin user model + <django.contrib.auth.models.User.is_active>` for details. + .. method:: User.get_full_name(): A longer formal identifier for the user. A common interpretation @@ -2000,7 +2009,7 @@ additional methods: .. method:: models.CustomUserManager.create_superuser(*username_field*, password, **other_fields) - The prototype of `create_user()` should accept the username field, + The prototype of `create_superuser()` should accept the username field, plus all required fields as arguments. For example, if your user model uses `email` as the username field, and has `date_of_birth` as a required fields, then create_superuser should be defined as:: @@ -2127,6 +2136,76 @@ override any of the definitions that refer to fields on :class:`~django.contrib.auth.models.AbstractUser` that aren't on your custom User class. +Custom users and permissions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To make it easy to include Django's permission framework into your own User +class, Django provides :class:`~django.contrib.auth.model.PermissionsMixin`. +This is an abstract model you can include in the class heirarchy for your User +model, giving you all the methods and database fields necessary to support +Django's permission model. + +:class:`~django.contrib.auth.model.PermissionsMixin` provides the following +methods and attributes: + +.. class:: models.PermissionsMixin + + .. attribute:: models.PermissionsMixin.is_superuser + + Boolean. Designates that this user has all permissions without + explicitly assigning them. + + .. method:: models.PermissionsMixin.get_group_permissions(obj=None) + + Returns a set of permission strings that the user has, through his/her + groups. + + If ``obj`` is passed in, only returns the group permissions for + this specific object. + + .. method:: models.PermissionsMixin.get_all_permissions(obj=None) + + Returns a set of permission strings that the user has, both through + group and user permissions. + + If ``obj`` is passed in, only returns the permissions for this + specific object. + + .. method:: models.PermissionsMixin.has_perm(perm, obj=None) + + Returns ``True`` if the user has the specified permission, where perm is + in the format ``"<app label>.<permission codename>"`` (see + `permissions`_). If the user is inactive, this method will + always return ``False``. + + If ``obj`` is passed in, this method won't check for a permission for + the model, but for this specific object. + + .. method:: models.PermissionsMixin.has_perms(perm_list, obj=None) + + Returns ``True`` if the user has each of the specified permissions, + where each perm is in the format + ``"<app label>.<permission codename>"``. If the user is inactive, + this method will always return ``False``. + + If ``obj`` is passed in, this method won't check for permissions for + the model, but for the specific object. + + .. method:: models.PermissionsMixin.has_module_perms(package_name) + + Returns ``True`` if the user has any permissions in the given package + (the Django app label). If the user is inactive, this method will + always return ``False``. + +.. admonition:: ModelBackend + + If you don't include the + :class:`~django.contrib.auth.model.PermissionsMixin`, you must ensure you + don't invoke the permissions methods on ``ModelBackend``. ``ModelBackend`` + assumes that certain fields are available on your user model. If your User + model doesn't provide those fields, you will receive database errors when + you check permissions. + Custom users and Proxy models ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2139,6 +2218,68 @@ If your project uses proxy models, you must either modify the proxy to extend the User model that is currently in use in your project, or merge your proxy's behavior into your User subclass. +Custom users and signals +~~~~~~~~~~~~~~~~~~~~~~~~ + +Another limitation of custom User models is that you can't use +:func:`django.contrib.auth.get_user_model()` as the sender or target of a signal +handler. Instead, you must register the handler with the actual User model. + +Custom users and testing/fixtures +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you are writing an application that interacts with the User model, you must +take some precautions to ensure that your test suite will run regardless of +the User model that is being used by a project. Any test that instantiates an +instance of User will fail if the User model has been swapped out. This +includes any attempt to create an instance of User with a fixture. + +To ensure that your test suite will pass in any project configuration, +``django.contrib.auth.tests.utils`` defines a ``@skipIfCustomUser`` decorator. +This decorator will cause a test case to be skipped if any User model other +than the default Django user is in use. This decorator can be applied to a +single test, or to an entire test class. + +Depending on your application, tests may also be needed to be added to ensure +that the application works with *any* user model, not just the default User +model. To assist with this, Django provides two substitute user models that +can be used in test suites: + +* :class:`django.contrib.auth.tests.custom_user.CustomUser`, a custom user + model that uses an ``email`` field as the username, and has a basic + admin-compliant permissions setup + +* :class:`django.contrib.auth.tests.custom_user.ExtensionUser`, a custom + user model that extends :class:`~django.contrib.auth.models.AbstractUser`, + adding a ``date_of_birth`` field. + +You can then use the ``@override_settings`` decorator to make that test run +with the custom User model. For example, here is a skeleton for a test that +would test three possible User models -- the default, plus the two User +models provided by ``auth`` app:: + + from django.contrib.auth.tests.utils import skipIfCustomUser + from django.test import TestCase + from django.test.utils import override_settings + + + class ApplicationTestCase(TestCase): + @skipIfCustomUser + def test_normal_user(self): + "Run tests for the normal user model" + self.assertSomething() + + @override_settings(AUTH_USER_MODEL='auth.CustomUser') + def test_custom_user(self): + "Run tests for a custom user model with email-based authentication" + self.assertSomething() + + @override_settings(AUTH_USER_MODEL='auth.ExtensionUser') + def test_extension_user(self): + "Run tests for a simple extension of the built-in User." + self.assertSomething() + + A full example -------------- @@ -2272,15 +2413,21 @@ code would be required in the app's ``admin.py`` file:: class UserChangeForm(forms.ModelForm): - """A form for updateing users. Includes all the fields on + """A form for updating users. Includes all the fields on the user, but replaces the password field with admin's - pasword hash display field. + password hash display field. """ password = ReadOnlyPasswordHashField() class Meta: model = MyUser + def clean_password(self): + # Regardless of what the user provides, return the initial value. + # This is done here, rather than on the field, because the + # field does not have access to the initial value + return self.initial["password"] + class MyUserAdmin(UserAdmin): # The forms to add and change user instances @@ -2376,6 +2523,12 @@ processing at the first positive match. you need to force users to re-authenticate using different methods. A simple way to do that is simply to execute ``Session.objects.all().delete()``. +.. versionadded:: 1.6 + +If a backend raises a :class:`~django.core.exceptions.PermissionDenied` +exception, authentication will immediately fail. Django won't check the +backends that follow. + Writing an authentication backend --------------------------------- diff --git a/docs/topics/cache.txt b/docs/topics/cache.txt index 2f95c33dd5..a15cf58370 100644 --- a/docs/topics/cache.txt +++ b/docs/topics/cache.txt @@ -785,6 +785,16 @@ nonexistent cache key.:: However, if the backend doesn't natively provide an increment/decrement operation, it will be implemented using a two-step retrieve/update. + +You can close the connection to your cache with ``close()`` if implemented by +the cache backend. + + >>> cache.close() + +.. note:: + + For caches that don't implement ``close`` methods it is a no-op. + .. _cache_key_prefixing: Cache key prefixing diff --git a/docs/topics/class-based-views/generic-editing.txt b/docs/topics/class-based-views/generic-editing.txt index 7bae3c692d..7d12184705 100644 --- a/docs/topics/class-based-views/generic-editing.txt +++ b/docs/topics/class-based-views/generic-editing.txt @@ -90,8 +90,8 @@ class: .. code-block:: python # models.py - from django import models from django.core.urlresolvers import reverse + from django.db import models class Author(models.Model): name = models.CharField(max_length=200) @@ -102,7 +102,7 @@ class: Then we can use :class:`CreateView` and friends to do the actual work. Notice how we're just configuring the generic class-based views here; we don't have to write any logic ourselves:: - + # views.py from django.views.generic.edit import CreateView, UpdateView, DeleteView from django.core.urlresolvers import reverse_lazy @@ -134,7 +134,7 @@ Finally, we hook these new views into the URLconf:: url(r'author/(?P<pk>\d+)/$', AuthorUpdate.as_view(), name='author_update'), url(r'author/(?P<pk>\d+)/delete/$', AuthorDelete.as_view(), name='author_delete'), ) - + .. note:: These views inherit :class:`~django.views.generic.detail.SingleObjectTemplateResponseMixin` @@ -160,8 +160,8 @@ you can use a custom :class:`ModelForm` to do this. First, add the foreign key relation to the model:: # models.py - from django import models from django.contrib.auth import User + from django.db import models class Author(models.Model): name = models.CharField(max_length=200) @@ -177,7 +177,7 @@ Create a custom :class:`ModelForm` in order to exclude the # forms.py from django import forms from myapp.models import Author - + class AuthorForm(forms.ModelForm): class Meta: model = Author @@ -190,7 +190,7 @@ In the view, use the custom :attr:`form_class` and override from django.views.generic.edit import CreateView from myapp.models import Author from myapp.forms import AuthorForm - + class AuthorCreate(CreateView): form_class = AuthorForm model = Author diff --git a/docs/topics/class-based-views/index.txt b/docs/topics/class-based-views/index.txt index a738221892..54d4b0f252 100644 --- a/docs/topics/class-based-views/index.txt +++ b/docs/topics/class-based-views/index.txt @@ -24,9 +24,9 @@ Basic examples Django provides base view classes which will suit a wide range of applications. All views inherit from the :class:`~django.views.generic.base.View` class, which handles linking the view in to the URLs, HTTP method dispatching and other -simple features. :class:`~django.views.generic.base.RedirectView` is for a simple HTTP -redirect, and :class:`~django.views.generic.base.TemplateView` extends the base class -to make it also render a template. +simple features. :class:`~django.views.generic.base.RedirectView` is for a +simple HTTP redirect, and :class:`~django.views.generic.base.TemplateView` +extends the base class to make it also render a template. Simple usage in your URLconf @@ -34,7 +34,8 @@ Simple usage in your URLconf The simplest way to use generic views is to create them directly in your URLconf. If you're only changing a few simple attributes on a class-based view, -you can simply pass them into the ``as_view`` method call itself:: +you can simply pass them into the +:meth:`~django.views.generic.base.View.as_view` method call itself:: from django.conf.urls import patterns, url, include from django.views.generic import TemplateView @@ -43,9 +44,10 @@ you can simply pass them into the ``as_view`` method call itself:: (r'^about/', TemplateView.as_view(template_name="about.html")), ) -Any arguments given will override the ``template_name`` on the -A similar overriding pattern can be used for the ``url`` attribute on -:class:`~django.views.generic.base.RedirectView`. +Any arguments passed to :meth:`~django.views.generic.base.View.as_view` will +override attributes set on the class. In this example, we set ``template_name`` +on the ``TemplateView``. A similar overriding pattern can be used for the +``url`` attribute on :class:`~django.views.generic.base.RedirectView`. Subclassing generic views @@ -67,8 +69,8 @@ and override the template name:: Then we just need to add this new view into our URLconf. `~django.views.generic.base.TemplateView` is a class, not a function, so we -point the URL to the ``as_view`` class method instead, which provides a -function-like entry to class-based views:: +point the URL to the :meth:`~django.views.generic.base.View.as_view` class +method instead, which provides a function-like entry to class-based views:: # urls.py from django.conf.urls import patterns, url, include diff --git a/docs/topics/db/managers.txt b/docs/topics/db/managers.txt index eda6f9dac0..a14616a17c 100644 --- a/docs/topics/db/managers.txt +++ b/docs/topics/db/managers.txt @@ -274,6 +274,21 @@ it into the inheritance hierarchy *after* the defaults:: # Default manager is CustomManager, but OtherManager is # also available via the "extra_manager" attribute. +Note that while you can *define* a custom manager on the abstract model, you +can't *invoke* any methods using the abstract model. That is:: + + ClassA.objects.do_something() + +is legal, but:: + + AbstractBase.objects.do_something() + +will raise an exception. This is because managers are intended to encapsulate +logic for managing collections of objects. Since you can't have a collection of +abstract objects, it doesn't make sense to be managing them. If you have +functionality that applies to the abstract model, you should put that functionality +in a ``staticmethod`` or ``classmethod`` on the abstract model. + Implementation concerns ----------------------- diff --git a/docs/topics/db/models.txt b/docs/topics/db/models.txt index 84b4c84061..2f1676ac1a 100644 --- a/docs/topics/db/models.txt +++ b/docs/topics/db/models.txt @@ -673,11 +673,12 @@ For example, this model has a few custom methods:: def baby_boomer_status(self): "Returns the person's baby-boomer status." import datetime - if datetime.date(1945, 8, 1) <= self.birth_date <= datetime.date(1964, 12, 31): - return "Baby boomer" if self.birth_date < datetime.date(1945, 8, 1): return "Pre-boomer" - return "Post-boomer" + elif self.birth_date < datetime.date(1965, 1, 1): + return "Baby boomer" + else: + return "Post-boomer" def is_midwestern(self): "Returns True if this person is from the Midwest." diff --git a/docs/topics/db/multi-db.txt b/docs/topics/db/multi-db.txt index d2ff8645a9..8a02305376 100644 --- a/docs/topics/db/multi-db.txt +++ b/docs/topics/db/multi-db.txt @@ -630,3 +630,49 @@ However, if you're using SQLite or MySQL with MyISAM tables, there is no enforced referential integrity; as a result, you may be able to 'fake' cross database foreign keys. However, this configuration is not officially supported by Django. + +.. _contrib_app_multiple_databases: + +Behavior of contrib apps +------------------------ + +Several contrib apps include models, and some apps depend on others. Since +cross-database relationships are impossible, this creates some restrictions on +how you can split these models across databases: + +- each one of ``contenttypes.ContentType``, ``sessions.Session`` and + ``sites.Site`` can be stored in any database, given a suitable router. +- ``auth`` models — ``User``, ``Group`` and ``Permission`` — are linked + together and linked to ``ContentType``, so they must be stored in the same + database as ``ContentType``. +- ``admin`` and ``comments`` depend on ``auth``, so their models must be in + the same database as ``auth``. +- ``flatpages`` and ``redirects`` depend on ``sites``, so their models must be + in the same database as ``sites``. + +In addition, some objects are automatically created just after +:djadmin:`syncdb` creates a table to hold them in a database: + +- a default ``Site``, +- a ``ContentType`` for each model (including those not stored in that + database), +- three ``Permission`` for each model (including those not stored in that + database). + +.. versionchanged:: 1.5 + Previously, ``ContentType`` and ``Permission`` instances were created only + in the default database. + +For common setups with multiple databases, it isn't useful to have these +objects in more than one database. Common setups include master / slave and +connecting to external databases. Therefore, it's recommended: + +- either to run :djadmin:`syncdb` only for the default database; +- or to write :ref:`database router<topics-db-multi-db-routing>` that allows + synchronizing these three models only to one database. + +.. warning:: + + If you're synchronizing content types to more that one database, be aware + that their primary keys may not match across databases. This may result in + data corruption or data loss. diff --git a/docs/topics/db/optimization.txt b/docs/topics/db/optimization.txt index 772792d39d..b5cca52e23 100644 --- a/docs/topics/db/optimization.txt +++ b/docs/topics/db/optimization.txt @@ -132,6 +132,41 @@ Write your own :doc:`custom SQL to retrieve data or populate models </topics/db/sql>`. Use ``django.db.connection.queries`` to find out what Django is writing for you and start from there. +Retrieve individual objects using a unique, indexed column +========================================================== + +There are two reasons to use a column with +:attr:`~django.db.models.Field.unique` or +:attr:`~django.db.models.Field.db_index` when using +:meth:`~django.db.models.query.QuerySet.get` to retrieve individual objects. +First, the query will be quicker because of the underlying database index. +Also, the query could run much slower if multiple objects match the lookup; +having a unique constraint on the column guarantees this will never happen. + +So using the :ref:`example Weblog models <queryset-model-example>`:: + + >>> entry = Entry.objects.get(id=10) + +will be quicker than: + + >>> entry = Entry.object.get(headline="News Item Title") + +because ``id`` is indexed by the database and is guaranteed to be unique. + +Doing the following is potentially quite slow: + + >>> entry = Entry.objects.get(headline__startswith="News") + +First of all, `headline` is not indexed, which will make the underlying +database fetch slower. + +Second, the lookup doesn't guarantee that only one object will be returned. +If the query matches more than one object, it will retrieve and transfer all of +them from the database. This penalty could be substantial if hundreds or +thousands of records are returned. The penalty will be compounded if the +database lives on a separate server, where network overhead and latency also +play a factor. + Retrieve everything at once if you know you will need it ======================================================== diff --git a/docs/topics/db/queries.txt b/docs/topics/db/queries.txt index d826a39562..90c06ac66a 100644 --- a/docs/topics/db/queries.txt +++ b/docs/topics/db/queries.txt @@ -417,7 +417,7 @@ translates (roughly) into the following SQL:: There's one exception though, in case of a :class:`~django.db.models.ForeignKey` you can specify the field name suffixed with ``_id``. In this case, the value parameter is expected - to contain the raw value of the foreign model's primary key. For example:: + to contain the raw value of the foreign model's primary key. For example: >>> Entry.objects.filter(blog_id__exact=4) @@ -575,12 +575,17 @@ To select all blogs that contain an entry with *"Lennon"* in the headline Blog.objects.filter(entry__headline__contains='Lennon').filter( entry__pub_date__year=2008) -In this second example, the first filter restricted the queryset to all those -blogs linked to that particular type of entry. The second filter restricted -the set of blogs *further* to those that are also linked to the second type of -entry. The entries select by the second filter may or may not be the same as -the entries in the first filter. We are filtering the ``Blog`` items with each -filter statement, not the ``Entry`` items. +Suppose there is only one blog that had both entries containing *"Lennon"* and +entries from 2008, but that none of the entries from 2008 contained *"Lennon"*. +The first query would not return any blogs, but the second query would return +that one blog. + +In the second example, the first filter restricts the queryset to all those +blogs linked to entries with *"Lennon"* in the headline. The second filter +restricts the set of blogs *further* to those that are also linked to entries +that were published in 2008. The entries selected by the second filter may or +may not be the same as the entries in the first filter. We are filtering the +``Blog`` items with each filter statement, not the ``Entry`` items. All of this behavior also applies to :meth:`~django.db.models.query.QuerySet.exclude`: all the conditions in a @@ -920,7 +925,7 @@ Things get more complicated if you use inheritance. Consider a subclass of class ThemeBlog(Blog): theme = models.CharField(max_length=200) - django_blog = ThemeBlog(name='Django', tagline='Django is easy', theme = 'python') + django_blog = ThemeBlog(name='Django', tagline='Django is easy', theme='python') django_blog.save() # django_blog.pk == 3 Due to how inheritance works, you have to set both ``pk`` and ``id`` to None:: diff --git a/docs/topics/db/transactions.txt b/docs/topics/db/transactions.txt index 4a52c5af35..65944abb8b 100644 --- a/docs/topics/db/transactions.txt +++ b/docs/topics/db/transactions.txt @@ -161,8 +161,12 @@ managers, too. transactions. It tells Django you'll be managing the transaction on your own. - If your view changes data and doesn't ``commit()`` or ``rollback()``, - Django will raise a ``TransactionManagementError`` exception. + Whether you are writing or simply reading from the database, you must + ``commit()`` or ``rollback()`` explicitly or Django will raise a + :exc:`TransactionManagementError` exception. This is required when reading + from the database because ``SELECT`` statements may call functions which + modify tables, and thus it is impossible to know if any data has been + modified. Manual transaction management looks like this:: @@ -204,11 +208,13 @@ This applies to all database operations, not just write operations. Even if your transaction only reads from the database, the transaction must be committed or rolled back before you complete a request. +.. _deactivate-transaction-management: + How to globally deactivate transaction management ================================================= Control freaks can totally disable all transaction management by setting -``DISABLE_TRANSACTION_MANAGEMENT`` to ``True`` in the Django settings file. +:setting:`TRANSACTIONS_MANAGED` to ``True`` in the Django settings file. If you do this, Django won't provide any automatic transaction management whatsoever. Middleware will no longer implicitly commit transactions, and diff --git a/docs/topics/files.txt b/docs/topics/files.txt index c9b4327941..66e104759a 100644 --- a/docs/topics/files.txt +++ b/docs/topics/files.txt @@ -139,6 +139,8 @@ useful -- you can use the global default storage system:: See :doc:`/ref/files/storage` for the file storage API. +.. _builtin-fs-storage: + The built-in filesystem storage class ------------------------------------- diff --git a/docs/topics/forms/modelforms.txt b/docs/topics/forms/modelforms.txt index 692be7cd7c..233346db0d 100644 --- a/docs/topics/forms/modelforms.txt +++ b/docs/topics/forms/modelforms.txt @@ -90,9 +90,6 @@ Model field Form field ``NullBooleanField`` ``CharField`` -``PhoneNumberField`` ``USPhoneNumberField`` - (from ``django.contrib.localflavor.us``) - ``PositiveIntegerField`` ``IntegerField`` ``PositiveSmallIntegerField`` ``IntegerField`` @@ -192,6 +189,8 @@ we'll discuss in a moment.):: name = forms.CharField(max_length=100) authors = forms.ModelMultipleChoiceField(queryset=Author.objects.all()) +.. _modelform-is-valid-and-errors: + The ``is_valid()`` method and ``errors`` ---------------------------------------- @@ -213,7 +212,9 @@ method. This method creates and saves a database object from the data bound to the form. A subclass of ``ModelForm`` can accept an existing model instance as the keyword argument ``instance``; if this is supplied, ``save()`` will update that instance. If it's not supplied, -``save()`` will create a new instance of the specified model:: +``save()`` will create a new instance of the specified model: + +.. code-block:: python # Create a form instance from POST data. >>> f = ArticleForm(request.POST) @@ -232,8 +233,10 @@ supplied, ``save()`` will update that instance. If it's not supplied, >>> f = ArticleForm(request.POST, instance=a) >>> f.save() -Note that ``save()`` will raise a ``ValueError`` if the data in the form -doesn't validate -- i.e., if form.errors evaluates to True. +Note that if the form :ref:`hasn't been validated +<modelform-is-valid-and-errors>`, calling ``save()`` will do so by checking +``form.errors``. A ``ValueError`` will be raised if the data in the form +doesn't validate -- i.e., if ``form.errors`` evaluates to ``True``. This ``save()`` method accepts an optional ``commit`` keyword argument, which accepts either ``True`` or ``False``. If you call ``save()`` with diff --git a/docs/topics/http/_images/middleware.graffle b/docs/topics/http/_images/middleware.graffle new file mode 100644 index 0000000000..4aa85f7611 --- /dev/null +++ b/docs/topics/http/_images/middleware.graffle @@ -0,0 +1,957 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>ActiveLayerIndex</key> + <integer>0</integer> + <key>ApplicationVersion</key> + <array> + <string>com.omnigroup.OmniGrafflePro</string> + <string>139.16.0.171715</string> + </array> + <key>AutoAdjust</key> + <true/> + <key>BackgroundGraphic</key> + <dict> + <key>Bounds</key> + <string>{{0, 0}, {559.28997802734375, 782.8900146484375}}</string> + <key>Class</key> + <string>SolidGraphic</string> + <key>ID</key> + <integer>2</integer> + <key>Style</key> + <dict> + <key>shadow</key> + <dict> + <key>Draws</key> + <string>NO</string> + </dict> + <key>stroke</key> + <dict> + <key>Draws</key> + <string>NO</string> + </dict> + </dict> + </dict> + <key>BaseZoom</key> + <integer>0</integer> + <key>CanvasOrigin</key> + <string>{0, 0}</string> + <key>ColumnAlign</key> + <integer>1</integer> + <key>ColumnSpacing</key> + <real>36</real> + <key>CreationDate</key> + <string>2012-12-09 18:55:12 +0000</string> + <key>Creator</key> + <string>Aymeric Augustin</string> + <key>DisplayScale</key> + <string>1.000 cm = 1.000 cm</string> + <key>GraphDocumentVersion</key> + <integer>8</integer> + <key>GraphicsList</key> + <array> + <dict> + <key>Bounds</key> + <string>{{144, 405}, {369, 27}}</string> + <key>Class</key> + <string>ShapedGraphic</string> + <key>ID</key> + <integer>33</integer> + <key>Shape</key> + <string>Bezier</string> + <key>ShapeData</key> + <dict> + <key>UnitPoints</key> + <array> + <string>{-0.5, -0.5}</string> + <string>{-0.5, -0.5}</string> + <string>{0.47959183673469341, -0.5}</string> + <string>{0.47959183673469408, -0.5}</string> + <string>{0.47959183673469341, -0.5}</string> + <string>{0.5, 0}</string> + <string>{0.5, 0}</string> + <string>{0.5, 0}</string> + <string>{0.47959183673469408, 0.5}</string> + <string>{0.47959183673469408, 0.5}</string> + <string>{0.47959183673469408, 0.5}</string> + <string>{-0.5, 0.5}</string> + <string>{-0.5, 0.5}</string> + <string>{-0.5, 0.5}</string> + <string>{-0.47560975609756084, 0}</string> + <string>{-0.47560975609756084, 0}</string> + <string>{-0.47560975609756084, 0}</string> + <string>{-0.5, -0.5}</string> + </array> + </dict> + <key>Text</key> + <dict> + <key>Text</key> + <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 view function}</string> + </dict> + </dict> + <dict> + <key>Bounds</key> + <string>{{229.5, 238.5}, {297, 36}}</string> + <key>Class</key> + <string>ShapedGraphic</string> + <key>ID</key> + <integer>31</integer> + <key>Rotation</key> + <real>270</real> + <key>Shape</key> + <string>AdjustableArrow</string> + <key>ShapeData</key> + <dict> + <key>width</key> + <real>27</real> + </dict> + <key>Style</key> + <dict> + <key>fill</key> + <dict> + <key>Color</key> + <dict> + <key>a</key> + <string>0.8</string> + <key>b</key> + <string>1</string> + <key>g</key> + <string>1</string> + <key>r</key> + <string>1</string> + </dict> + <key>MiddleFraction</key> + <real>0.70634919404983521</real> + </dict> + <key>shadow</key> + <dict> + <key>Color</key> + <dict> + <key>a</key> + <string>0.4</string> + <key>b</key> + <string>0</string> + <key>g</key> + <string>0</string> + <key>r</key> + <string>0</string> + </dict> + <key>Draws</key> + <string>NO</string> + <key>Fuzziness</key> + <real>0.0</real> + <key>ShadowVector</key> + <string>{0, 2}</string> + </dict> + <key>stroke</key> + <dict> + <key>Color</key> + <dict> + <key>b</key> + <string>0</string> + <key>g</key> + <string>0</string> + <key>r</key> + <string>1</string> + </dict> + <key>Pattern</key> + <integer>1</integer> + </dict> + </dict> + <key>Text</key> + <dict> + <key>Text</key> + <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340 +\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;} +{\colortbl;\red255\green255\blue255;\red255\green0\blue0;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf2 process_exception}</string> + </dict> + <key>TextRelativeArea</key> + <string>{{0.125, 0.25}, {0.75, 0.5}}</string> + <key>isConnectedShape</key> + <true/> + </dict> + <dict> + <key>Bounds</key> + <string>{{328.5, 229.5}, {315, 36}}</string> + <key>Class</key> + <string>ShapedGraphic</string> + <key>ID</key> + <integer>30</integer> + <key>Rotation</key> + <real>270</real> + <key>Shape</key> + <string>AdjustableArrow</string> + <key>ShapeData</key> + <dict> + <key>width</key> + <real>27</real> + </dict> + <key>Style</key> + <dict> + <key>fill</key> + <dict> + <key>Color</key> + <dict> + <key>a</key> + <string>0.8</string> + <key>b</key> + <string>1</string> + <key>g</key> + <string>1</string> + <key>r</key> + <string>1</string> + </dict> + <key>MiddleFraction</key> + <real>0.70634919404983521</real> + </dict> + <key>shadow</key> + <dict> + <key>Color</key> + <dict> + <key>a</key> + <string>0.4</string> + <key>b</key> + <string>0</string> + <key>g</key> + <string>0</string> + <key>r</key> + <string>0</string> + </dict> + <key>Draws</key> + <string>NO</string> + <key>Fuzziness</key> + <real>0.0</real> + <key>ShadowVector</key> + <string>{0, 2}</string> + </dict> + <key>stroke</key> + <dict> + <key>Color</key> + <dict> + <key>b</key> + <string>0</string> + <key>g</key> + <string>0.501961</string> + <key>r</key> + <string>0</string> + </dict> + </dict> + </dict> + <key>Text</key> + <dict> + <key>Text</key> + <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340 +\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;} +{\colortbl;\red255\green255\blue255;\red0\green128\blue0;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf2 process_response}</string> + </dict> + <key>TextRelativeArea</key> + <string>{{0.125, 0.25}, {0.75, 0.5}}</string> + <key>isConnectedShape</key> + <true/> + </dict> + <dict> + <key>Bounds</key> + <string>{{283.5, 238.5}, {297, 36}}</string> + <key>Class</key> + <string>ShapedGraphic</string> + <key>ID</key> + <integer>29</integer> + <key>Rotation</key> + <real>270</real> + <key>Shape</key> + <string>AdjustableArrow</string> + <key>ShapeData</key> + <dict> + <key>width</key> + <real>27</real> + </dict> + <key>Style</key> + <dict> + <key>fill</key> + <dict> + <key>Color</key> + <dict> + <key>a</key> + <string>0.8</string> + <key>b</key> + <string>1</string> + <key>g</key> + <string>1</string> + <key>r</key> + <string>1</string> + </dict> + <key>MiddleFraction</key> + <real>0.70634919404983521</real> + </dict> + <key>shadow</key> + <dict> + <key>Color</key> + <dict> + <key>a</key> + <string>0.4</string> + <key>b</key> + <string>0</string> + <key>g</key> + <string>0</string> + <key>r</key> + <string>0</string> + </dict> + <key>Draws</key> + <string>NO</string> + <key>Fuzziness</key> + <real>0.0</real> + <key>ShadowVector</key> + <string>{0, 2}</string> + </dict> + <key>stroke</key> + <dict> + <key>Color</key> + <dict> + <key>b</key> + <string>0</string> + <key>g</key> + <string>0.501961</string> + <key>r</key> + <string>0</string> + </dict> + <key>Pattern</key> + <integer>1</integer> + </dict> + </dict> + <key>Text</key> + <dict> + <key>Text</key> + <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340 +\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;} +{\colortbl;\red255\green255\blue255;\red0\green128\blue0;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf2 process_template_response}</string> + </dict> + <key>TextRelativeArea</key> + <string>{{0.125, 0.25}, {0.75, 0.5}}</string> + <key>isConnectedShape</key> + <true/> + </dict> + <dict> + <key>Bounds</key> + <string>{{27, 243}, {288, 36}}</string> + <key>Class</key> + <string>ShapedGraphic</string> + <key>ID</key> + <integer>28</integer> + <key>Rotation</key> + <real>90</real> + <key>Shape</key> + <string>AdjustableArrow</string> + <key>ShapeData</key> + <dict> + <key>width</key> + <real>27</real> + </dict> + <key>Style</key> + <dict> + <key>fill</key> + <dict> + <key>Color</key> + <dict> + <key>a</key> + <string>0.8</string> + <key>b</key> + <string>1</string> + <key>g</key> + <string>1</string> + <key>r</key> + <string>1</string> + </dict> + <key>MiddleFraction</key> + <real>0.70634919404983521</real> + </dict> + <key>shadow</key> + <dict> + <key>Color</key> + <dict> + <key>a</key> + <string>0.4</string> + <key>b</key> + <string>0</string> + <key>g</key> + <string>0</string> + <key>r</key> + <string>0</string> + </dict> + <key>Draws</key> + <string>NO</string> + <key>Fuzziness</key> + <real>0.0</real> + <key>ShadowVector</key> + <string>{0, 2}</string> + </dict> + <key>stroke</key> + <dict> + <key>Color</key> + <dict> + <key>b</key> + <string>0</string> + <key>g</key> + <string>0.501961</string> + <key>r</key> + <string>0</string> + </dict> + </dict> + </dict> + <key>Text</key> + <dict> + <key>Text</key> + <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340 +\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;} +{\colortbl;\red255\green255\blue255;\red0\green128\blue0;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf2 process_view}</string> + </dict> + <key>TextRelativeArea</key> + <string>{{0.125, 0.25}, {0.75, 0.5}}</string> + <key>isConnectedShape</key> + <true/> + </dict> + <dict> + <key>Bounds</key> + <string>{{-40.500000000767386, 220.49999999804004}, {297, 36}}</string> + <key>Class</key> + <string>ShapedGraphic</string> + <key>ID</key> + <integer>27</integer> + <key>Rotation</key> + <real>90</real> + <key>Shape</key> + <string>AdjustableArrow</string> + <key>ShapeData</key> + <dict> + <key>width</key> + <real>27</real> + </dict> + <key>Style</key> + <dict> + <key>fill</key> + <dict> + <key>Color</key> + <dict> + <key>a</key> + <string>0.8</string> + <key>b</key> + <string>1</string> + <key>g</key> + <string>1</string> + <key>r</key> + <string>1</string> + </dict> + <key>MiddleFraction</key> + <real>0.70634919404983521</real> + </dict> + <key>shadow</key> + <dict> + <key>Color</key> + <dict> + <key>a</key> + <string>0.4</string> + <key>b</key> + <string>0</string> + <key>g</key> + <string>0</string> + <key>r</key> + <string>0</string> + </dict> + <key>Draws</key> + <string>NO</string> + <key>Fuzziness</key> + <real>0.0</real> + <key>ShadowVector</key> + <string>{0, 2}</string> + </dict> + <key>stroke</key> + <dict> + <key>Color</key> + <dict> + <key>b</key> + <string>0</string> + <key>g</key> + <string>0.501961</string> + <key>r</key> + <string>0</string> + </dict> + </dict> + </dict> + <key>Text</key> + <dict> + <key>Text</key> + <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340 +\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;} +{\colortbl;\red255\green255\blue255;\red0\green128\blue0;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf2 process_request}</string> + </dict> + <key>TextRelativeArea</key> + <string>{{0.125, 0.25}, {0.75, 0.5}}</string> + <key>isConnectedShape</key> + <true/> + </dict> + <dict> + <key>Bounds</key> + <string>{{360, 63}, {144, 27}}</string> + <key>Class</key> + <string>ShapedGraphic</string> + <key>ID</key> + <integer>12</integer> + <key>Magnets</key> + <array> + <string>{0, 1}</string> + <string>{0, -1}</string> + <string>{1, 0}</string> + <string>{-1, 0}</string> + </array> + <key>Shape</key> + <string>Rectangle</string> + <key>Text</key> + <dict> + <key>Text</key> + <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340 +\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 HttpResponse}</string> + </dict> + </dict> + <dict> + <key>Bounds</key> + <string>{{72, 63}, {144, 27}}</string> + <key>Class</key> + <string>ShapedGraphic</string> + <key>ID</key> + <integer>11</integer> + <key>Magnets</key> + <array> + <string>{0, 1}</string> + <string>{0, -1}</string> + <string>{1, 0}</string> + <string>{-1, 0}</string> + </array> + <key>Shape</key> + <string>Rectangle</string> + <key>Text</key> + <dict> + <key>Text</key> + <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340 +\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 HttpRequest}</string> + </dict> + </dict> + <dict> + <key>Bounds</key> + <string>{{72, 324}, {432, 27}}</string> + <key>Class</key> + <string>ShapedGraphic</string> + <key>ID</key> + <integer>10</integer> + <key>Magnets</key> + <array> + <string>{0, 1}</string> + <string>{0, -1}</string> + <string>{1, 0}</string> + <string>{-1, 0}</string> + </array> + <key>Shape</key> + <string>Rectangle</string> + <key>Style</key> + <dict> + <key>fill</key> + <dict> + <key>FillType</key> + <integer>2</integer> + <key>GradientAngle</key> + <real>90</real> + <key>GradientColor</key> + <dict> + <key>w</key> + <string>0.666667</string> + </dict> + </dict> + <key>stroke</key> + <dict> + <key>CornerRadius</key> + <real>5</real> + </dict> + </dict> + <key>Text</key> + <dict> + <key>Text</key> + <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340 +\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 MessageMiddleware}</string> + </dict> + </dict> + <dict> + <key>Bounds</key> + <string>{{72, 279}, {432, 27}}</string> + <key>Class</key> + <string>ShapedGraphic</string> + <key>ID</key> + <integer>9</integer> + <key>Magnets</key> + <array> + <string>{0, 1}</string> + <string>{0, -1}</string> + <string>{1, 0}</string> + <string>{-1, 0}</string> + </array> + <key>Shape</key> + <string>Rectangle</string> + <key>Style</key> + <dict> + <key>fill</key> + <dict> + <key>FillType</key> + <integer>2</integer> + <key>GradientAngle</key> + <real>90</real> + <key>GradientColor</key> + <dict> + <key>w</key> + <string>0.666667</string> + </dict> + </dict> + <key>stroke</key> + <dict> + <key>CornerRadius</key> + <real>5</real> + </dict> + </dict> + <key>Text</key> + <dict> + <key>Text</key> + <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340 +\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 AuthenticationMiddleware}</string> + </dict> + </dict> + <dict> + <key>Bounds</key> + <string>{{72, 234}, {432, 27}}</string> + <key>Class</key> + <string>ShapedGraphic</string> + <key>ID</key> + <integer>8</integer> + <key>Magnets</key> + <array> + <string>{0, 1}</string> + <string>{0, -1}</string> + <string>{1, 0}</string> + <string>{-1, 0}</string> + </array> + <key>Shape</key> + <string>Rectangle</string> + <key>Style</key> + <dict> + <key>fill</key> + <dict> + <key>FillType</key> + <integer>2</integer> + <key>GradientAngle</key> + <real>90</real> + <key>GradientColor</key> + <dict> + <key>w</key> + <string>0.666667</string> + </dict> + </dict> + <key>stroke</key> + <dict> + <key>CornerRadius</key> + <real>5</real> + </dict> + </dict> + <key>Text</key> + <dict> + <key>Text</key> + <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340 +\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 CsrfViewMiddleware}</string> + </dict> + </dict> + <dict> + <key>Bounds</key> + <string>{{72, 189}, {432, 27}}</string> + <key>Class</key> + <string>ShapedGraphic</string> + <key>ID</key> + <integer>7</integer> + <key>Magnets</key> + <array> + <string>{0, 1}</string> + <string>{0, -1}</string> + <string>{1, 0}</string> + <string>{-1, 0}</string> + </array> + <key>Shape</key> + <string>Rectangle</string> + <key>Style</key> + <dict> + <key>fill</key> + <dict> + <key>FillType</key> + <integer>2</integer> + <key>GradientAngle</key> + <real>90</real> + <key>GradientColor</key> + <dict> + <key>w</key> + <string>0.666667</string> + </dict> + </dict> + <key>stroke</key> + <dict> + <key>CornerRadius</key> + <real>5</real> + </dict> + </dict> + <key>Text</key> + <dict> + <key>Text</key> + <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340 +\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 SessionMiddleware}</string> + </dict> + </dict> + <dict> + <key>Bounds</key> + <string>{{72, 144}, {432, 27}}</string> + <key>Class</key> + <string>ShapedGraphic</string> + <key>ID</key> + <integer>6</integer> + <key>Magnets</key> + <array> + <string>{0, 1}</string> + <string>{0, -1}</string> + <string>{1, 0}</string> + <string>{-1, 0}</string> + </array> + <key>Shape</key> + <string>Rectangle</string> + <key>Style</key> + <dict> + <key>fill</key> + <dict> + <key>FillType</key> + <integer>2</integer> + <key>GradientAngle</key> + <real>90</real> + <key>GradientColor</key> + <dict> + <key>w</key> + <string>0.666667</string> + </dict> + </dict> + <key>stroke</key> + <dict> + <key>CornerRadius</key> + <real>5</real> + </dict> + </dict> + <key>Text</key> + <dict> + <key>Text</key> + <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340 +\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc + +\f0\fs24 \cf0 CommonMiddleware}</string> + </dict> + </dict> + </array> + <key>GridInfo</key> + <dict> + <key>ShowsGrid</key> + <string>YES</string> + <key>SnapsToGrid</key> + <string>YES</string> + </dict> + <key>GuidesLocked</key> + <string>NO</string> + <key>GuidesVisible</key> + <string>YES</string> + <key>HPages</key> + <integer>1</integer> + <key>ImageCounter</key> + <integer>1</integer> + <key>KeepToScale</key> + <false/> + <key>Layers</key> + <array> + <dict> + <key>Lock</key> + <string>NO</string> + <key>Name</key> + <string>Calque 1</string> + <key>Print</key> + <string>YES</string> + <key>View</key> + <string>YES</string> + </dict> + </array> + <key>LayoutInfo</key> + <dict> + <key>Animate</key> + <string>NO</string> + <key>circoMinDist</key> + <real>18</real> + <key>circoSeparation</key> + <real>0.0</real> + <key>layoutEngine</key> + <string>dot</string> + <key>neatoSeparation</key> + <real>0.0</real> + <key>twopiSeparation</key> + <real>0.0</real> + </dict> + <key>LinksVisible</key> + <string>NO</string> + <key>MagnetsVisible</key> + <string>NO</string> + <key>MasterSheets</key> + <array/> + <key>ModificationDate</key> + <string>2012-12-09 19:48:54 +0000</string> + <key>Modifier</key> + <string>Aymeric Augustin</string> + <key>NotesVisible</key> + <string>NO</string> + <key>Orientation</key> + <integer>2</integer> + <key>OriginVisible</key> + <string>NO</string> + <key>PageBreaks</key> + <string>YES</string> + <key>PrintInfo</key> + <dict> + <key>NSBottomMargin</key> + <array> + <string>float</string> + <string>41</string> + </array> + <key>NSHorizonalPagination</key> + <array> + <string>coded</string> + <string>BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFxlwCG</string> + </array> + <key>NSLeftMargin</key> + <array> + <string>float</string> + <string>18</string> + </array> + <key>NSPaperSize</key> + <array> + <string>size</string> + <string>{595.28997802734375, 841.8900146484375}</string> + </array> + <key>NSPrintReverseOrientation</key> + <array> + <string>int</string> + <string>0</string> + </array> + <key>NSRightMargin</key> + <array> + <string>float</string> + <string>18</string> + </array> + <key>NSTopMargin</key> + <array> + <string>float</string> + <string>18</string> + </array> + </dict> + <key>PrintOnePage</key> + <false/> + <key>ReadOnly</key> + <string>NO</string> + <key>RowAlign</key> + <integer>1</integer> + <key>RowSpacing</key> + <real>36</real> + <key>SheetTitle</key> + <string>Canevas 1</string> + <key>SmartAlignmentGuidesActive</key> + <string>YES</string> + <key>SmartDistanceGuidesActive</key> + <string>YES</string> + <key>UniqueID</key> + <integer>1</integer> + <key>UseEntirePage</key> + <false/> + <key>VPages</key> + <integer>1</integer> + <key>WindowInfo</key> + <dict> + <key>CurrentSheet</key> + <integer>0</integer> + <key>ExpandedCanvases</key> + <array/> + <key>Frame</key> + <string>{{248, 4}, {694, 874}}</string> + <key>ListView</key> + <true/> + <key>OutlineWidth</key> + <integer>142</integer> + <key>RightSidebar</key> + <false/> + <key>ShowRuler</key> + <true/> + <key>Sidebar</key> + <true/> + <key>SidebarWidth</key> + <integer>120</integer> + <key>VisibleRegion</key> + <string>{{0, 0}, {559, 735}}</string> + <key>Zoom</key> + <real>1</real> + <key>ZoomValues</key> + <array> + <array> + <string>Canevas 1</string> + <real>1</real> + <real>1</real> + </array> + </array> + </dict> +</dict> +</plist> diff --git a/docs/topics/http/_images/middleware.pdf b/docs/topics/http/_images/middleware.pdf Binary files differnew file mode 100644 index 0000000000..8a9e61ef40 --- /dev/null +++ b/docs/topics/http/_images/middleware.pdf diff --git a/docs/topics/http/_images/middleware.png b/docs/topics/http/_images/middleware.png Binary files differdeleted file mode 100644 index 505c70ac36..0000000000 --- a/docs/topics/http/_images/middleware.png +++ /dev/null diff --git a/docs/topics/http/_images/middleware.svg b/docs/topics/http/_images/middleware.svg new file mode 100644 index 0000000000..4da8d22da8 --- /dev/null +++ b/docs/topics/http/_images/middleware.svg @@ -0,0 +1,3 @@ +<?xml version="1.0"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" version="1.1" viewBox="52 47 481 409" width="481pt" height="409pt"><metadata xmlns:dc="http://purl.org/dc/elements/1.1/"><dc:date>2012-12-09 19:48Z</dc:date><!-- Produced by OmniGraffle Professional 5.4.2 --></metadata><defs><filter id="Shadow" filterUnits="userSpaceOnUse"><feGaussianBlur in="SourceAlpha" result="blur" stdDeviation="3.488"/><feOffset in="blur" result="offset" dx="0" dy="4"/><feFlood flood-color="black" flood-opacity=".75" result="flood"/><feComposite in="flood" in2="offset" operator="in"/></filter><linearGradient x1="0" x2="1" id="Gradient" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#aaa"/></linearGradient><linearGradient id="Obj_Gradient" xl:href="#Gradient" gradientTransform="translate(288 144) rotate(90) scale(27)"/><font-face font-family="Courier" font-size="12" units-per-em="1000" underline-position="-178.22266" underline-thickness="57.617188" slope="0" x-height="462.40234" cap-height="594.72656" ascent="753.90625" descent="-246.09375" font-weight="500"><font-face-src><font-face-name name="Courier"/></font-face-src></font-face><linearGradient id="Obj_Gradient_2" xl:href="#Gradient" gradientTransform="translate(288 189) rotate(90) scale(27)"/><linearGradient id="Obj_Gradient_3" xl:href="#Gradient" gradientTransform="translate(288 234) rotate(90) scale(27)"/><linearGradient id="Obj_Gradient_4" xl:href="#Gradient" gradientTransform="translate(288 279) rotate(90) scale(27)"/><linearGradient id="Obj_Gradient_5" xl:href="#Gradient" gradientTransform="translate(288 324) rotate(90) scale(27)"/><font-face font-family="Helvetica" font-size="12" units-per-em="1000" underline-position="-75.683594" underline-thickness="49.316406" slope="0" x-height="522.94922" cap-height="717.28516" ascent="770.01953" descent="-229.98047" font-weight="500"><font-face-src><font-face-name name="Helvetica"/></font-face-src></font-face></defs><g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1"><title>Canevas 1</title><rect fill="white" width="559.28998" height="782.89"/><g><title>Calque 1</title><g><use xl:href="#id6_Graphic" filter="url(#Shadow)"/><use xl:href="#id7_Graphic" filter="url(#Shadow)"/><use xl:href="#id8_Graphic" filter="url(#Shadow)"/><use xl:href="#id9_Graphic" filter="url(#Shadow)"/><use xl:href="#id10_Graphic" filter="url(#Shadow)"/><use xl:href="#id11_Graphic" filter="url(#Shadow)"/><use xl:href="#id12_Graphic" filter="url(#Shadow)"/><use xl:href="#id33_Graphic" filter="url(#Shadow)"/></g><g id="id6_Graphic"><path d="M 77 144 L 499 144 C 501.76142 144 504 146.23858 504 149 L 504 166 C 504 168.76142 501.76142 171 499 171 L 77 171 C 74.238576 171 72 168.76142 72 166 C 72 166 72 166 72 166 L 72 149 C 72 146.23858 74.238576 144 77 144 C 77 144 77 144 77 144 Z" fill="url(#Obj_Gradient)"/><path d="M 77 144 L 499 144 C 501.76142 144 504 146.23858 504 149 L 504 166 C 504 168.76142 501.76142 171 499 171 L 77 171 C 74.238576 171 72 168.76142 72 166 C 72 166 72 166 72 166 L 72 149 C 72 146.23858 74.238576 144 77 144 C 77 144 77 144 77 144 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(77 150.5)" fill="black"><tspan font-family="Courier" font-size="12" font-weight="500" fill="black" x="153.390625" y="11" textLength="115.21875">CommonMiddleware</tspan></text></g><g id="id7_Graphic"><path d="M 77 189 L 499 189 C 501.76142 189 504 191.23858 504 194 L 504 211 C 504 213.76142 501.76142 216 499 216 L 77 216 C 74.238576 216 72 213.76142 72 211 C 72 211 72 211 72 211 L 72 194 C 72 191.23858 74.238576 189 77 189 C 77 189 77 189 77 189 Z" fill="url(#Obj_Gradient_2)"/><path d="M 77 189 L 499 189 C 501.76142 189 504 191.23858 504 194 L 504 211 C 504 213.76142 501.76142 216 499 216 L 77 216 C 74.238576 216 72 213.76142 72 211 C 72 211 72 211 72 211 L 72 194 C 72 191.23858 74.238576 189 77 189 C 77 189 77 189 77 189 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(77 195.5)" fill="black"><tspan font-family="Courier" font-size="12" font-weight="500" x="149.79004" y="11" textLength="122.41992">SessionMiddleware</tspan></text></g><g id="id8_Graphic"><path d="M 77 234 L 499 234 C 501.76142 234 504 236.23858 504 239 L 504 256 C 504 258.76142 501.76142 261 499 261 L 77 261 C 74.238576 261 72 258.76142 72 256 C 72 256 72 256 72 256 L 72 239 C 72 236.23858 74.238576 234 77 234 C 77 234 77 234 77 234 Z" fill="url(#Obj_Gradient_3)"/><path d="M 77 234 L 499 234 C 501.76142 234 504 236.23858 504 239 L 504 256 C 504 258.76142 501.76142 261 499 261 L 77 261 C 74.238576 261 72 258.76142 72 256 C 72 256 72 256 72 256 L 72 239 C 72 236.23858 74.238576 234 77 234 C 77 234 77 234 77 234 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(77 240.5)" fill="black"><tspan font-family="Courier" font-size="12" font-weight="500" x="146.18945" y="11" textLength="129.62109">CsrfViewMiddleware</tspan></text></g><g id="id9_Graphic"><path d="M 77 279 L 499 279 C 501.76142 279 504 281.23858 504 284 L 504 301 C 504 303.76142 501.76142 306 499 306 L 77 306 C 74.238576 306 72 303.76142 72 301 C 72 301 72 301 72 301 L 72 284 C 72 281.23858 74.238576 279 77 279 C 77 279 77 279 77 279 Z" fill="url(#Obj_Gradient_4)"/><path d="M 77 279 L 499 279 C 501.76142 279 504 281.23858 504 284 L 504 301 C 504 303.76142 501.76142 306 499 306 L 77 306 C 74.238576 306 72 303.76142 72 301 C 72 301 72 301 72 301 L 72 284 C 72 281.23858 74.238576 279 77 279 C 77 279 77 279 77 279 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(77 285.5)" fill="black"><tspan font-family="Courier" font-size="12" font-weight="500" x="124.58594" y="11" textLength="172.82812">AuthenticationMiddleware</tspan></text></g><g id="id10_Graphic"><path d="M 77 324 L 499 324 C 501.76142 324 504 326.23858 504 329 L 504 346 C 504 348.76142 501.76142 351 499 351 L 77 351 C 74.238576 351 72 348.76142 72 346 C 72 346 72 346 72 346 L 72 329 C 72 326.23858 74.238576 324 77 324 C 77 324 77 324 77 324 Z" fill="url(#Obj_Gradient_5)"/><path d="M 77 324 L 499 324 C 501.76142 324 504 326.23858 504 329 L 504 346 C 504 348.76142 501.76142 351 499 351 L 77 351 C 74.238576 351 72 348.76142 72 346 C 72 346 72 346 72 346 L 72 329 C 72 326.23858 74.238576 324 77 324 C 77 324 77 324 77 324 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(77 330.5)" fill="black"><tspan font-family="Courier" font-size="12" font-weight="500" x="149.79004" y="11" textLength="122.41992">MessageMiddleware</tspan></text></g><g id="id11_Graphic"><rect x="72" y="63" width="144" height="27" fill="white"/><rect x="72" y="63" width="144" height="27" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(77 69.5)" fill="black"><tspan font-family="Courier" font-size="12" font-weight="500" x="27.393555" y="11" textLength="79.21289">HttpRequest</tspan></text></g><g id="id12_Graphic"><rect x="360" y="63" width="144" height="27" fill="white"/><rect x="360" y="63" width="144" height="27" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(365 69.5)" fill="black"><tspan font-family="Courier" font-size="12" font-weight="500" x="23.792969" y="11" textLength="86.41406">HttpResponse</tspan></text></g><path d="M 99 90 L 117 90 L 117 360 L 126 360 L 108 387 L 90 360 L 99 360 Z" fill="white" fill-opacity=".8"/><path d="M 99 90 L 117 90 L 117 360 L 126 360 L 108 387 L 90 360 L 99 360 Z" stroke="green" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(115 132.125) rotate(90)" fill="green"><tspan font-family="Courier" font-size="12" font-weight="500" fill="green" x="52.36621" y="11" textLength="108.01758">process_request</tspan></text><path d="M 162 117 L 180 117 L 180 378 L 189 378 L 171 405 L 153 378 L 162 378 Z" fill="white" fill-opacity=".8"/><path d="M 162 117 L 180 117 L 180 378 L 189 378 L 171 405 L 153 378 L 162 378 Z" stroke="green" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(178 158) rotate(90)" fill="green"><tspan font-family="Courier" font-size="12" font-weight="500" fill="green" x="59.79297" y="11" textLength="86.41406">process_view</tspan></text><path d="M 441 405 L 423 405 L 423 135 L 414 135 L 432 108 L 450 135 L 441 135 Z" fill="white" fill-opacity=".8"/><path d="M 441 405 L 423 405 L 423 135 L 414 135 L 432 108 L 450 135 L 441 135 Z" stroke="green" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" stroke-dasharray="4,4"/><text transform="translate(425 362.875) rotate(-90)" fill="green"><tspan font-family="Courier" font-size="12" font-weight="500" fill="green" x="16.360352" y="11" textLength="180.0293">process_template_response</tspan></text><path d="M 495 405 L 477 405 L 477 117 L 468 117 L 486 90 L 504 117 L 495 117 Z" fill="white" fill-opacity=".8"/><path d="M 495 405 L 477 405 L 477 117 L 468 117 L 486 90 L 504 117 L 495 117 Z" stroke="green" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(479 360.625) rotate(-90)" fill="green"><tspan font-family="Courier" font-size="12" font-weight="500" fill="green" x="55.515625" y="11" textLength="115.21875">process_response</tspan></text><path d="M 387 405 L 369 405 L 369 135 L 360 135 L 378 108 L 396 135 L 387 135 Z" fill="white" fill-opacity=".8"/><path d="M 387 405 L 369 405 L 369 135 L 360 135 L 378 108 L 396 135 L 387 135 Z" stroke="red" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" stroke-dasharray="4,4"/><text transform="translate(371 362.875) rotate(-90)" fill="red"><tspan font-family="Courier" font-size="12" font-weight="500" fill="red" x="45.16504" y="11" textLength="122.41992">process_exception</tspan></text><g id="id33_Graphic"><path d="M 144 405 L 505.4694 405 L 513 418.5 L 505.4694 432 L 144 432 L 153 418.5 Z" fill="white"/><path d="M 144 405 L 505.4694 405 L 513 418.5 L 505.4694 432 L 144 432 L 153 418.5 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(149 411.5)" fill="black"><tspan font-family="Helvetica" font-size="12" font-weight="500" fill="black" x="144.81543" y="11" textLength="69.36914">view function</tspan></text></g></g></g></svg> diff --git a/docs/topics/http/middleware.txt b/docs/topics/http/middleware.txt index c27e7e8690..18243c77ce 100644 --- a/docs/topics/http/middleware.txt +++ b/docs/topics/http/middleware.txt @@ -4,25 +4,28 @@ Middleware Middleware is a framework of hooks into Django's request/response processing. It's a light, low-level "plugin" system for globally altering Django's input -and/or output. +or output. Each middleware component is responsible for doing some specific function. For -example, Django includes a middleware component, ``XViewMiddleware``, that adds -an ``"X-View"`` HTTP header to every response to a ``HEAD`` request. +example, Django includes a middleware component, +:class:`~django.middleware.transaction.TransactionMiddleware`, that wraps the +processing of each HTTP request in a database transaction. This document explains how middleware works, how you activate middleware, and how to write your own middleware. Django ships with some built-in middleware -you can use right out of the box; they're documented in the :doc:`built-in +you can use right out of the box. They're documented in the :doc:`built-in middleware reference </ref/middleware>`. Activating middleware ===================== -To activate a middleware component, add it to the :setting:`MIDDLEWARE_CLASSES` -list in your Django settings. In :setting:`MIDDLEWARE_CLASSES`, each middleware -component is represented by a string: the full Python path to the middleware's -class name. For example, here's the default :setting:`MIDDLEWARE_CLASSES` -created by :djadmin:`django-admin.py startproject <startproject>`:: +To activate a middleware component, add it to the +:setting:`MIDDLEWARE_CLASSES` tuple in your Django settings. + +In :setting:`MIDDLEWARE_CLASSES`, each middleware component is represented by +a string: the full Python path to the middleware's class name. For example, +here's the default value created by :djadmin:`django-admin.py startproject +<startproject>`:: MIDDLEWARE_CLASSES = ( 'django.middleware.common.CommonMiddleware', @@ -32,23 +35,44 @@ created by :djadmin:`django-admin.py startproject <startproject>`:: 'django.contrib.messages.middleware.MessageMiddleware', ) -During the request phases (:meth:`process_request` and :meth:`process_view` -middleware), Django applies middleware in the order it's defined in -:setting:`MIDDLEWARE_CLASSES`, top-down. During the response phases -(:meth:`process_response` and :meth:`process_exception` middleware), the -classes are applied in reverse order, from the bottom up. You can think of it -like an onion: each middleware class is a "layer" that wraps the view: - -.. image:: _images/middleware.png - :width: 502 - :height: 417 - :alt: Middleware application order. - -A Django installation doesn't require any middleware -- e.g., -:setting:`MIDDLEWARE_CLASSES` can be empty, if you'd like -- but it's strongly +A Django installation doesn't require any middleware — +:setting:`MIDDLEWARE_CLASSES` can be empty, if you'd like — but it's strongly suggested that you at least use :class:`~django.middleware.common.CommonMiddleware`. +The order in :setting:`MIDDLEWARE_CLASSES` matters because a middleware can +depend on other middleware. For instance, +:class:`~django.contrib.auth.middleware.AuthenticationMiddleware` stores the +authenticated user in the session; therefore, it must run after +:class:`~django.contrib.sessions.middleware.SessionMiddleware`. + +Hooks and application order +=========================== + +During the request phase, before calling the view, Django applies middleware +in the order it's defined in :setting:`MIDDLEWARE_CLASSES`, top-down. Two +hooks are available: + +* :meth:`process_request` +* :meth:`process_view` + +During the response phase, after calling the view, middleware are applied in +reverse order, from the bottom up. Three hooks are available: + +* :meth:`process_exception` (only if the view raised an exception) +* :meth:`process_template_response` (only for template responses) +* :meth:`process_response` + +.. image:: _images/middleware.* + :alt: middleware application order + :width: 481 + :height: 409 + +If you prefer, you can also think of it like an onion: each middleware class +is a "layer" that wraps the view. + +The behavior of each hook is described below. + Writing your own middleware =========================== @@ -62,16 +86,19 @@ Python class that defines one or more of the following methods: .. method:: process_request(self, request) -``request`` is an :class:`~django.http.HttpRequest` object. This method is -called on each request, before Django decides which view to execute. +``request`` is an :class:`~django.http.HttpRequest` object. + +``process_request()`` is called on each request, before Django decides which +view to execute. -``process_request()`` should return either ``None`` or an -:class:`~django.http.HttpResponse` object. If it returns ``None``, Django will -continue processing this request, executing any other middleware and, then, the -appropriate view. If it returns an :class:`~django.http.HttpResponse` object, -Django won't bother calling ANY other request, view or exception middleware, or -the appropriate view; it'll return that :class:`~django.http.HttpResponse`. -Response middleware is always called on every response. +It should return either ``None`` or an :class:`~django.http.HttpResponse` +object. If it returns ``None``, Django will continue processing this request, +executing any other ``process_request()`` middleware, then, ``process_view()`` +middleware, and finally, the appropriate view. If it returns an +:class:`~django.http.HttpResponse` object, Django won't bother calling any +other request, view or exception middleware, or the appropriate view; it'll +apply response middleware to that :class:`~django.http.HttpResponse`, and +return the result. .. _view-middleware: @@ -88,14 +115,15 @@ dictionary of keyword arguments that will be passed to the view. Neither ``view_args`` nor ``view_kwargs`` include the first view argument (``request``). -``process_view()`` is called just before Django calls the view. It should -return either ``None`` or an :class:`~django.http.HttpResponse` object. If it -returns ``None``, Django will continue processing this request, executing any -other ``process_view()`` middleware and, then, the appropriate view. If it -returns an :class:`~django.http.HttpResponse` object, Django won't bother -calling ANY other request, view or exception middleware, or the appropriate -view; it'll return that :class:`~django.http.HttpResponse`. Response -middleware is always called on every response. +``process_view()`` is called just before Django calls the view. + +It should return either ``None`` or an :class:`~django.http.HttpResponse` +object. If it returns ``None``, Django will continue processing this request, +executing any other ``process_view()`` middleware and, then, the appropriate +view. If it returns an :class:`~django.http.HttpResponse` object, Django won't +bother calling any other view or exception middleware, or the appropriate +view; it'll apply response middleware to that +:class:`~django.http.HttpResponse`, and return the result. .. note:: @@ -119,19 +147,17 @@ middleware is always called on every response. .. method:: process_template_response(self, request, response) -``request`` is an :class:`~django.http.HttpRequest` object. ``response`` is a -subclass of :class:`~django.template.response.SimpleTemplateResponse` (e.g. -:class:`~django.template.response.TemplateResponse`) or any response object -that implements a ``render`` method. +``request`` is an :class:`~django.http.HttpRequest` object. ``response`` is +the :class:`~django.template.response.TemplateResponse` object (or equivalent) +returned by a Django view or by a middleware. -``process_template_response()`` must return a response object that implements a -``render`` method. It could alter the given ``response`` by changing -``response.template_name`` and ``response.context_data``, or it could create -and return a brand-new -:class:`~django.template.response.SimpleTemplateResponse` or equivalent. +``process_template_response()`` is called just after the view has finished +executing, if the response instance has a ``render()`` method, indicating that +it is a :class:`~django.template.response.TemplateResponse` or equivalent. -``process_template_response()`` will only be called if the response -instance has a ``render()`` method, indicating that it is a +It must return a response object that implements a ``render`` method. It could +alter the given ``response`` by changing ``response.template_name`` and +``response.context_data``, or it could create and return a brand-new :class:`~django.template.response.TemplateResponse` or equivalent. You don't need to explicitly render responses -- responses will be @@ -139,7 +165,7 @@ automatically rendered once all template response middleware has been called. Middleware are run in reverse order during the response phase, which -includes process_template_response. +includes ``process_template_response()``. .. _response-middleware: @@ -148,21 +174,34 @@ includes process_template_response. .. method:: process_response(self, request, response) -``request`` is an :class:`~django.http.HttpRequest` object. ``response`` is the -:class:`~django.http.HttpResponse` object returned by a Django view. +``request`` is an :class:`~django.http.HttpRequest` object. ``response`` is +the :class:`~django.http.HttpResponse` or +:class:`~django.http.StreamingHttpResponse` object returned by a Django view +or by a middleware. + +``process_response()`` is called on all responses before they're returned to +the browser. -``process_response()`` must return an :class:`~django.http.HttpResponse` -object. It could alter the given ``response``, or it could create and return a -brand-new :class:`~django.http.HttpResponse`. +It must return an :class:`~django.http.HttpResponse` or +:class:`~django.http.StreamingHttpResponse` object. It could alter the given +``response``, or it could create and return a brand-new +:class:`~django.http.HttpResponse` or +:class:`~django.http.StreamingHttpResponse`. Unlike the ``process_request()`` and ``process_view()`` methods, the -``process_response()`` method is always called, even if the ``process_request()`` -and ``process_view()`` methods of the same middleware class were skipped because -an earlier middleware method returned an :class:`~django.http.HttpResponse` -(this means that your ``process_response()`` method cannot rely on setup done in -``process_request()``, for example). In addition, during the response phase the -classes are applied in reverse order, from the bottom up. This means classes -defined at the end of :setting:`MIDDLEWARE_CLASSES` will be run first. +``process_response()`` method is always called, even if the +``process_request()`` and ``process_view()`` methods of the same middleware +class were skipped (because an earlier middleware method returned an +:class:`~django.http.HttpResponse`). In particular, this means that your +``process_response()`` method cannot rely on setup done in +``process_request()``. + +Finally, remember that during the response phase, middleware are applied in +reverse order, from the bottom up. This means classes defined at the end of +:setting:`MIDDLEWARE_CLASSES` will be run first. + +Dealing with streaming responses +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. versionchanged:: 1.5 ``response`` may also be an :class:`~django.http.StreamingHttpResponse` @@ -177,10 +216,17 @@ must test for streaming responses and adjust their behavior accordingly:: if response.streaming: response.streaming_content = wrap_streaming_content(response.streaming_content) else: - response.content = wrap_content(response.content) + response.content = alter_content(response.content) + +.. note:: + + ``streaming_content`` should be assumed to be too large to hold in memory. + Response middleware may wrap it in a new generator, but must not consume + it. Wrapping is typically implemented as follows:: -``streaming_content`` should be assumed to be too large to hold in memory. -Middleware may wrap it in a new generator, but must not consume it. + def wrap_streaming_content(content) + for chunk in content: + yield alter_content(chunk) .. _exception-middleware: @@ -195,8 +241,9 @@ Middleware may wrap it in a new generator, but must not consume it. Django calls ``process_exception()`` when a view raises an exception. ``process_exception()`` should return either ``None`` or an :class:`~django.http.HttpResponse` object. If it returns an -:class:`~django.http.HttpResponse` object, the response will be returned to -the browser. Otherwise, default exception handling kicks in. +:class:`~django.http.HttpResponse` object, the template response and response +middleware will be applied, and the resulting response returned to the +browser. Otherwise, default exception handling kicks in. Again, middleware are run in reverse order during the response phase, which includes ``process_exception``. If an exception middleware returns a response, @@ -221,9 +268,9 @@ Marking middleware as unused ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ It's sometimes useful to determine at run-time whether a piece of middleware -should be used. In these cases, your middleware's ``__init__`` method may raise -``django.core.exceptions.MiddlewareNotUsed``. Django will then remove that -piece of middleware from the middleware process. +should be used. In these cases, your middleware's ``__init__`` method may +raise :exc:`django.core.exceptions.MiddlewareNotUsed`. Django will then remove +that piece of middleware from the middleware process. Guidelines ---------- diff --git a/docs/topics/http/sessions.txt b/docs/topics/http/sessions.txt index 15f9f7feba..baf8aa5cb5 100644 --- a/docs/topics/http/sessions.txt +++ b/docs/topics/http/sessions.txt @@ -45,6 +45,8 @@ If you want to use a database-backed session, you need to add Once you have configured your installation, run ``manage.py syncdb`` to install the single database table that stores session data. +.. _cached-sessions-backend: + Using cached sessions --------------------- @@ -62,6 +64,13 @@ sure you've configured your cache; see the :doc:`cache documentation sessions directly instead of sending everything through the file or database cache backends. +If you have multiple caches defined in :setting:`CACHES`, Django will use the +default cache. To use another cache, set :setting:`SESSION_CACHE_ALIAS` to the +name of that cache. + +.. versionchanged:: 1.5 + The :setting:`SESSION_CACHE_ALIAS` setting was added. + Once your cache is configured, you've got two choices for how to store data in the cache: @@ -250,17 +259,35 @@ You can edit it multiple times. with no custom expiration (or those set to expire at browser close), this will equal :setting:`SESSION_COOKIE_AGE`. + This function accepts two optional keyword arguments: + + - ``modification``: last modification of the session, as a + :class:`~datetime.datetime` object. Defaults to the current time. + - ``expiry``: expiry information for the session, as a + :class:`~datetime.datetime` object, an :class:`int` (in seconds), or + ``None``. Defaults to the value stored in the session by + :meth:`set_expiry`, if there is one, or ``None``. + .. method:: get_expiry_date Returns the date this session will expire. For sessions with no custom expiration (or those set to expire at browser close), this will equal the date :setting:`SESSION_COOKIE_AGE` seconds from now. + This function accepts the same keyword argumets as :meth:`get_expiry_age`. + .. method:: get_expire_at_browser_close Returns either ``True`` or ``False``, depending on whether the user's session cookie will expire when the user's Web browser is closed. + .. method:: SessionBase.clear_expired + + .. versionadded:: 1.5 + + Removes expired sessions from the session store. This class method is + called by :djadmin:`clearsessions`. + Session object guidelines ------------------------- @@ -447,22 +474,29 @@ This setting is a global default and can be overwritten at a per-session level by explicitly calling the :meth:`~backends.base.SessionBase.set_expiry` method of ``request.session`` as described above in `using sessions in views`_. -Clearing the session table +Clearing the session store ========================== -If you're using the database backend, note that session data can accumulate in -the ``django_session`` database table and Django does *not* provide automatic -purging. Therefore, it's your job to purge expired sessions on a regular basis. +As users create new sessions on your website, session data can accumulate in +your session store. If you're using the database backend, the +``django_session`` database table will grow. If you're using the file backend, +your temporary directory will contain an increasing number of files. -To understand this problem, consider what happens when a user uses a session. +To understand this problem, consider what happens with the database backend. When a user logs in, Django adds a row to the ``django_session`` database table. Django updates this row each time the session data changes. If the user logs out manually, Django deletes the row. But if the user does *not* log out, -the row never gets deleted. +the row never gets deleted. A similar process happens with the file backend. + +Django does *not* provide automatic purging of expired sessions. Therefore, +it's your job to purge expired sessions on a regular basis. Django provides a +clean-up management command for this purpose: :djadmin:`clearsessions`. It's +recommended to call this command on a regular basis, for example as a daily +cron job. -Django provides a sample clean-up script: ``django-admin.py cleanup``. -That script deletes any session in the session table whose ``expire_date`` is -in the past -- but your application may have different requirements. +Note that the cache backend isn't vulnerable to this problem, because caches +automatically delete stale data. Neither is the cookie backend, because the +session data is stored by the users' browsers. Settings ======== diff --git a/docs/topics/http/shortcuts.txt b/docs/topics/http/shortcuts.txt index 0dc38b1459..b1b4700b73 100644 --- a/docs/topics/http/shortcuts.txt +++ b/docs/topics/http/shortcuts.txt @@ -4,7 +4,7 @@ Django shortcut functions .. module:: django.shortcuts :synopsis: - Convenience shortcuts that spam multiple levels of Django's MVC stack. + Convenience shortcuts that span multiple levels of Django's MVC stack. .. index:: shortcuts diff --git a/docs/topics/http/urls.txt b/docs/topics/http/urls.txt index e178df2af2..00c07da6ea 100644 --- a/docs/topics/http/urls.txt +++ b/docs/topics/http/urls.txt @@ -552,12 +552,11 @@ layers where URLs are needed: * In templates: Using the :ttag:`url` template tag. -* In Python code: Using the :func:`django.core.urlresolvers.reverse()` +* In Python code: Using the :func:`django.core.urlresolvers.reverse` function. * In higher level code related to handling of URLs of Django model instances: - The :meth:`django.db.models.Model.get_absolute_url()` method and the - :func:`django.db.models.permalink` decorator. + The :meth:`~django.db.models.Model.get_absolute_url` method. Examples -------- @@ -622,10 +621,10 @@ view:: ) This is completely valid, but it leads to problems when you try to do reverse -URL matching (through the :func:`~django.db.models.permalink` decorator or the -:ttag:`url` template tag). Continuing this example, if you wanted to retrieve -the URL for the ``archive`` view, Django's reverse URL matcher would get -confused, because *two* URL patterns point at that view. +URL matching (through the :func:`~django.core.urlresolvers.reverse` function +or the :ttag:`url` template tag). Continuing this example, if you wanted to +retrieve the URL for the ``archive`` view, Django's reverse URL matcher would +get confused, because *two* URL patterns point at that view. To solve this problem, Django supports **named URL patterns**. That is, you can give a name to a URL pattern in order to distinguish it from other patterns @@ -724,7 +723,7 @@ the fully qualified name into parts, and then tries the following lookup: render a template. The current application can also be specified manually as an argument - to the :func:`django.core.urlresolvers.reverse()` function. + to the :func:`django.core.urlresolvers.reverse` function. 3. If there is no current application. Django looks for a default application instance. The default application instance is the instance diff --git a/docs/topics/http/views.txt b/docs/topics/http/views.txt index 7c4d1bbb6e..caa2882f37 100644 --- a/docs/topics/http/views.txt +++ b/docs/topics/http/views.txt @@ -209,6 +209,17 @@ This view loads and renders the template ``403.html`` in your root template directory, or if this file does not exist, instead serves the text "403 Forbidden", as per :rfc:`2616` (the HTTP 1.1 Specification). +``django.views.defaults.permission_denied`` is triggered by a +:exc:`~django.core.exceptions.PermissionDenied` exception. To deny access in a +view you can use code like this:: + + from django.core.exceptions import PermissionDenied + + def edit(request, pk): + if not request.user.is_staff: + raise PermissionDenied + # ... + It is possible to override ``django.views.defaults.permission_denied`` in the same way you can for the 404 and 500 views by specifying a ``handler403`` in your URLconf:: diff --git a/docs/topics/install.txt b/docs/topics/install.txt index 52994ed16a..b71033f319 100644 --- a/docs/topics/install.txt +++ b/docs/topics/install.txt @@ -10,7 +10,7 @@ Install Python Being a Python Web framework, Django requires Python. It works with any Python version from 2.6.5 to 2.7. It also features -experimental support for versions 3.2 and 3.3. +experimental support for versions from 3.2.3 to 3.3. Get Python at http://www.python.org. If you're running Linux or Mac OS X, you probably already have it installed. @@ -106,15 +106,15 @@ support channels provided by each 3rd party project. In addition to a database backend, you'll need to make sure your Python database bindings are installed. -* If you're using PostgreSQL, you'll need the ``postgresql_psycopg2`` package. +* If you're using PostgreSQL, you'll need the `postgresql_psycopg2`_ package. You might want to refer to our :ref:`PostgreSQL notes <postgresql-notes>` for further technical details specific to this database. If you're on Windows, check out the unofficial `compiled Windows version`_. -* If you're using MySQL, you'll need the ``MySQL-python`` package, version 1.2.1p2 or higher. You - will also want to read the database-specific :ref:`notes for the MySQL - backend <mysql-notes>`. +* If you're using MySQL, you'll need the ``MySQL-python`` package, version + 1.2.1p2 or higher. You will also want to read the database-specific + :ref:`notes for the MySQL backend <mysql-notes>`. * If you're using Oracle, you'll need a copy of cx_Oracle_, but please read the database-specific :ref:`notes for the Oracle backend <oracle-notes>` @@ -124,21 +124,23 @@ database bindings are installed. * If you're using an unofficial 3rd party backend, please consult the documentation provided for any additional requirements. -If you plan to use Django's ``manage.py syncdb`` command to -automatically create database tables for your models, 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. On some databases, Django will need -``ALTER TABLE`` privileges during ``syncdb`` but won't issue -``ALTER TABLE`` statements on a table once ``syncdb`` has created it. +If you plan to use Django's ``manage.py syncdb`` 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. On some databases, Django will need ``ALTER TABLE`` +privileges during ``syncdb`` but won't issue ``ALTER TABLE`` statements on a +table once ``syncdb`` has created it. After creating a database user with these +permissions, you'll specify the details in your project's settings file, +see :setting:`DATABASES` for details. -If you're using Django's :doc:`testing framework</topics/testing>` to test database queries, -Django will need permission to create a test database. +If you're using Django's :doc:`testing framework</topics/testing>` to test +database queries, Django will need permission to create a test database. .. _PostgreSQL: http://www.postgresql.org/ .. _MySQL: http://www.mysql.com/ -.. _psycopg: http://initd.org/pub/software/psycopg/ +.. _postgresql_psycopg2: http://initd.org/psycopg/ .. _compiled Windows version: http://stickpeople.com/projects/python/win-psycopg/ .. _SQLite: http://www.sqlite.org/ .. _pysqlite: http://trac.edgewall.org/wiki/PySqlite diff --git a/docs/topics/logging.txt b/docs/topics/logging.txt index 7bd56e92ec..652ad397ff 100644 --- a/docs/topics/logging.txt +++ b/docs/topics/logging.txt @@ -440,7 +440,7 @@ Handlers Django provides one log handler in addition to those provided by the Python logging module. -.. class:: AdminEmailHandler([include_html=False]) +.. class:: AdminEmailHandler(include_html=False, email_backend=None) This handler sends an email to the site admins for each log message it receives. @@ -470,13 +470,30 @@ Python logging module. with names and values of local variables at each level of the stack, plus the values of your Django settings. This information is potentially very sensitive, and you may not want to send it over email. Consider using - something such as `django-sentry`_ to get the best of both worlds -- the + something such as `Sentry`_ to get the best of both worlds -- the rich information of full tracebacks plus the security of *not* sending the information over email. You may also explicitly designate certain sensitive information to be filtered out of error reports -- learn more on :ref:`Filtering error reports<filtering-error-reports>`. -.. _django-sentry: http://pypi.python.org/pypi/django-sentry + .. versionadded:: 1.6 + + By setting the ``email_backend`` argument of ``AdminEmailHandler``, the + :ref:`email backend <topic-email-backends>` that is being used by the + handler can be overridden, like this:: + + 'handlers': { + 'mail_admins': { + 'level': 'ERROR', + 'class': 'django.utils.log.AdminEmailHandler', + 'email_backend': 'django.core.mail.backends.filebased.EmailBackend', + } + }, + + By default, an instance of the email backend specified in + :setting:`EMAIL_BACKEND` will be used. + +.. _Sentry: http://pypi.python.org/pypi/sentry Filters diff --git a/docs/topics/python3.txt b/docs/topics/python3.txt index f5749faaf2..e6dc165399 100644 --- a/docs/topics/python3.txt +++ b/docs/topics/python3.txt @@ -278,15 +278,13 @@ Iterators :: - class MyIterator(object): + class MyIterator(six.Iterator): def __iter__(self): return self # implement some logic here def __next__(self): raise StopIteration # implement some logic here - next = __next__ # Python 2 compatibility - Boolean evaluation ~~~~~~~~~~~~~~~~~~ @@ -297,7 +295,8 @@ Boolean evaluation def __bool__(self): return True # implement some logic here - __nonzero__ = __bool__ # Python 2 compatibility + def __nonzero__(self): # Python 2 compatibility + return type(self).__bool__(self) Division ~~~~~~~~ @@ -309,12 +308,14 @@ Division def __truediv__(self, other): return self / other # implement some logic here - __div__ = __truediv__ # Python 2 compatibility + def __div__(self, other): # Python 2 compatibility + return type(self).__truediv__(self, other) def __itruediv__(self, other): return self // other # implement some logic here - __idiv__ = __itruediv__ # Python 2 compatibility + def __idiv__(self, other): # Python 2 compatibility + return type(self).__itruediv__(self, other) .. module: django.utils.six diff --git a/docs/topics/security.txt b/docs/topics/security.txt index 0a3c6bff02..169f9ac773 100644 --- a/docs/topics/security.txt +++ b/docs/topics/security.txt @@ -185,6 +185,31 @@ recommend you ensure your Web server is configured such that: Additionally, as of 1.3.1, Django requires you to explicitly enable support for the ``X-Forwarded-Host`` header if your configuration requires it. +Configuration for Apache +------------------------ + +The easiest way to get the described behavior in Apache is as follows. Create +a `virtual host`_ using the ServerName_ and ServerAlias_ directives to restrict +the domains Apache reacts to. Please keep in mind that while the directives do +support ports the match is only performed against the hostname. This means that +the ``Host`` header could still contain a port pointing to another webserver on +the same machine. The next step is to make sure that your newly created virtual +host is not also the default virtual host. Apache uses the first virtual host +found in the configuration file as default virtual host. As such you have to +ensure that you have another virtual host which will act as catch-all virtual +host. Just add one if you do not have one already, there is nothing special +about it aside from ensuring it is the first virtual host in the configuration +file. Debian/Ubuntu users usually don't have to take any action, since Apache +ships with a default virtual host in ``sites-available`` which is linked into +``sites-enabled`` as ``000-default`` and included from ``apache2.conf``. Just +make sure not to name your site ``000-abc``, since files are included in +alphabetical order. + +.. _virtual host: http://httpd.apache.org/docs/2.2/vhosts/ +.. _ServerName: http://httpd.apache.org/docs/2.2/mod/core.html#servername +.. _ServerAlias: http://httpd.apache.org/docs/2.2/mod/core.html#serveralias + + .. _additional-security-topics: Additional security topics diff --git a/docs/topics/serialization.txt b/docs/topics/serialization.txt index 9b44166e42..28f600e223 100644 --- a/docs/topics/serialization.txt +++ b/docs/topics/serialization.txt @@ -166,15 +166,6 @@ Notes for specific serialization formats json ^^^^ -If you're using UTF-8 (or any other non-ASCII encoding) data with the JSON -serializer, you must pass ``ensure_ascii=False`` as a parameter to the -``serialize()`` call. Otherwise, the output won't be encoded correctly. - -For example:: - - json_serializer = serializers.get_serializer("json")() - json_serializer.serialize(queryset, ensure_ascii=False, stream=response) - Be aware that not all Django output can be passed unmodified to :mod:`json`. In particular, :ref:`lazy translation objects <lazy-translations>` need a `special encoder`_ written for them. Something like this will work:: diff --git a/docs/topics/templates.txt b/docs/topics/templates.txt index af45a8d95b..fb2119515b 100644 --- a/docs/topics/templates.txt +++ b/docs/topics/templates.txt @@ -16,9 +16,9 @@ or CheetahTemplate_, you should feel right at home with Django's templates. .. admonition:: Philosophy If you have a background in programming, or if you're used to languages - like PHP which mix programming code directly into HTML, you'll want to - bear in mind that the Django template system is not simply Python embedded - into HTML. This is by design: the template system is meant to express + which mix programming code directly into HTML, you'll want to bear in + mind that the Django template system is not simply Python embedded into + HTML. This is by design: the template system is meant to express presentation, not program logic. The Django template system provides tags which function similarly to some diff --git a/docs/topics/testing.txt b/docs/topics/testing.txt index d0b2e7cdf9..8c11e32a55 100644 --- a/docs/topics/testing.txt +++ b/docs/topics/testing.txt @@ -379,6 +379,15 @@ control the particular collation used by the test database. See the :doc:`settings documentation </ref/settings>` for details of these advanced settings. +.. admonition:: Finding data from your production database when running tests? + + If your code attempts to access the database when its modules are compiled, + this will occur *before* the test database is set up, with potentially + unexpected results. For example, if you have a database query in + module-level code and a real database exists, production data could pollute + your tests. *It is a bad idea to have such import-time database queries in + your code* anyway - rewrite your code so that it doesn't do this. + .. _topics-testing-masterslave: Testing master/slave configurations @@ -1177,10 +1186,13 @@ Normal Python unit test classes extend a base class of .. _testcase_hierarchy_diagram: -.. figure:: _images/django_unittest_classes_hierarchy.png +.. figure:: _images/django_unittest_classes_hierarchy.* :alt: Hierarchy of Django unit testing classes (TestCase subclasses) + :width: 508 + :height: 391 - Hierarchy of Django unit testing classes +Regardless of the version of Python you're using, if you've installed +:mod:`unittest2`, :mod:`django.utils.unittest` will point to that library. TestCase ^^^^^^^^ @@ -1586,15 +1598,24 @@ The decorator can also be applied to test case classes:: the original ``LoginTestCase`` is still equally affected by the decorator. -.. note:: +When overriding settings, make sure to handle the cases in which your app's +code uses a cache or similar feature that retains state even if the +setting is changed. Django provides the +:data:`django.test.signals.setting_changed` signal that lets you register +callbacks to clean up and otherwise reset state when settings are changed. + +Django itself uses this signal to reset various data: - When overriding settings, make sure to handle the cases in which your app's - code uses a cache or similar feature that retains state even if the - setting is changed. Django provides the - :data:`django.test.signals.setting_changed` signal that lets you register - callbacks to clean up and otherwise reset state when settings are changed. - Note that this signal isn't currently used by Django itself, so changing - built-in settings may not yield the results you expect. +================================ ======================== +Overriden settings Data reset +================================ ======================== +USE_TZ, TIME_ZONE Databases timezone +TEMPLATE_CONTEXT_PROCESSORS Context processors cache +TEMPLATE_LOADERS Template loaders cache +SERIALIZATION_MODULES Serializers cache +LOCALE_PATHS, LANGUAGE_CODE Default translation and loaded translations +MEDIA_ROOT, DEFAULT_FILE_STORAGE Default file storage +================================ ======================== Emptying the test outbox ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1752,6 +1773,11 @@ your test suite. via an explicit ``order_by()`` call on the queryset prior to comparison. + .. versionchanged:: 1.6 + The method now checks for undefined order and raises ``ValueError`` + if undefined order is spotted. The ordering is seen as undefined if + the given ``qs`` isn't ordered and the comparison is against more + than one ordered values. .. method:: TestCase.assertNumQueries(num, func, *args, **kwargs) @@ -2075,6 +2101,7 @@ out the `full reference`_ for more details. def test_login(self): from selenium.webdriver.support.wait import WebDriverWait + timeout = 2 ... self.selenium.find_element_by_xpath('//input[@value="Log in"]').click() # Wait until the response is received |
