From a9e0159481a1b52e396bb0edee5f03563226e6da Mon Sep 17 00:00:00 2001 From: Marko Tibold Date: Sat, 28 Jan 2012 13:38:29 +0100 Subject: prepare for tagging --- djangorestframework/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'djangorestframework') diff --git a/djangorestframework/__init__.py b/djangorestframework/__init__.py index 55f92cc4..a5ba90e2 100644 --- a/djangorestframework/__init__.py +++ b/djangorestframework/__init__.py @@ -1,3 +1,3 @@ -__version__ = '0.3.2-dev' +__version__ = '0.3.2' VERSION = __version__ # synonym -- cgit v1.2.3 From cc226e7e67b13a25c59a727581f4fd780f5d553a Mon Sep 17 00:00:00 2001 From: Marko Tibold Date: Sat, 28 Jan 2012 14:06:34 +0100 Subject: moving forward --- djangorestframework/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'djangorestframework') diff --git a/djangorestframework/__init__.py b/djangorestframework/__init__.py index a5ba90e2..55f92cc4 100644 --- a/djangorestframework/__init__.py +++ b/djangorestframework/__init__.py @@ -1,3 +1,3 @@ -__version__ = '0.3.2' +__version__ = '0.3.2-dev' VERSION = __version__ # synonym -- cgit v1.2.3 From bbfa404e4679f4229e44fd7e641e62fdd2e7bdd5 Mon Sep 17 00:00:00 2001 From: Marko Tibold Date: Sat, 28 Jan 2012 15:27:06 +0100 Subject: Fix silly error. This makes more sense. --- djangorestframework/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'djangorestframework') diff --git a/djangorestframework/__init__.py b/djangorestframework/__init__.py index 55f92cc4..0aaa2915 100644 --- a/djangorestframework/__init__.py +++ b/djangorestframework/__init__.py @@ -1,3 +1,3 @@ -__version__ = '0.3.2-dev' +__version__ = '0.3.3-dev' VERSION = __version__ # synonym -- cgit v1.2.3 From 22ee89f0f3fa295a265547336f837261bb919f34 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Sat, 28 Jan 2012 14:38:06 +0000 Subject: Tidy up auto-escaping. --- djangorestframework/templates/renderer.html | 2 +- djangorestframework/templates/renderer.txt | 4 ++-- djangorestframework/views.py | 7 +++++-- 3 files changed, 8 insertions(+), 5 deletions(-) (limited to 'djangorestframework') diff --git a/djangorestframework/templates/renderer.html b/djangorestframework/templates/renderer.html index ff761023..5faa8b3e 100644 --- a/djangorestframework/templates/renderer.html +++ b/djangorestframework/templates/renderer.html @@ -50,7 +50,7 @@

{{ 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 %} - - - -
- - - -
- -
-
-{% csrf_token %} -
- {{ form.username }} -
-
- {{ form.password }} - -
-
- -
-
- -
+ + + + + + +
+ + + +
+
+
+ {% csrf_token %} +
+ {{ form.username }} +
+
+ {{ form.password }} + +
+
+ +
+
+ +
+
+
+ + - -
-
- - - -
- +
+ -- 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