The fourth (and last?) take on a form from multiple models,

using pretty much the same template as for a non-form view.

This solution is less hackish than the previous one which
used the form.as_table() rendering of a form, and then split
the resulting html in chunks.

Instead, '''all''' the html has been moved out to a formfield
template, and a custom form class is generated which will render
the form elements using an indicated template.

 * Add form factory in utils.py (an old version which still has
   html in the code is there for history, but will be removed

 * Changes in ipr/views.py:new(), now subclassing one form with
   some class members being other form instances, matching the
   members used for the show() view

 * A fix in ipr/models, making an email field use models.EmailField

 * Reverting a number of changes in ipr/details.html which aren't
   needed any more, as well as in ipr/new.html; and adding
   ipr/formfield.html
 - Legacy-Id: 104
This commit is contained in:
Henrik Levkowetz 2007-05-06 05:35:46 +00:00
parent 80829985a0
commit 68d4a58fa7
7 changed files with 130 additions and 56 deletions

View file

@ -5,11 +5,11 @@ import datetime
class LatestIprDisclosures(Feed): class LatestIprDisclosures(Feed):
feed_type = Atom1Feed feed_type = Atom1Feed
feed_url = "/feeds/ipr/"
title = "IPR Disclosures to the IETF" title = "IPR Disclosures to the IETF"
link = "/ipr/" link = "/ipr/"
description = "Updates on new IPR Disclosures made to the IETF." description = "Updates on new IPR Disclosures made to the IETF."
language = "en" language = "en"
feed_url = "/feeds/ipr/"
def items(self): def items(self):
return IprDetail.objects.order_by('-submitted_date')[:5] return IprDetail.objects.order_by('-submitted_date')[:5]

View file

@ -128,7 +128,7 @@ class IprContact(models.Model):
address2 = models.CharField(blank=True, maxlength=255) address2 = models.CharField(blank=True, maxlength=255)
telephone = models.CharField(maxlength=25) telephone = models.CharField(maxlength=25)
fax = models.CharField(blank=True, maxlength=25) fax = models.CharField(blank=True, maxlength=25)
email = models.CharField(maxlength=255) email = models.EmailField(maxlength=255)
def __str__(self): def __str__(self):
return self.name return self.name
class Meta: class Meta:

View file

@ -2,6 +2,7 @@ import models
from django.shortcuts import render_to_response as render from django.shortcuts import render_to_response as render
import django.newforms as forms import django.newforms as forms
import ietf.utils import ietf.utils
import syslog
def default(request): def default(request):
"""Default page, with links to sub-pages""" """Default page, with links to sub-pages"""
@ -61,35 +62,27 @@ def update(request, ipr_id=None):
return show(request, ipr_id) return show(request, ipr_id)
def new(request, type): def new(request, type):
"""Form to make a new IPR disclosure""" """Make a new IPR disclosure"""
debug = "" debug = ""
sections = {
"section1": "p_h_legal_name ",
"section2": "ph_name ph_title ph_department ph_address1 ph_address2 ph_telephone ph_fax ph_email",
"section3": "ietf_name ietf_title ietf_department ietf_address1 ietf_address2 ietf_telephone ietf_fax ietf_email",
"section4": "rfclist draftlist other_designations",
"section5": "p_applications date_applied country selecttype p_notes discloser_identify",
"section6": "licensing_option stdonly_license comments lic_checkbox selectowned",
"section7": "sub_name sub_title sub_department sub_address1 sub_address2 sub_telephone sub_fax sub_email",
"section8": "other_notes",
"ignore" : "document_title rfc_number id_document_tag submitted_date status " +
"old_ipr_url additional_old_title1 additional_old_title2 " +
"additional_old_url1 additional_old_url2 update_notified_date",
}
IprForm = forms.form_for_model(models.IprDetail, formfield_callback=detail_field_fixup)
ContactForm = forms.form_for_model(models.IprContact)
# It would be nicer if we could use mixin subclassing, but that won't # CustomForm = mk_formatting_form(format="%(errors)s%(field)s%(help_text)s")
# work with multiple classes with the same elements. CustomForm = ietf.utils.makeFormattingForm(template="ipr/formfield.html")
for prefix in ["ph", "ietf", "sub"]: BaseIprForm = forms.form_for_model(models.IprDetail, form=CustomForm, formfield_callback=detail_field_fixup)
for field in ContactForm.base_fields: ContactForm = forms.form_for_model(models.IprContact, form=CustomForm)
IprForm.base_fields[prefix + "_" + field] = ContactForm.base_fields[field]
# Some extra fields which will get post-processing to generate the IprRfcs # Some subclassing:
# and IprDrafts entries which go into the database: class IprForm(BaseIprForm):
IprForm.base_fields["rfclist"] = forms.CharField(required=False) holder_contact = None
IprForm.base_fields["draftlist"] = forms.CharField(required=False) rfclist = forms.CharField(required=False)
IprForm.base_fields["stdonly_license"] = forms.BooleanField(required=False) draftlist = forms.CharField(required=False)
stdonly_license = forms.BooleanField(required=False)
def __init__(self, *args, **kw):
self.base_fields["holder_contact"] = ContactForm(prefix="ph", *args, **kw)
# syslog.syslog("IprForm.__init__: holder_contact: %s" % repr(self.base_fields["holder_contact"]))
self.base_fields["ietf_contact"] = ContactForm(prefix="ietf", *args, **kw)
self.base_fields["submitter"] = ContactForm(prefix="sub", *args, **kw)
BaseIprForm.__init__(self, *args, **kw)
if request.method == 'POST': if request.method == 'POST':
form = IprForm(request.POST) form = IprForm(request.POST)
@ -99,9 +92,7 @@ def new(request, type):
else: else:
form = IprForm() form = IprForm()
blocks = ietf.utils.split_form(form.as_table(), sections ) return render("ipr/new_%s.html" % type, {"ipr": form, "debug": ""})
return render("ipr/new_%s.html" % type, {"ipr": form, "form": blocks})
def detail_field_fixup(field): def detail_field_fixup(field):
if field.name == "licensing_option": if field.name == "licensing_option":

View file

@ -6,10 +6,10 @@
.ipr { width: 101ex; } .ipr { width: 101ex; }
.even { } .even { }
.odd { } .odd { }
.even th { background: #aaa; color: #336; font-family: Arial, sans-serif; font-size: small; text-align: left; font-weight: bold; } .even td,th { background: #eee; color: #000; font-family: Arial, sans-serif; font-size: small; text-align: left; vertical-align: top; }
.odd th { background: #cca; color: #336; font-family: Arial, sans-serif; font-size: small; text-align: left; font-weight: bold; } .odd td,th { background: #eed; color: #000; font-family: Arial, sans-serif; font-size: small; text-align: left; vertical-align: top; }
.even td { background: #eee; color: #000; font-family: Arial, sans-serif; font-size: small; text-align: left; vertical-align: top; } .even tr:first-child th { background: #aaa; color: #336; font-family: Arial, sans-serif; font-size: small; text-align: left; font-weight: bold; }
.odd td { background: #eed; color: #000; font-family: Arial, sans-serif; font-size: small; text-align: left; vertical-align: top; } .odd tr:first-child th { background: #cca; color: #336; font-family: Arial, sans-serif; font-size: small; text-align: left; font-weight: bold; }
table.ipr { table.ipr {
padding:2px; padding:2px;
border-width:1px; border-width:1px;
@ -19,7 +19,8 @@
.ipr th { border: 0px; margin: 0px; padding: 4px; } .ipr th { border: 0px; margin: 0px; padding: 4px; }
.ipr td { border: 0px; margin: 0px; padding: 4px; } .ipr td { border: 0px; margin: 0px; padding: 4px; }
td.fixwidth { width: 14ex; } td.fixwidth { width: 14ex; }
.ipr ul { margin-left: -6ex; list-style-type: none; } td.inset{ padding-left: 14ex; }
.ipr ul { padding-left: -2ex; list-style-type: none; }
h4.ipr { text-align: center; } h4.ipr { text-align: center; }
input { width: 72ex; font-family: sans-serif; font-size: 11pt; font-weight: normal; } input { width: 72ex; font-family: sans-serif; font-size: 11pt; font-weight: normal; }
input[type="radio"] { width: auto; } input[type="radio"] { width: auto; }
@ -27,6 +28,7 @@
input[type="submit"] { width: auto; } input[type="submit"] { width: auto; }
textarea { width: 72ex; height: 5em; font-family: sans-serif; font-size: 11pt; font-weight: normal; } textarea { width: 72ex; height: 5em; font-family: sans-serif; font-size: 11pt; font-weight: normal; }
.required { color: red; } .required { color: red; }
.errorlist { background: red; padding: 0 0 0 2px; border: 0px; margin: 0px; }
</style> </style>
{% block top_info %} {% block top_info %}
@ -147,7 +149,6 @@
{% block section3 %} {% block section3 %}
{% if not ipr.is_bound or not ipr.old_ipr_url %}
<blockquote class="{% cycle parity %}"> <blockquote class="{% cycle parity %}">
<table border="0" cellpadding="0" cellspacing="0" class="ipr person"> <table border="0" cellpadding="0" cellspacing="0" class="ipr person">
<tr> <tr>
@ -157,7 +158,7 @@
</th> </th>
</tr> </tr>
{% block section3_data %} {% block section3_data %}
{% if ipr.unbond_form or ipr.ietf_contact.name %} {% if not ipr.is_bound or ipr.ietf_contact.name %}
<tr><td class="fixwidth">Name:</td> <td><b>{{ ipr.ietf_contact.name }}</b></td></tr> <tr><td class="fixwidth">Name:</td> <td><b>{{ ipr.ietf_contact.name }}</b></td></tr>
<tr><td class="fixwidth">Title:</td> <td><b>{{ ipr.ietf_contact.title }}</b></td></tr> <tr><td class="fixwidth">Title:</td> <td><b>{{ ipr.ietf_contact.title }}</b></td></tr>
<tr><td class="fixwidth">Department:</td> <td><b>{{ ipr.ietf_contact.department }}</b></td></tr> <tr><td class="fixwidth">Department:</td> <td><b>{{ ipr.ietf_contact.department }}</b></td></tr>
@ -172,9 +173,6 @@
{% endblock %} {% endblock %}
</table> </table>
</blockquote> </blockquote>
{% else %}
<!-- Not showing section {% cycle section %} -->
{% endif %}
{% endblock %} {% endblock %}
@ -203,8 +201,6 @@
</blockquote> </blockquote>
{% endblock %} {% endblock %}
{% if not ipr.is_bound or not ipr.old_ipr_url %}
{% block section5 %} {% block section5 %}
<blockquote class="{% cycle parity %}"> <blockquote class="{% cycle parity %}">
<table border="0" cellpadding="0" cellspacing="0" class="ipr"> <table border="0" cellpadding="0" cellspacing="0" class="ipr">
@ -245,9 +241,9 @@
</td> </td>
</tr> </tr>
{% if ipr.discloser_identify %} {% if ipr.discloser_identify %}
<tr><td class="fixwidth"> </td><td><b>{{ ipr.discloser_identify|escape|linebreaks }}</b></td></tr> <tr><td colspan="2" class="inset"><b>{{ ipr.discloser_identify|escape|linebreaks }}</b></td></tr>
{% else %} {% else %}
<tr><td class="fixwidth"> </td><td><i>No information submitted</i></td></tr> <tr><td colspan="2" class="inset"></span><i>No information submitted</i></td></tr>
{% endif %} {% endif %}
{% endblock %} {% endblock %}
{% else %} {% else %}
@ -370,7 +366,6 @@
</blockquote> </blockquote>
{% endblock %} {% endblock %}
{% endif %}
{{ debug }} {{ debug }}
{% block bot_info %} {% block bot_info %}

View file

@ -0,0 +1,8 @@
{% if errors %}
<ul>
{% for error in errors %}
<li>{{ errorr }}</li>
{% endfor %}
</ul>
{% endif %}
{{ field }}{{ help_text }}

View file

@ -1,4 +1,4 @@
{% extends "ipr/details.html" %} {% extends "ipr/details.html" %}
{% block title %}IPR Disclosure Page{% endblock %} {% block title %}IPR Disclosure Page{% endblock %}
{% block top_info %} {% block top_info %}
{% if not ipr %} {% if not ipr %}
@ -53,17 +53,9 @@
</p> </p>
</blockquote> </blockquote>
{% endif %} {% endif %}
<form> <form method="post">
{% endblock %} {% endblock %}
{% block section1_data %}{{ form.section1 }}{% endblock %}
{% block section2_data %}{{ form.section2 }}{% endblock %}
{% block section3_data %}{{ form.section3 }}{% endblock %}
{% block section4_data %}{{ form.section4 }}{% endblock %}
{% block section5_data %}{{ form.section5 }}{% endblock %}
{% block section6_data %}{{ form.section6 }}{% endblock %}
{% block section7_data %}{{ form.section7 }}{% endblock %}
{% block section8_data %}{{ form.section8 }}{% endblock %}
{% block bot_info %} {% block bot_info %}
<center><input type="submit" name="submit" value="Submit"></center> <center><input type="submit" name="submit" value="Submit"></center>
</form> </form>

View file

@ -176,3 +176,91 @@ def split_form(html, blocks):
output[block] = "\n".join(output[block]) output[block] = "\n".join(output[block])
return output return output
def mk_formatting_form(format="<span>%(label)s</span><span><ul>%(errors)s</ul>%(field)s%(help_text)s</span>",
labelfmt="%s:", fieldfmt="%s", errfmt="<li>%s</li>", error_wrap="<ul>%s</ul>", helpfmt="%s"):
"""Create a form class which formats its fields using the provided format string(s).
The format string may use these format specifications:
%(label)s
%(errors)s
%(field)s
%(help_text)s
The individual sub-formats must contain "%s" if defined.
"""
class FormattingForm(forms.BaseForm):
_format = format
_labelfmt = labelfmt
_fieldfmt = fieldfmt
_errfmt = errfmt
_errwrap = error_wrap
_helpfmt = helpfmt
def __getitem__(self, name):
"Returns a BoundField with the given name."
# syslog.syslog("FormattingForm.__getitem__(%s)" % (name))
try:
field = self.fields[name]
except KeyError:
# syslog.syslog("Exception: FormattingForm.__getitem__: Key %r not found" % (name))
raise KeyError('Key %r not found in Form' % name)
if not isinstance(field, forms.fields.Field):
return field
try:
bf = forms.forms.BoundField(self, field, name)
except Exception, e:
# syslog.syslog("Exception: FormattingForm.__getitem__: %s" % (e))
raise Exception(e)
try:
error_txt = "".join([self._errfmt % escape(error) for error in bf.errors])
error_txt = error_txt and self._errwrap % error_txt
label_txt = bf.label and self._labelfmt % bf.label_tag(escape(bf.label)) or ''
field_txt = self._fieldfmt % unicode(bf)
help_txt = field.help_text and self._helpfmt % field.help_text or u''
except Exception, e:
# syslog.syslog("Exception: FormattingForm.__getitem__: %s" % (e))
raise Exception(e)
return self._format % {"label":label_txt, "errors":error_txt, "field":field_txt, "help_text":help_txt}
def add_prefix(self, field_name):
return self.prefix and ('%s_%s' % (self.prefix, field_name)) or field_name
# syslog.syslog("Created new FormattingForm class: %s" % FormattingForm)
return FormattingForm
def makeFormattingForm(template=None):
"""Create a form class which formats its fields using the provided template
The template is provided with a dictionary containing the following keys, value
pairs:
"label": field label, if any,
"errors": list of errors, if any,
"field": widget rendering for an unbound form / field value for a bound form,
"help_text": field help text, if any
"""
from django.template import loader
import django.newforms as forms
class FormattingForm(forms.BaseForm):
_template = template
def __getitem__(self, name):
"Returns a BoundField with the given name."
try:
field = self.fields[name]
except KeyError:
raise KeyError('Key %r not found in Form' % name)
if not isinstance(field, forms.fields.Field):
return field
bf = forms.forms.BoundField(self, field, name)
return loader.render_to_string(self._template, { "errors": bf.errors, "label": bf.label, "field": unicode(bf), "help_text": field.help_text })
return FormattingForm