1
0
mirror of https://github.com/django/django.git synced 2025-07-05 02:09:13 +00:00

Merge to r764. Fix 684, also allow overloading indivual fields templates in the admin.

git-svn-id: http://code.djangoproject.com/svn/django/branches/new-admin@765 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Robert Wittams 2005-10-02 17:55:03 +00:00
parent 3afc81d44e
commit cfe2e95529
4 changed files with 127 additions and 32 deletions

View File

@ -228,15 +228,17 @@ class SsiNode(template.Node):
return output
class IncludeNode(template.Node):
def __init__(self, template_path):
def __init__(self, template_path_var):
self.template_path_var = template_path_var
def render(self, context):
try:
template_path = template.resolve(self.template_path_var, context)
template_path = template.resolve_variable(self.template_path_var, context)
print "IncludeNode rendering %s" % template_path
t = template_loader.get_template(template_path)
return t.render(context)
except:
except Exception, e:
print e
return '' # Fail silently for invalid included templates.

View File

@ -1035,9 +1035,10 @@ def method_set_related_many_to_many(rel_opts, rel_field, self, id_list):
m2m_table = rel_field.get_m2m_db_table(rel_opts)
this_id = getattr(self, self._meta.pk.column)
cursor = db.db.cursor()
cursor.execute("DELETE FROM %s WHERE %s_id = %%s" % (m2m_table, rel.object_name.lower()), [this_id])
sql = "INSERT INTO %s (%s_id, %s_id) VALUES (%%s, %%s)" % (m2m_table, rel.object_name.lower(), rel_opts.object_name.lower())
cursor.executemany(sql, [(this_id, i) for i in id_list])
delete_stmt = "DELETE FROM %s WHERE %s_id = %%s" % (m2m_table, rel.object_name.lower())
cursor.execute(delete_stmt, [this_id])
insert_stmt = "INSERT INTO %s (%s, %s) VALUES (%%s, %%s)" % (m2m_table, rel.pk.column, rel_opts.pk.column)
cursor.executemany(insert_stmt, [(this_id, i) for i in id_list])
db.db.commit()
# ORDERING METHODS #########################
@ -1488,7 +1489,7 @@ def get_manipulator(opts, klass, extra_methods, add=False, change=False):
setattr(man, k, v)
return man
def manipulator_init(opts, add, change, self, obj_key=None):
def manipulator_init(opts, add, change, self, obj_key=None, follow=None):
if change:
assert obj_key is not None, "ChangeManipulator.__init__() must be passed obj_key parameter."
self.obj_key = obj_key

View File

@ -8,6 +8,12 @@ from django.utils.functional import curry
from django.views.admin.main import AdminBoundField
import re
word_re = re.compile('[A-Z][a-z]+')
def class_name_to_underscored(name):
return '_'.join([ s.lower() for s in word_re.findall(name)[:-1] ])
class IncludeAdminScriptNode(template.Node):
def __init__(self, var):
self.var = var
@ -43,23 +49,6 @@ class SubmitRowNode(template.Node):
}, context);
context.pop()
return output;
# t = ['<div class="submit-row">']
# if not is_popup:
# if has_delete_permission and (change or show_delete):
# t.append('<p class="float-left"><a href="delete/" class="deletelink">Delete</a></p>')
# if change and save_as:
# t.append('<input type="submit" value="Save as new" name="_saveasnew" %s/>' % onclick_attrib)
# if (not save_as or add):
# t.append('<input type="submit" value="Save and add another" name="_addanother" %s/>' % onclick_attrib)
# t.append('<input type="submit" value="Save and continue editing" name="_continue" %s/>' % onclick_attrib )
# t.append('<input type="submit" value="Save" class="default" %s/>' % onclick_attrib)
# t.append('</div>\n')
# return ''.join(t)
class AdminFieldBoundNode(template.Node):
def __init__(self, argument):
@ -103,19 +92,32 @@ class FieldWidgetNode(template.Node):
self.bound_field_var = bound_field_var
def render(self, context):
bound_field = template.resolve_variable(self.bound_field_var, context)
add = context['add']
change = context['change']
context.push()
context['bound_field'] = bound_field
t = template_loader.get_template("admin_field_widget")
output = t.render(context)
context.pop()
return output
klass = bound_field.field.__class__
t = None
while klass:
try:
field_class_name = klass.__name__
template_name = "widget/%s" % \
class_name_to_underscored(field_class_name)
t = template_loader.get_template(template_name)
break
except template.TemplateDoesNotExist:
klass = (len(klass.__bases__) > 0) and klass.__bases__[0] or None
if t == None:
t = template_loader.get_template("widget/default")
output = t.render(context)
context.pop()
return output
class FieldWrapper(object):
def __init__(self, field ):
@ -259,9 +261,9 @@ one_arg_tag_nodes = [
FilterInterfaceScriptMaybeNode,
]
word = re.compile('[A-Z][a-z]+')
def register_one_arg_tag(node):
tag_name = '_'.join([ s.lower() for s in word.findall(node.__name__)[:-1] ])
tag_name = class_name_to_underscored(node.__name__)
parse_func = curry(do_one_arg_tag, node)
template.register_tag(tag_name, parse_func)

90
docs/outputting_pdf.txt Normal file
View File

@ -0,0 +1,90 @@
===========================
Outputting PDFs with Django
===========================
This document explains how to output PDF files dynamically using Django views.
This is made possible by the excellent, open-source ReportLab_ Python PDF
library.
The advantage of generating PDF files dynamically is that you can create
customzed PDFs for different purposes -- say, for different users or different
pieces of content.
For example, Django was used at kusports.com to generate customized,
printer-friendly NCAA tournament brackets, as PDF files, for people
participating in a March Madness contest.
.. _ReportLab: http://www.reportlab.org/rl_toolkit.html
Install ReportLab
=================
Download and install the ReportLab library from http://www.reportlab.org/downloads.html.
The `user guide`_ (not coincidentally, a PDF file) explains how to install it.
Test your installation by importing it in the Python interactive interpreter::
>>> import reportlab
If that command doesn't raise any errors, the installation worked.
.. _user guide: http://www.reportlab.org/rsrc/userguide.pdf
Write your view
===============
The key to generating PDFs dynamically with Django is that the ReportLab API
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`_.
.. _Request and response objects: http://www.djangoproject.com/documentation/request_response/
Here's a "Hello World" example::
from reportlab.pdfgen import canvas
from django.utils.httpwrappers import HttpResponse
def some_view(request):
# Create the HttpResponse object with the appropriate PDF headers.
response = HttpResponse(mimetype='application/pdf')
response['Content-Disposition'] = 'attachment; filename=somefilename.pdf'
# Create the PDF object, using the response object as its "file."
p = canvas.Canvas(response)
# Draw things on the PDF. Here's where the PDF generation happens.
# See the ReportLab documentation for the full list of functionality.
p.drawString(100, 100, "Hello world.")
# Close the PDF object cleanly, and we're done.
p.showPage()
p.save()
return response
The code and comments should be self-explanatory, but a few things deserve a
mention:
* The response gets a special mimetype, ``application/pdf``. This tells
browsers that the document is a PDF 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 PDF 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 ReportLab API is easy: Just pass ``response`` as the
first argument to ``canvas.Canvas``. The ``Canvas`` class expects a
file-like object, and ``HttpResponse`` objects fit the bill.
* Note that all subsequent PDF-generation methods are called on the PDF
object (in this case, ``p``) -- not on ``response``.
* Finally, it's important to call ``showPage()`` and ``save()`` on the PDF
file.