{{ name }}
-{% autoescape off %}{{ description }}{% endautoescape %}
+{{ description }}
{{ response.status }} {{ response.status_text }}{% autoescape off %}
{% for key, val in response.headers.items %}{{ key }}: {{ val|urlize_quoted_links }}
diff --git a/djangorestframework/templates/renderer.txt b/djangorestframework/templates/renderer.txt
index 5be8c117..b584952c 100644
--- a/djangorestframework/templates/renderer.txt
+++ b/djangorestframework/templates/renderer.txt
@@ -1,8 +1,8 @@
-{{ name }}
+{% autoescape off %}{{ name }}
{{ description }}
-{% autoescape off %}HTTP/1.0 {{ response.status }} {{ response.status_text }}
+HTTP/1.0 {{ response.status }} {{ response.status_text }}
{% for key, val in response.headers.items %}{{ key }}: {{ val }}
{% endfor %}
{{ content }}{% endautoescape %}
diff --git a/djangorestframework/views.py b/djangorestframework/views.py
index 88d81d25..32d2437c 100644
--- a/djangorestframework/views.py
+++ b/djangorestframework/views.py
@@ -36,6 +36,7 @@ def _remove_trailing_string(content, trailing):
return content[:-len(trailing)]
return content
+
def _remove_leading_indent(content):
"""
Remove leading indent from a block of text.
@@ -50,6 +51,7 @@ def _remove_leading_indent(content):
return re.sub(re.compile(whitespace_pattern, re.MULTILINE), '', content)
return content
+
def _camelcase_to_spaces(content):
"""
Translate 'CamelCaseNames' to 'Camel Case Names'.
@@ -161,9 +163,10 @@ class View(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, DjangoView):
def markup_description(self, description):
if apply_markdown:
- return apply_markdown(description)
+ description = apply_markdown(description)
else:
- return mark_safe(escape(description).replace('\n', '
'))
+ description = escape(description).replace('\n', '
')
+ return mark_safe(description)
def http_method_not_allowed(self, request, *args, **kwargs):
"""
--
cgit v1.2.3
From 765ec0b76ea22c857190ee6a25e9e6615e5b0c5e Mon Sep 17 00:00:00 2001
From: Tom Christie
Date: Sat, 28 Jan 2012 18:53:55 +0000
Subject: Use `staticfiles` for serving css. Fixes #116.
---
.../static/css/djangorestframework.css | 1152 ++++++++++++++++++++
djangorestframework/templates/renderer.html | 29 +-
2 files changed, 1161 insertions(+), 20 deletions(-)
create mode 100644 djangorestframework/static/css/djangorestframework.css
(limited to 'djangorestframework')
diff --git a/djangorestframework/static/css/djangorestframework.css b/djangorestframework/static/css/djangorestframework.css
new file mode 100644
index 00000000..8fc4bace
--- /dev/null
+++ b/djangorestframework/static/css/djangorestframework.css
@@ -0,0 +1,1152 @@
+/********************** admin 'base.css' ************************/
+
+body {
+ margin: 0;
+ padding: 0;
+ font-size: 12px;
+ font-family: "Lucida Grande","DejaVu Sans","Bitstream Vera Sans",Verdana,Arial,sans-serif;
+ color: #333;
+ background: #fff;
+}
+
+/* LINKS */
+
+a:link, a:visited {
+ color: #5b80b2;
+ text-decoration: none;
+}
+
+a:hover {
+ color: #036;
+}
+
+a img {
+ border: none;
+}
+
+a.section:link, a.section:visited {
+ color: white;
+ text-decoration: none;
+}
+
+/* GLOBAL DEFAULTS */
+
+p, ol, ul, dl {
+ margin: .2em 0 .8em 0;
+}
+
+p {
+ padding: 0;
+ line-height: 140%;
+}
+
+h1,h2,h3,h4,h5 {
+ font-weight: bold;
+}
+
+h1 {
+ font-size: 18px;
+ color: #666;
+ padding: 0 6px 0 0;
+ margin: 0 0 .2em 0;
+}
+
+h2 {
+ font-size: 16px;
+ margin: 1em 0 .5em 0;
+}
+
+h2.subhead {
+ font-weight: normal;
+ margin-top: 0;
+}
+
+h3 {
+ font-size: 14px;
+ margin: .8em 0 .3em 0;
+ color: #666;
+ font-weight: bold;
+}
+
+h4 {
+ font-size: 12px;
+ margin: 1em 0 .8em 0;
+ padding-bottom: 3px;
+}
+
+h5 {
+ font-size: 10px;
+ margin: 1.5em 0 .5em 0;
+ color: #666;
+ text-transform: uppercase;
+ letter-spacing: 1px;
+}
+
+ul li {
+ list-style-type: square;
+ padding: 1px 0;
+}
+
+ul.plainlist {
+ margin-left: 0 !important;
+}
+
+ul.plainlist li {
+ list-style-type: none;
+}
+
+li ul {
+ margin-bottom: 0;
+}
+
+li, dt, dd {
+ font-size: 11px;
+ line-height: 14px;
+}
+
+dt {
+ font-weight: bold;
+ margin-top: 4px;
+}
+
+dd {
+ margin-left: 0;
+}
+
+form {
+ margin: 0;
+ padding: 0;
+}
+
+fieldset {
+ margin: 0;
+ padding: 0;
+}
+
+blockquote {
+ font-size: 11px;
+ color: #777;
+ margin-left: 2px;
+ padding-left: 10px;
+ border-left: 5px solid #ddd;
+}
+
+code, pre {
+ font-family: "Bitstream Vera Sans Mono", Monaco, "Courier New", Courier, monospace;
+ background: inherit;
+ color: #666;
+ font-size: 11px;
+}
+
+pre.literal-block {
+ margin: 10px;
+ background: #eee;
+ padding: 6px 8px;
+}
+
+code strong {
+ color: #930;
+}
+
+hr {
+ clear: both;
+ color: #eee;
+ background-color: #eee;
+ height: 1px;
+ border: none;
+ margin: 0;
+ padding: 0;
+ font-size: 1px;
+ line-height: 1px;
+}
+
+/* TEXT STYLES & MODIFIERS */
+
+.small {
+ font-size: 11px;
+}
+
+.tiny {
+ font-size: 10px;
+}
+
+p.tiny {
+ margin-top: -2px;
+}
+
+.mini {
+ font-size: 9px;
+}
+
+p.mini {
+ margin-top: -3px;
+}
+
+.help, p.help {
+ font-size: 10px !important;
+ color: #999;
+}
+
+p img, h1 img, h2 img, h3 img, h4 img, td img {
+ vertical-align: middle;
+}
+
+.quiet, a.quiet:link, a.quiet:visited {
+ color: #999 !important;
+ font-weight: normal !important;
+}
+
+.quiet strong {
+ font-weight: bold !important;
+}
+
+.float-right {
+ float: right;
+}
+
+.float-left {
+ float: left;
+}
+
+.clear {
+ clear: both;
+}
+
+.align-left {
+ text-align: left;
+}
+
+.align-right {
+ text-align: right;
+}
+
+.example {
+ margin: 10px 0;
+ padding: 5px 10px;
+ background: #efefef;
+}
+
+.nowrap {
+ white-space: nowrap;
+}
+
+/* TABLES */
+
+table {
+ border-collapse: collapse;
+ border-color: #ccc;
+}
+
+td, th {
+ font-size: 11px;
+ line-height: 13px;
+ border-bottom: 1px solid #eee;
+ vertical-align: top;
+ padding: 5px;
+ font-family: "Lucida Grande", Verdana, Arial, sans-serif;
+}
+
+th {
+ text-align: left;
+ font-size: 12px;
+ font-weight: bold;
+}
+
+thead th,
+tfoot td {
+ color: #666;
+ padding: 2px 5px;
+ font-size: 11px;
+ background: #e1e1e1 url(../img/admin/nav-bg.gif) top left repeat-x;
+ border-left: 1px solid #ddd;
+ border-bottom: 1px solid #ddd;
+}
+
+tfoot td {
+ border-bottom: none;
+ border-top: 1px solid #ddd;
+}
+
+thead th:first-child,
+tfoot td:first-child {
+ border-left: none !important;
+}
+
+thead th.optional {
+ font-weight: normal !important;
+}
+
+fieldset table {
+ border-right: 1px solid #eee;
+}
+
+tr.row-label td {
+ font-size: 9px;
+ padding-top: 2px;
+ padding-bottom: 0;
+ border-bottom: none;
+ color: #666;
+ margin-top: -1px;
+}
+
+tr.alt {
+ background: #f6f6f6;
+}
+
+.row1 {
+ background: #EDF3FE;
+}
+
+.row2 {
+ background: white;
+}
+
+/* SORTABLE TABLES */
+
+thead th a:link, thead th a:visited {
+ color: #666;
+ display: block;
+}
+
+table thead th.sorted {
+ background-position: bottom left !important;
+}
+
+table thead th.sorted a {
+ padding-right: 13px;
+}
+
+table thead th.ascending a {
+ background: url(../img/admin/arrow-up.gif) right .4em no-repeat;
+}
+
+table thead th.descending a {
+ background: url(../img/admin/arrow-down.gif) right .4em no-repeat;
+}
+
+/* ORDERABLE TABLES */
+
+table.orderable tbody tr td:hover {
+ cursor: move;
+}
+
+table.orderable tbody tr td:first-child {
+ padding-left: 14px;
+ background-image: url(../img/admin/nav-bg-grabber.gif);
+ background-repeat: repeat-y;
+}
+
+table.orderable-initalized .order-cell, body>tr>td.order-cell {
+ display: none;
+}
+
+/* FORM DEFAULTS */
+
+input, textarea, select, .form-row p {
+ margin: 2px 0;
+ padding: 2px 3px;
+ vertical-align: middle;
+ font-family: "Lucida Grande", Verdana, Arial, sans-serif;
+ font-weight: normal;
+ font-size: 11px;
+}
+
+textarea {
+ vertical-align: top !important;
+}
+
+input[type=text], input[type=password], textarea, select, .vTextField {
+ border: 1px solid #ccc;
+}
+
+/* FORM BUTTONS */
+
+.button, input[type=submit], input[type=button], .submit-row input {
+ background: white url(../img/admin/nav-bg.gif) bottom repeat-x;
+ padding: 3px 5px;
+ color: black;
+ border: 1px solid #bbb;
+ border-color: #ddd #aaa #aaa #ddd;
+}
+
+.button:active, input[type=submit]:active, input[type=button]:active {
+ background-image: url(../img/admin/nav-bg-reverse.gif);
+ background-position: top;
+}
+
+.button[disabled], input[type=submit][disabled], input[type=button][disabled] {
+ background-image: url(../img/admin/nav-bg.gif);
+ background-position: bottom;
+ opacity: 0.4;
+}
+
+.button.default, input[type=submit].default, .submit-row input.default {
+ border: 2px solid #5b80b2;
+ background: #7CA0C7 url(../img/admin/default-bg.gif) bottom repeat-x;
+ font-weight: bold;
+ color: white;
+ float: right;
+}
+
+.button.default:active, input[type=submit].default:active {
+ background-image: url(../img/admin/default-bg-reverse.gif);
+ background-position: top;
+}
+
+.button[disabled].default, input[type=submit][disabled].default, input[type=button][disabled].default {
+ background-image: url(../img/admin/default-bg.gif);
+ background-position: bottom;
+ opacity: 0.4;
+}
+
+
+/* MODULES */
+
+.module {
+ border: 1px solid #ccc;
+ margin-bottom: 5px;
+ background: white;
+}
+
+.module p, .module ul, .module h3, .module h4, .module dl, .module pre {
+ padding-left: 10px;
+ padding-right: 10px;
+}
+
+.module blockquote {
+ margin-left: 12px;
+}
+
+.module ul, .module ol {
+ margin-left: 1.5em;
+}
+
+.module h3 {
+ margin-top: .6em;
+}
+
+.module h2, .module caption, .inline-group h2 {
+ margin: 0;
+ padding: 2px 5px 3px 5px;
+ font-size: 11px;
+ text-align: left;
+ font-weight: bold;
+ background: #7CA0C7 url(../img/admin/default-bg.gif) top left repeat-x;
+ color: white;
+}
+
+.module table {
+ border-collapse: collapse;
+}
+
+/* MESSAGES & ERRORS */
+
+ul.messagelist {
+ padding: 0 0 5px 0;
+ margin: 0;
+}
+
+ul.messagelist li {
+ font-size: 12px;
+ display: block;
+ padding: 4px 5px 4px 25px;
+ margin: 0 0 3px 0;
+ border-bottom: 1px solid #ddd;
+ color: #666;
+ background: #ffc url(../img/admin/icon_success.gif) 5px .3em no-repeat;
+}
+
+ul.messagelist li.warning{
+ background-image: url(../img/admin/icon_alert.gif);
+}
+
+ul.messagelist li.error{
+ background-image: url(../img/admin/icon_error.gif);
+}
+
+.errornote {
+ font-size: 12px !important;
+ display: block;
+ padding: 4px 5px 4px 25px;
+ margin: 0 0 3px 0;
+ border: 1px solid red;
+ color: red;
+ background: #ffc url(../img/admin/icon_error.gif) 5px .3em no-repeat;
+}
+
+ul.errorlist {
+ margin: 0 !important;
+ padding: 0 !important;
+}
+
+.errorlist li {
+ font-size: 12px !important;
+ display: block;
+ padding: 4px 5px 4px 25px;
+ margin: 0 0 3px 0;
+ border: 1px solid red;
+ color: white;
+ background: red url(../img/admin/icon_alert.gif) 5px .3em no-repeat;
+}
+
+.errorlist li a {
+ color: white;
+ text-decoration: underline;
+}
+
+td ul.errorlist {
+ margin: 0 !important;
+ padding: 0 !important;
+}
+
+td ul.errorlist li {
+ margin: 0 !important;
+}
+
+.errors {
+ background: #ffc;
+}
+
+.errors input, .errors select, .errors textarea {
+ border: 1px solid red;
+}
+
+div.system-message {
+ background: #ffc;
+ margin: 10px;
+ padding: 6px 8px;
+ font-size: .8em;
+}
+
+div.system-message p.system-message-title {
+ padding: 4px 5px 4px 25px;
+ margin: 0;
+ color: red;
+ background: #ffc url(../img/admin/icon_error.gif) 5px .3em no-repeat;
+}
+
+.description {
+ font-size: 12px;
+ padding: 5px 0 0 12px;
+}
+
+/* BREADCRUMBS */
+
+div.breadcrumbs {
+ background: white url(../img/admin/nav-bg-reverse.gif) 0 -10px repeat-x;
+ padding: 2px 8px 3px 8px;
+ font-size: 11px;
+ color: #999;
+ border-top: 1px solid white;
+ border-bottom: 1px solid #ccc;
+ text-align: left;
+}
+
+/* ACTION ICONS */
+
+.addlink {
+ padding-left: 12px;
+ background: url(../img/admin/icon_addlink.gif) 0 .2em no-repeat;
+}
+
+.changelink {
+ padding-left: 12px;
+ background: url(../img/admin/icon_changelink.gif) 0 .2em no-repeat;
+}
+
+.deletelink {
+ padding-left: 12px;
+ background: url(../img/admin/icon_deletelink.gif) 0 .25em no-repeat;
+}
+
+a.deletelink:link, a.deletelink:visited {
+ color: #CC3434;
+}
+
+a.deletelink:hover {
+ color: #993333;
+}
+
+/* OBJECT TOOLS */
+
+.object-tools {
+ font-size: 10px;
+ font-weight: bold;
+ font-family: Arial,Helvetica,sans-serif;
+ padding-left: 0;
+ float: right;
+ position: relative;
+ margin-top: -2.4em;
+ margin-bottom: -2em;
+}
+
+.form-row .object-tools {
+ margin-top: 5px;
+ margin-bottom: 5px;
+ float: none;
+ height: 2em;
+ padding-left: 3.5em;
+}
+
+.object-tools li {
+ display: block;
+ float: left;
+ background: url(../img/admin/tool-left.gif) 0 0 no-repeat;
+ padding: 0 0 0 8px;
+ margin-left: 2px;
+ height: 16px;
+}
+
+.object-tools li:hover {
+ background: url(../img/admin/tool-left_over.gif) 0 0 no-repeat;
+}
+
+.object-tools a:link, .object-tools a:visited {
+ display: block;
+ float: left;
+ color: white;
+ padding: .1em 14px .1em 8px;
+ height: 14px;
+ background: #999 url(../img/admin/tool-right.gif) 100% 0 no-repeat;
+}
+
+.object-tools a:hover, .object-tools li:hover a {
+ background: #5b80b2 url(../img/admin/tool-right_over.gif) 100% 0 no-repeat;
+}
+
+.object-tools a.viewsitelink, .object-tools a.golink {
+ background: #999 url(../img/admin/tooltag-arrowright.gif) top right no-repeat;
+ padding-right: 28px;
+}
+
+.object-tools a.viewsitelink:hover, .object-tools a.golink:hover {
+ background: #5b80b2 url(../img/admin/tooltag-arrowright_over.gif) top right no-repeat;
+}
+
+.object-tools a.addlink {
+ background: #999 url(../img/admin/tooltag-add.gif) top right no-repeat;
+ padding-right: 28px;
+}
+
+.object-tools a.addlink:hover {
+ background: #5b80b2 url(../img/admin/tooltag-add_over.gif) top right no-repeat;
+}
+
+/* OBJECT HISTORY */
+
+table#change-history {
+ width: 100%;
+}
+
+table#change-history tbody th {
+ width: 16em;
+}
+
+/* PAGE STRUCTURE */
+
+#container {
+ position: relative;
+ width: 100%;
+ min-width: 760px;
+ padding: 0;
+}
+
+#content {
+ margin: 10px 15px;
+}
+
+#header {
+ width: 100%;
+}
+
+#content-main {
+ float: left;
+ width: 100%;
+}
+
+#content-related {
+ float: right;
+ width: 18em;
+ position: relative;
+ margin-right: -19em;
+}
+
+#footer {
+ clear: both;
+ padding: 10px;
+}
+
+/* COLUMN TYPES */
+
+.colMS {
+ margin-right: 20em !important;
+}
+
+.colSM {
+ margin-left: 20em !important;
+}
+
+.colSM #content-related {
+ float: left;
+ margin-right: 0;
+ margin-left: -19em;
+}
+
+.colSM #content-main {
+ float: right;
+}
+
+.popup .colM {
+ width: 95%;
+}
+
+.subcol {
+ float: left;
+ width: 46%;
+ margin-right: 15px;
+}
+
+.dashboard #content {
+ width: 500px;
+}
+
+/* HEADER */
+
+#header {
+ background: #417690;
+ color: #ffc;
+ overflow: hidden;
+}
+
+#header a:link, #header a:visited {
+ color: white;
+}
+
+#header a:hover {
+ text-decoration: underline;
+}
+
+#branding h1 {
+ padding: 0 10px;
+ font-size: 18px;
+ margin: 8px 0;
+ font-weight: normal;
+ color: #f4f379;
+}
+
+#branding h2 {
+ padding: 0 10px;
+ font-size: 14px;
+ margin: -8px 0 8px 0;
+ font-weight: normal;
+ color: #ffc;
+}
+
+#user-tools {
+ position: absolute;
+ top: 0;
+ right: 0;
+ padding: 1.2em 10px;
+ font-size: 11px;
+ text-align: right;
+}
+
+/* SIDEBAR */
+
+#content-related h3 {
+ font-size: 12px;
+ color: #666;
+ margin-bottom: 3px;
+}
+
+#content-related h4 {
+ font-size: 11px;
+}
+
+#content-related .module h2 {
+ background: #eee url(../img/admin/nav-bg.gif) bottom left repeat-x;
+ color: #666;
+}
+
+/********************** admin 'forms.css' ************************/
+
+/* FORM ROWS */
+
+.form-row {
+ overflow: hidden;
+ padding: 8px 12px;
+ font-size: 11px;
+ border-bottom: 1px solid #eee;
+}
+
+.form-row img, .form-row input {
+ vertical-align: middle;
+}
+
+form .form-row p {
+ padding-left: 0;
+ font-size: 11px;
+}
+
+/* FORM LABELS */
+
+form h4 {
+ margin: 0 !important;
+ padding: 0 !important;
+ border: none !important;
+}
+
+label {
+ font-weight: normal !important;
+ color: #666;
+ font-size: 12px;
+}
+
+.required label, label.required {
+ font-weight: bold !important;
+ color: #333 !important;
+}
+
+/* RADIO BUTTONS */
+
+form ul.radiolist li {
+ list-style-type: none;
+}
+
+form ul.radiolist label {
+ float: none;
+ display: inline;
+}
+
+form ul.inline {
+ margin-left: 0;
+ padding: 0;
+}
+
+form ul.inline li {
+ float: left;
+ padding-right: 7px;
+}
+
+/* ALIGNED FIELDSETS */
+
+.aligned label {
+ display: block;
+ padding: 3px 10px 0 0;
+ float: left;
+ width: 8em;
+}
+
+.aligned ul label {
+ display: inline;
+ float: none;
+ width: auto;
+}
+
+.colMS .aligned .vLargeTextField, .colMS .aligned .vXMLLargeTextField {
+ width: 350px;
+}
+
+form .aligned p, form .aligned ul {
+ margin-left: 7em;
+ padding-left: 30px;
+}
+
+form .aligned table p {
+ margin-left: 0;
+ padding-left: 0;
+}
+
+form .aligned p.help {
+ padding-left: 38px;
+}
+
+.aligned .vCheckboxLabel {
+ float: none !important;
+ display: inline;
+ padding-left: 4px;
+}
+
+.colM .aligned .vLargeTextField, .colM .aligned .vXMLLargeTextField {
+ width: 610px;
+}
+
+.checkbox-row p.help {
+ margin-left: 0;
+ padding-left: 0 !important;
+}
+
+fieldset .field-box {
+ float: left;
+ margin-right: 20px;
+}
+
+/* WIDE FIELDSETS */
+
+.wide label {
+ width: 15em !important;
+}
+
+form .wide p {
+ margin-left: 15em;
+}
+
+form .wide p.help {
+ padding-left: 38px;
+}
+
+.colM fieldset.wide .vLargeTextField, .colM fieldset.wide .vXMLLargeTextField {
+ width: 450px;
+}
+
+/* COLLAPSED FIELDSETS */
+
+fieldset.collapsed * {
+ display: none;
+}
+
+fieldset.collapsed h2, fieldset.collapsed {
+ display: block !important;
+}
+
+fieldset.collapsed h2 {
+ background-image: url(../img/admin/nav-bg.gif);
+ background-position: bottom left;
+ color: #999;
+}
+
+fieldset.collapsed .collapse-toggle {
+ background: transparent;
+ display: inline !important;
+}
+
+/* MONOSPACE TEXTAREAS */
+
+fieldset.monospace textarea {
+ font-family: "Bitstream Vera Sans Mono",Monaco,"Courier New",Courier,monospace;
+}
+
+/* SUBMIT ROW */
+
+.submit-row {
+ padding: 5px 7px;
+ text-align: right;
+ background: white url(../img/admin/nav-bg.gif) 0 100% repeat-x;
+ border: 1px solid #ccc;
+ margin: 5px 0;
+ overflow: hidden;
+}
+
+.submit-row input {
+ margin: 0 0 0 5px;
+}
+
+.submit-row p {
+ margin: 0.3em;
+}
+
+.submit-row p.deletelink-box {
+ float: left;
+}
+
+.submit-row .deletelink {
+ background: url(../img/admin/icon_deletelink.gif) 0 50% no-repeat;
+ padding-left: 14px;
+}
+
+/* CUSTOM FORM FIELDS */
+
+.vSelectMultipleField {
+ vertical-align: top !important;
+}
+
+.vCheckboxField {
+ border: none;
+}
+
+.vDateField, .vTimeField {
+ margin-right: 2px;
+}
+
+.vURLField {
+ width: 30em;
+}
+
+.vLargeTextField, .vXMLLargeTextField {
+ width: 48em;
+}
+
+.flatpages-flatpage #id_content {
+ height: 40.2em;
+}
+
+.module table .vPositiveSmallIntegerField {
+ width: 2.2em;
+}
+
+.vTextField {
+ width: 20em;
+}
+
+.vIntegerField {
+ width: 5em;
+}
+
+.vForeignKeyRawIdAdminField {
+ width: 5em;
+}
+
+/* INLINES */
+
+.inline-group {
+ padding: 0;
+ border: 1px solid #ccc;
+ margin: 10px 0;
+}
+
+.inline-group .aligned label {
+ width: 8em;
+}
+
+.inline-related {
+ position: relative;
+}
+
+.inline-related h3 {
+ margin: 0;
+ color: #666;
+ padding: 3px 5px;
+ font-size: 11px;
+ background: #e1e1e1 url(../img/admin/nav-bg.gif) top left repeat-x;
+ border-bottom: 1px solid #ddd;
+}
+
+.inline-related h3 span.delete {
+ float: right;
+}
+
+.inline-related h3 span.delete label {
+ margin-left: 2px;
+ font-size: 11px;
+}
+
+.inline-related fieldset {
+ margin: 0;
+ background: #fff;
+ border: none;
+}
+
+.inline-related fieldset.module h3 {
+ margin: 0;
+ padding: 2px 5px 3px 5px;
+ font-size: 11px;
+ text-align: left;
+ font-weight: bold;
+ background: #bcd;
+ color: #fff;
+}
+
+.inline-group .tabular fieldset.module {
+ border: none;
+ border-bottom: 1px solid #ddd;
+}
+
+.inline-related.tabular fieldset.module table {
+ width: 100%;
+}
+
+.last-related fieldset {
+ border: none;
+}
+
+.inline-group .tabular tr.has_original td {
+ padding-top: 2em;
+}
+
+.inline-group .tabular tr td.original {
+ padding: 2px 0 0 0;
+ width: 0;
+ _position: relative;
+}
+
+.inline-group .tabular th.original {
+ width: 0px;
+ padding: 0;
+}
+
+.inline-group .tabular td.original p {
+ position: absolute;
+ left: 0;
+ height: 1.1em;
+ padding: 2px 7px;
+ overflow: hidden;
+ font-size: 9px;
+ font-weight: bold;
+ color: #666;
+ _width: 700px;
+}
+
+.inline-group ul.tools {
+ padding: 0;
+ margin: 0;
+ list-style: none;
+}
+
+.inline-group ul.tools li {
+ display: inline;
+ padding: 0 5px;
+}
+
+.inline-group div.add-row,
+.inline-group .tabular tr.add-row td {
+ color: #666;
+ padding: 3px 5px;
+ border-bottom: 1px solid #ddd;
+ background: #e1e1e1 url(../img/admin/nav-bg.gif) top left repeat-x;
+}
+
+.inline-group .tabular tr.add-row td {
+ padding: 4px 5px 3px;
+ border-bottom: none;
+}
+
+.inline-group ul.tools a.add,
+.inline-group div.add-row a,
+.inline-group .tabular tr.add-row td a {
+ background: url(../img/admin/icon_addlink.gif) 0 50% no-repeat;
+ padding-left: 14px;
+ font-size: 11px;
+ outline: 0; /* Remove dotted border around link */
+}
+
+.empty-form {
+ display: none;
+}
+
+/* IE7 specific bug fixes */
+
+.submit-row input {
+ float: right;
+}
+
+/* Overrides specific to REST framework */
+
+#site-name a {
+ color: #F4F379 !important;
+}
+
+.errorlist {
+ display: inline !important;
+}
+
+.errorlist li {
+ display: inline !important;
+ background: white !important;
+ color: black !important;
+ border: 0 !important;
+}
+
+/* Custom styles */
+.version {
+ font-size: 8px;
+}
diff --git a/djangorestframework/templates/renderer.html b/djangorestframework/templates/renderer.html
index 5faa8b3e..e396a58f 100644
--- a/djangorestframework/templates/renderer.html
+++ b/djangorestframework/templates/renderer.html
@@ -1,25 +1,14 @@
-{% load urlize_quoted_links %}{% load add_query_param %}
+
+{% load urlize_quoted_links %}
+{% load add_query_param %}
+{% load static %}
-
-
- {% if ADMIN_MEDIA_PREFIX %}
-
-
- {% else %}
-
-
- {% endif %}
- Django REST framework - {{ name }}
-
+
+
+ Django REST framework - {{ name }}
+
@@ -34,7 +23,7 @@
--
cgit v1.2.3
From c0674e36d498b7b727e3d5a260b5cdf4104b4d26 Mon Sep 17 00:00:00 2001
From: Tom Christie
Date: Sat, 28 Jan 2012 19:06:40 +0000
Subject: Drop implicit 'pk' on last arg in urlconf. (Too magical).
---
djangorestframework/mixins.py | 5 -----
1 file changed, 5 deletions(-)
(limited to 'djangorestframework')
diff --git a/djangorestframework/mixins.py b/djangorestframework/mixins.py
index 7f0870f8..2ea5e840 100644
--- a/djangorestframework/mixins.py
+++ b/djangorestframework/mixins.py
@@ -507,11 +507,6 @@ class ModelMixin(object):
if BaseRenderer._FORMAT_QUERY_PARAM in tmp:
del tmp[BaseRenderer._FORMAT_QUERY_PARAM]
- if args:
- # If we have any no kwargs then assume the last arg represents the
- # primrary key. Otherwise assume the kwargs uniquely identify the
- # model.
- tmp.update({'pk': args[-1]})
return Q(**tmp)
def get_instance_data(self, model, content, **kwargs):
--
cgit v1.2.3
From c7a805603405e21897b1788408beb5165685a2ec Mon Sep 17 00:00:00 2001
From: Tom Christie
Date: Sun, 29 Jan 2012 13:19:56 +0000
Subject: Use named args in mixin tests.
---
djangorestframework/tests/mixins.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
(limited to 'djangorestframework')
diff --git a/djangorestframework/tests/mixins.py b/djangorestframework/tests/mixins.py
index 88b13dd5..a7512efc 100644
--- a/djangorestframework/tests/mixins.py
+++ b/djangorestframework/tests/mixins.py
@@ -30,7 +30,7 @@ class TestModelRead(TestModelsTestCase):
mixin = ReadModelMixin()
mixin.resource = GroupResource
- response = mixin.get(request, group.id)
+ response = mixin.get(request, id=group.id)
self.assertEquals(group.name, response.name)
def test_read_404(self):
@@ -41,7 +41,7 @@ class TestModelRead(TestModelsTestCase):
mixin = ReadModelMixin()
mixin.resource = GroupResource
- self.assertRaises(ErrorResponse, mixin.get, request, 12345)
+ self.assertRaises(ErrorResponse, mixin.get, request, id=12345)
class TestModelCreation(TestModelsTestCase):
--
cgit v1.2.3
From 278b3576f311ad49a95b8efb997a194e5211df57 Mon Sep 17 00:00:00 2001
From: Tom Christie
Date: Mon, 30 Jan 2012 14:13:57 +0000
Subject: Fixes #148. Thanks @dvinegla.
---
djangorestframework/permissions.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'djangorestframework')
diff --git a/djangorestframework/permissions.py b/djangorestframework/permissions.py
index 945023ce..d832c5fe 100644
--- a/djangorestframework/permissions.py
+++ b/djangorestframework/permissions.py
@@ -188,7 +188,7 @@ class PerUserThrottling(BaseThrottle):
def get_cache_key(self):
if self.auth.is_authenticated():
- ident = str(self.auth)
+ ident = unicode(self.auth)
else:
ident = self.view.request.META.get('REMOTE_ADDR', None)
return 'throttle_user_%s' % ident
--
cgit v1.2.3
From 50c359c551728b8cdbb963a9f233c635065effb0 Mon Sep 17 00:00:00 2001
From: Tom Christie
Date: Mon, 30 Jan 2012 15:54:38 +0000
Subject: Refs #148
---
djangorestframework/permissions.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'djangorestframework')
diff --git a/djangorestframework/permissions.py b/djangorestframework/permissions.py
index d832c5fe..dfe55ce9 100644
--- a/djangorestframework/permissions.py
+++ b/djangorestframework/permissions.py
@@ -188,7 +188,7 @@ class PerUserThrottling(BaseThrottle):
def get_cache_key(self):
if self.auth.is_authenticated():
- ident = unicode(self.auth)
+ ident = self.auth.id
else:
ident = self.view.request.META.get('REMOTE_ADDR', None)
return 'throttle_user_%s' % ident
--
cgit v1.2.3
From b2fcfffb3bdaed89d39ee563c58dc0ede5e857ac Mon Sep 17 00:00:00 2001
From: Tom Christie
Date: Tue, 31 Jan 2012 09:05:52 +0000
Subject: django-staticfiles for Django 1.2 compatability
---
djangorestframework/runtests/settings.py | 6 ++++++
1 file changed, 6 insertions(+)
(limited to 'djangorestframework')
diff --git a/djangorestframework/runtests/settings.py b/djangorestframework/runtests/settings.py
index 07855fa7..25f77111 100644
--- a/djangorestframework/runtests/settings.py
+++ b/djangorestframework/runtests/settings.py
@@ -97,6 +97,12 @@ INSTALLED_APPS = (
'djangorestframework',
)
+import django
+
+if django.VERSION < (1, 3):
+ INSTALLED_APPS += ('staticfiles',)
+
+
# OAuth support is optional, so we only test oauth if it's installed.
try:
import oauth_provider
--
cgit v1.2.3
From 7886fa2b16fe9a82b1b83b7e2ddc361870b21d48 Mon Sep 17 00:00:00 2001
From: Tom Christie
Date: Wed, 1 Feb 2012 20:24:45 +0000
Subject: Update test settings for 1.2
---
djangorestframework/runtests/settings.py | 2 ++
1 file changed, 2 insertions(+)
(limited to 'djangorestframework')
diff --git a/djangorestframework/runtests/settings.py b/djangorestframework/runtests/settings.py
index 25f77111..f54a554b 100644
--- a/djangorestframework/runtests/settings.py
+++ b/djangorestframework/runtests/settings.py
@@ -97,6 +97,8 @@ INSTALLED_APPS = (
'djangorestframework',
)
+STATIC_URL = '/static/'
+
import django
if django.VERSION < (1, 3):
--
cgit v1.2.3
From 894f63259880252ed5317ce485eb13c4429b65c1 Mon Sep 17 00:00:00 2001
From: Tom Christie
Date: Wed, 1 Feb 2012 20:48:32 +0000
Subject: Remove use of Q objects.
---
djangorestframework/mixins.py | 59 +++++++++++++++----------------------------
1 file changed, 20 insertions(+), 39 deletions(-)
(limited to 'djangorestframework')
diff --git a/djangorestframework/mixins.py b/djangorestframework/mixins.py
index 2ea5e840..c7b32d2d 100644
--- a/djangorestframework/mixins.py
+++ b/djangorestframework/mixins.py
@@ -6,7 +6,6 @@ classes that can be added to a `View`.
from django.contrib.auth.models import AnonymousUser
from django.core.paginator import Paginator
from django.db.models.fields.related import ForeignKey
-from django.db.models.query import Q
from django.http import HttpResponse
from urlobject import URLObject
@@ -479,39 +478,25 @@ class ModelMixin(object):
queryset = None
- def build_query(self, *args, **kwargs):
- """ Returns django.db.models.Q object to be used for the objects retrival.
-
- Arguments:
- - args: unnamed URL arguments
- - kwargs: named URL arguments
-
- If a URL passes any arguments to the view being the QueryMixin subclass
- build_query manages the arguments and provides the Q object that will be
- used for the objects retrival with filter/get queryset methods.
-
- Technically, neither args nor kwargs have to be provided, however the default
- behaviour is to map all kwargs as the query constructors so that if this
- method is not overriden only kwargs keys being model fields are valid.
-
- If positional args are provided, the last one argument is understood
- as the primary key. However this usage should be considered
- deperecated, and will be removed in a future version.
+ def get_query_kwargs(self, *args, **kwargs):
+ """
+ Return a dict of kwargs that will be used to build the
+ model instance retrieval or to filter querysets.
"""
- tmp = dict(kwargs)
+ kwargs = dict(kwargs)
# If the URLconf includes a .(?P\w+) pattern to match against
# a .json, .xml suffix, then drop the 'format' kwarg before
# constructing the query.
- if BaseRenderer._FORMAT_QUERY_PARAM in tmp:
- del tmp[BaseRenderer._FORMAT_QUERY_PARAM]
+ if BaseRenderer._FORMAT_QUERY_PARAM in kwargs:
+ del kwargs[BaseRenderer._FORMAT_QUERY_PARAM]
- return Q(**tmp)
+ return kwargs
def get_instance_data(self, model, content, **kwargs):
"""
- Returns the dict with the data for model instance creation/update query.
+ Returns the dict with the data for model instance creation/update.
Arguments:
- model: model class (django.db.models.Model subclass) to work with
@@ -536,12 +521,11 @@ class ModelMixin(object):
return all_kw_args
- def get_object(self, *args, **kwargs):
+ def get_instance(self, **kwargs):
"""
- Get the instance object for read/update/delete requests.
+ Get a model instance for read/update/delete requests.
"""
- model = self.resource.model
- return model.objects.get(self.build_query(*args, **kwargs))
+ return self.get_queryset().get(**kwargs)
def get_queryset(self):
"""
@@ -563,21 +547,15 @@ class ReadModelMixin(ModelMixin):
"""
def get(self, request, *args, **kwargs):
model = self.resource.model
+ query_kwargs = self.get_query_kwargs(request, *args, **kwargs)
try:
- self.model_instance = self.get_object(*args, **kwargs)
+ self.model_instance = self.get_instance(**query_kwargs)
except model.DoesNotExist:
raise ErrorResponse(status.HTTP_404_NOT_FOUND)
return self.model_instance
- def build_query(self, *args, **kwargs):
- # Build query is overriden to filter the kwargs priori
- # to use them as build_query argument
- filtered_keywords = kwargs.copy()
-
- return super(ReadModelMixin, self).build_query(*args, **filtered_keywords)
-
class CreateModelMixin(ModelMixin):
"""
@@ -625,11 +603,12 @@ class UpdateModelMixin(ModelMixin):
"""
def put(self, request, *args, **kwargs):
model = self.resource.model
+ query_kwargs = self.get_query_kwargs(request, *args, **kwargs)
# TODO: update on the url of a non-existing resource url doesn't work
# correctly at the moment - will end up with a new url
try:
- self.model_instance = self.get_object(*args, **kwargs)
+ self.model_instance = self.get_instance(*query_kwargs)
for (key, val) in self.CONTENT.items():
setattr(self.model_instance, key, val)
@@ -645,9 +624,10 @@ class DeleteModelMixin(ModelMixin):
"""
def delete(self, request, *args, **kwargs):
model = self.resource.model
+ query_kwargs = self.get_query_kwargs(request, *args, **kwargs)
try:
- instance = self.get_object(*args, **kwargs)
+ instance = self.get_instance(**query_kwargs)
except model.DoesNotExist:
raise ErrorResponse(status.HTTP_404_NOT_FOUND, None, {})
@@ -663,8 +643,9 @@ class ListModelMixin(ModelMixin):
def get(self, request, *args, **kwargs):
queryset = self.get_queryset()
ordering = self.get_ordering()
+ query_kwargs = self.get_query_kwargs(request, *args, **kwargs)
- queryset = queryset.filter(self.build_query(**kwargs))
+ queryset = queryset.filter(**query_kwargs)
if ordering:
queryset = queryset.order_by(*ordering)
--
cgit v1.2.3
From da8187d2c293e095969c00751c21338d53c7f3f2 Mon Sep 17 00:00:00 2001
From: Camille Harang
Date: Wed, 1 Feb 2012 23:56:54 +0100
Subject: * -> **
---
djangorestframework/mixins.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'djangorestframework')
diff --git a/djangorestframework/mixins.py b/djangorestframework/mixins.py
index c7b32d2d..f4a9c998 100644
--- a/djangorestframework/mixins.py
+++ b/djangorestframework/mixins.py
@@ -608,7 +608,7 @@ class UpdateModelMixin(ModelMixin):
# TODO: update on the url of a non-existing resource url doesn't work
# correctly at the moment - will end up with a new url
try:
- self.model_instance = self.get_instance(*query_kwargs)
+ self.model_instance = self.get_instance(**query_kwargs)
for (key, val) in self.CONTENT.items():
setattr(self.model_instance, key, val)
--
cgit v1.2.3
From bd25e99f155b68e31239bf1c9e3d4e70d53bbddd Mon Sep 17 00:00:00 2001
From: Tom Christie
Date: Thu, 2 Feb 2012 09:05:28 +0000
Subject: Python docs say inherit from Exception, not BaseException.
---
djangorestframework/response.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'djangorestframework')
diff --git a/djangorestframework/response.py b/djangorestframework/response.py
index 96345cee..13f0477e 100644
--- a/djangorestframework/response.py
+++ b/djangorestframework/response.py
@@ -34,7 +34,7 @@ class Response(object):
return STATUS_CODE_TEXT.get(self.status, '')
-class ErrorResponse(BaseException):
+class ErrorResponse(Exception):
"""
An exception representing an Response that should be returned immediately.
Any content should be serialized as-is, without being filtered.
--
cgit v1.2.3
From 15fc26f50b94d41d1024a3f40fe21af5f2d07bfb Mon Sep 17 00:00:00 2001
From: Tom Christie
Date: Tue, 7 Feb 2012 08:58:15 +0000
Subject: Fix up packaging and staticfiles changes. Fixes #155. Fixes #153.
Fixes #150.
---
.../static/css/djangorestframework.css | 57 ++++++++++++++
djangorestframework/templates/api_login.html | 90 ++++++++++------------
2 files changed, 97 insertions(+), 50 deletions(-)
(limited to 'djangorestframework')
diff --git a/djangorestframework/static/css/djangorestframework.css b/djangorestframework/static/css/djangorestframework.css
index 8fc4bace..1e75b8e8 100644
--- a/djangorestframework/static/css/djangorestframework.css
+++ b/djangorestframework/static/css/djangorestframework.css
@@ -1129,6 +1129,58 @@ fieldset.monospace textarea {
float: right;
}
+body.login {
+ background: #eee;
+}
+
+.login #container {
+ background: white;
+ border: 1px solid #ccc;
+ width: 28em;
+ min-width: 300px;
+ margin-left: auto;
+ margin-right: auto;
+ margin-top: 100px;
+}
+
+.login #content-main {
+ width: 100%;
+}
+
+.login form {
+ margin-top: 1em;
+}
+
+.login .form-row {
+ padding: 4px 0;
+ float: left;
+ width: 100%;
+}
+
+.login .form-row label {
+ float: left;
+ width: 9em;
+ padding-right: 0.5em;
+ line-height: 2em;
+ text-align: right;
+ font-size: 1em;
+ color: #333;
+}
+
+.login .form-row #id_username, .login .form-row #id_password {
+ width: 14em;
+}
+
+.login span.help {
+ font-size: 10px;
+ display: block;
+}
+
+.login .submit-row {
+ clear: both;
+ padding: 1em 0 0 9.4em;
+}
+
/* Overrides specific to REST framework */
#site-name a {
@@ -1147,6 +1199,11 @@ fieldset.monospace textarea {
}
/* Custom styles */
+
.version {
font-size: 8px;
}
+
+.form-row {
+ border-bottom: 0.25em !important;
+}
diff --git a/djangorestframework/templates/api_login.html b/djangorestframework/templates/api_login.html
index 750f898b..016a4e10 100644
--- a/djangorestframework/templates/api_login.html
+++ b/djangorestframework/templates/api_login.html
@@ -1,54 +1,44 @@
+{% load static %}
-
- {% if ADMIN_MEDIA_PREFIX %}
-
-
-
- {% else %}
-
-
-
- {% endif %}
-
-
-
-
-
-
- Django REST framework
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+ Django REST framework
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
--
cgit v1.2.3
From 76a7d35813b637bb199a0d388468f9265f8adaf2 Mon Sep 17 00:00:00 2001
From: Jamie Matthews
Date: Tue, 7 Feb 2012 11:08:55 +0000
Subject: Ensure duplicate "page" parameters are not created
Previously, URLObject.add_query_param was used to generate
next/previous page links in PaginatorMixin. This resulted
in (for example) page 2's "next" link having the params:
?page=2&page=3
Instead, URLObject.set_query_param should be used to replace
the current value of the "page" parameter.
---
djangorestframework/mixins.py | 2 +-
djangorestframework/tests/mixins.py | 9 +++++++++
2 files changed, 10 insertions(+), 1 deletion(-)
(limited to 'djangorestframework')
diff --git a/djangorestframework/mixins.py b/djangorestframework/mixins.py
index f4a9c998..836c3a59 100644
--- a/djangorestframework/mixins.py
+++ b/djangorestframework/mixins.py
@@ -679,7 +679,7 @@ class PaginatorMixin(object):
Constructs a url used for getting the next/previous urls
"""
url = URLObject.parse(self.request.get_full_path())
- url = url.add_query_param('page', page_number)
+ url = url.set_query_param('page', page_number)
limit = self.get_limit()
if limit != self.limit:
diff --git a/djangorestframework/tests/mixins.py b/djangorestframework/tests/mixins.py
index a7512efc..8268fdca 100644
--- a/djangorestframework/tests/mixins.py
+++ b/djangorestframework/tests/mixins.py
@@ -280,3 +280,12 @@ class TestPagination(TestCase):
self.assertTrue('foo=bar' in content['next'])
self.assertTrue('another=something' in content['next'])
self.assertTrue('page=2' in content['next'])
+
+ def test_duplicate_parameters_are_not_created(self):
+ """ Regression: ensure duplicate "page" parameters are not added to
+ paginated URLs. So page 1 should contain ?page=2, not ?page=1&page=2 """
+ request = self.req.get('/paginator/?page=1')
+ response = MockPaginatorView.as_view()(request)
+ content = json.loads(response.content)
+ self.assertTrue('page=2' in content['next'])
+ self.assertFalse('page=1' in content['next'])
--
cgit v1.2.3