mirror of
https://github.com/django/django.git
synced 2025-07-05 02:09:13 +00:00
Merged to trunk r1174, some other fixes
git-svn-id: http://code.djangoproject.com/svn/django/branches/new-admin@1175 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
commit
5bba260dcc
@ -77,7 +77,7 @@ def main():
|
|||||||
try:
|
try:
|
||||||
action = args[0]
|
action = args[0]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
print_error("An action is required.", sys.argv[0])
|
parser.print_usage_and_exit()
|
||||||
if not ACTION_MAPPING.has_key(action):
|
if not ACTION_MAPPING.has_key(action):
|
||||||
print_error("Your action, %r, was invalid." % action, sys.argv[0])
|
print_error("Your action, %r, was invalid." % action, sys.argv[0])
|
||||||
if action in ('createsuperuser', 'init', 'validate'):
|
if action in ('createsuperuser', 'init', 'validate'):
|
||||||
|
@ -155,10 +155,16 @@ def items_for_result(cl, result):
|
|||||||
except meta.FieldDoesNotExist:
|
except meta.FieldDoesNotExist:
|
||||||
# For non-field list_display values, the value is a method
|
# For non-field list_display values, the value is a method
|
||||||
# name. Execute the method.
|
# name. Execute the method.
|
||||||
|
func = getattr(result, field_name)
|
||||||
try:
|
try:
|
||||||
result_repr = strip_tags(str(getattr(result, field_name)()))
|
result_repr = str(func())
|
||||||
except ObjectDoesNotExist:
|
except ObjectDoesNotExist:
|
||||||
result_repr = EMPTY_CHANGELIST_VALUE
|
result_repr = EMPTY_CHANGELIST_VALUE
|
||||||
|
else:
|
||||||
|
# Strip HTML tags in the resulting text, except if the
|
||||||
|
# function has an "allow_tags" attribute set to True.
|
||||||
|
if not getattr(func, 'allow_tags', False):
|
||||||
|
result_repr = strip_tags(result_repr)
|
||||||
else:
|
else:
|
||||||
field_val = getattr(result, f.attname)
|
field_val = getattr(result, f.attname)
|
||||||
|
|
||||||
|
@ -30,7 +30,6 @@ def submit_row(context, bound_manipulator):
|
|||||||
show_delete = context['show_delete']
|
show_delete = context['show_delete']
|
||||||
has_delete_permission = context['has_delete_permission']
|
has_delete_permission = context['has_delete_permission']
|
||||||
is_popup = context['is_popup']
|
is_popup = context['is_popup']
|
||||||
print is_popup.something
|
|
||||||
return {
|
return {
|
||||||
'onclick_attrib' : (bound_manipulator.ordered_objects and change
|
'onclick_attrib' : (bound_manipulator.ordered_objects and change
|
||||||
and 'onclick="submitOrderForm();"' or ''),
|
and 'onclick="submitOrderForm();"' or ''),
|
||||||
|
@ -265,7 +265,24 @@ class RelatedObject(object):
|
|||||||
return bound_related_object_class(self, field_mapping, original)
|
return bound_related_object_class(self, field_mapping, original)
|
||||||
|
|
||||||
def get_method_name_part(self):
|
def get_method_name_part(self):
|
||||||
return self.parent_opts.get_rel_object_method_name(self.opts, self.field)
|
# This method encapsulates the logic that decides what name to give a
|
||||||
|
# method that retrieves related many-to-one objects. Usually it just
|
||||||
|
# uses the lower-cased object_name, but if the related object is in
|
||||||
|
# another app, its app_label is appended.
|
||||||
|
#
|
||||||
|
# Examples:
|
||||||
|
#
|
||||||
|
# # Normal case -- a related object in the same app.
|
||||||
|
# # This method returns "choice".
|
||||||
|
# Poll.get_choice_list()
|
||||||
|
#
|
||||||
|
# # A related object in a different app.
|
||||||
|
# # This method returns "lcom_bestofaward".
|
||||||
|
# Place.get_lcom_bestofaward_list() # "lcom_bestofaward"
|
||||||
|
rel_obj_name = self.field.rel.related_name or self.opts.object_name.lower()
|
||||||
|
if self.parent_opts.app_label != self.opts.app_label:
|
||||||
|
rel_obj_name = '%s_%s' % (self.opts.app_label, rel_obj_name)
|
||||||
|
return rel_obj_name
|
||||||
|
|
||||||
class Options:
|
class Options:
|
||||||
def __init__(self, module_name='', verbose_name='', verbose_name_plural='', db_table='',
|
def __init__(self, module_name='', verbose_name='', verbose_name_plural='', db_table='',
|
||||||
@ -387,26 +404,6 @@ class Options:
|
|||||||
def get_delete_permission(self):
|
def get_delete_permission(self):
|
||||||
return 'delete_%s' % self.object_name.lower()
|
return 'delete_%s' % self.object_name.lower()
|
||||||
|
|
||||||
def get_rel_object_method_name(self, rel_opts, rel_field):
|
|
||||||
# This method encapsulates the logic that decides what name to give a
|
|
||||||
# method that retrieves related many-to-one objects. Usually it just
|
|
||||||
# uses the lower-cased object_name, but if the related object is in
|
|
||||||
# another app, its app_label is appended.
|
|
||||||
#
|
|
||||||
# Examples:
|
|
||||||
#
|
|
||||||
# # Normal case -- a related object in the same app.
|
|
||||||
# # This method returns "choice".
|
|
||||||
# Poll.get_choice_list()
|
|
||||||
#
|
|
||||||
# # A related object in a different app.
|
|
||||||
# # This method returns "lcom_bestofaward".
|
|
||||||
# Place.get_lcom_bestofaward_list() # "lcom_bestofaward"
|
|
||||||
rel_obj_name = rel_field.rel.related_name or rel_opts.object_name.lower()
|
|
||||||
if self.app_label != rel_opts.app_label:
|
|
||||||
rel_obj_name = '%s_%s' % (rel_opts.app_label, rel_obj_name)
|
|
||||||
return rel_obj_name
|
|
||||||
|
|
||||||
def get_all_related_objects(self):
|
def get_all_related_objects(self):
|
||||||
try: # Try the cache first.
|
try: # Try the cache first.
|
||||||
return self._all_related_objects
|
return self._all_related_objects
|
||||||
|
119
docs/outputting_csv.txt
Normal file
119
docs/outputting_csv.txt
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
==========================
|
||||||
|
Outputting CSV with Django
|
||||||
|
==========================
|
||||||
|
|
||||||
|
This document explains how to output CSV (Comma Separated Values) dynamically
|
||||||
|
using Django views.
|
||||||
|
|
||||||
|
To do this, you can either use the `Python CSV library`_ or the Django template
|
||||||
|
system.
|
||||||
|
|
||||||
|
.. _Python CSV library: http://www.python.org/doc/current/lib/module-csv.html
|
||||||
|
|
||||||
|
Using the Python CSV library
|
||||||
|
============================
|
||||||
|
|
||||||
|
Python comes with a CSV library, ``csv``. The key to using it with Django is
|
||||||
|
that the ``csv`` module's CSV-creation capability acts on file-like objects,
|
||||||
|
and Django's ``HttpResponse`` objects are file-like objects.
|
||||||
|
|
||||||
|
.. admonition:: Note
|
||||||
|
|
||||||
|
For more information on ``HttpResponse`` objects, see
|
||||||
|
`Request and response objects`_.
|
||||||
|
|
||||||
|
For more information on the CSV library, see the `CSV library docs`_.
|
||||||
|
|
||||||
|
.. _Request and response objects: http://www.djangoproject.com/documentation/request_response/
|
||||||
|
.. _CSV library docs: http://www.python.org/doc/current/lib/module-csv.html
|
||||||
|
|
||||||
|
Here's an example::
|
||||||
|
|
||||||
|
import csv
|
||||||
|
from django.utils.httpwrappers import HttpResponse
|
||||||
|
|
||||||
|
def some_view(request):
|
||||||
|
# Create the HttpResponse object with the appropriate CSV header.
|
||||||
|
response = HttpResponse(mimetype='text/csv')
|
||||||
|
response['Content-Disposition'] = 'attachment; filename=somefilename.csv'
|
||||||
|
|
||||||
|
writer = csv.writer(response)
|
||||||
|
writer.writerow(['First row', 'Foo', 'Bar', 'Baz'])
|
||||||
|
writer.writerow(['Second row', 'A', 'B', 'C', '"Testing"', "Here's a quote"])
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
The code and comments should be self-explanatory, but a few things deserve a
|
||||||
|
mention:
|
||||||
|
|
||||||
|
* The response gets a special mimetype, ``text/csv``. This tells
|
||||||
|
browsers that the document is a CSV file, rather than an HTML file. If
|
||||||
|
you leave this off, browsers will probably interpret the output as HTML,
|
||||||
|
which would result in ugly, scary gobbledygook in the browser window.
|
||||||
|
|
||||||
|
* The response gets an additional ``Content-Disposition`` header, which
|
||||||
|
contains the name of the CSV file. This filename is arbitrary: Call it
|
||||||
|
whatever you want. It'll be used by browsers in the "Save as..."
|
||||||
|
dialogue, etc.
|
||||||
|
|
||||||
|
* Hooking into the CSV-generation API is easy: Just pass ``response`` as
|
||||||
|
the first argument to ``csv.writer``. The ``csv.writer`` function expects
|
||||||
|
a file-like object, and ``HttpResponse`` objects fit the bill.
|
||||||
|
|
||||||
|
* For each row in your CSV file, call ``writer.writerow``, passing it an
|
||||||
|
iterable object such as a list or tuple.
|
||||||
|
|
||||||
|
* The CSV module takes care of quoting for you, so you don't have to worry
|
||||||
|
about escaping strings with quotes or commas in them. Just pass
|
||||||
|
``writerow()`` your raw strings, and it'll do the right thing.
|
||||||
|
|
||||||
|
Using the template system
|
||||||
|
=========================
|
||||||
|
|
||||||
|
Alternatively, you can use the `Django template system`_ to generate CSV. This
|
||||||
|
is lower-level than using the convenient CSV, but the solution is presented
|
||||||
|
here for completeness.
|
||||||
|
|
||||||
|
The idea here is to pass a list of items to your template, and have the
|
||||||
|
template output the commas in a ``{% for %}`` loop.
|
||||||
|
|
||||||
|
Here's an example, which generates the same CSV file as above::
|
||||||
|
|
||||||
|
from django.utils.httpwrappers import HttpResponse
|
||||||
|
from django.core.template import loader, Context
|
||||||
|
|
||||||
|
def some_view(request):
|
||||||
|
# Create the HttpResponse object with the appropriate CSV header.
|
||||||
|
response = HttpResponse(mimetype='text/csv')
|
||||||
|
response['Content-Disposition'] = 'attachment; filename=somefilename.csv'
|
||||||
|
|
||||||
|
# The data is hard-coded here, but you could load it from a database or
|
||||||
|
# some other source.
|
||||||
|
csv_data = (
|
||||||
|
('First row', 'Foo', 'Bar', 'Baz'),
|
||||||
|
('Second row', 'A', 'B', 'C', '"Testing"', "Here's a quote"),
|
||||||
|
)
|
||||||
|
|
||||||
|
t = loader.get_template('my_template_name')
|
||||||
|
c = Context({
|
||||||
|
'data': csv_data,
|
||||||
|
})
|
||||||
|
response.write(t.render(c))
|
||||||
|
return response
|
||||||
|
|
||||||
|
The only difference between this example and the previous example is that this
|
||||||
|
one uses template loading instead of the CSV module. The rest of the code --
|
||||||
|
such as the ``mimetype='text/csv'`` -- is the same.
|
||||||
|
|
||||||
|
Then, create the template ``my_template_name``, with this template code::
|
||||||
|
|
||||||
|
{% for row in data %}"{{ row.0|addslashes }}", "{{ row.1|addslashes }}", "{{ row.2|addslashes }}", "{{ row.3|addslashes }}", "{{ row.4|addslashes }}"
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
This template is quite basic. It just iterates over the given data and displays
|
||||||
|
a line of CSV for each row. It uses the `addslashes template filter`_ to ensure
|
||||||
|
there aren't any problems with quotes. If you can be certain your data doesn't
|
||||||
|
have single or double quotes in it, you can remove the ``addslashes`` filters.
|
||||||
|
|
||||||
|
.. _Django template system: http://www.djangoproject.com/documentation/templates/
|
||||||
|
.. _addslashes template filter: http://www.djangoproject.com/documentation/templates/#addslashes
|
Loading…
x
Reference in New Issue
Block a user