From 68d4a58fa761fea43204c5eba5d320d8fd970aa5 Mon Sep 17 00:00:00 2001 From: Henrik Levkowetz Date: Sun, 6 May 2007 05:35:46 +0000 Subject: [PATCH] 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 --- ietf/ipr/feeds.py | 2 +- ietf/ipr/models.py | 2 +- ietf/ipr/views.py | 49 +++++++---------- ietf/templates/ipr/details.html | 25 ++++----- ietf/templates/ipr/formfield.html | 8 +++ ietf/templates/ipr/new.html | 12 +---- ietf/utils.py | 88 +++++++++++++++++++++++++++++++ 7 files changed, 130 insertions(+), 56 deletions(-) create mode 100644 ietf/templates/ipr/formfield.html diff --git a/ietf/ipr/feeds.py b/ietf/ipr/feeds.py index 3747bc64a..7f1eb303c 100644 --- a/ietf/ipr/feeds.py +++ b/ietf/ipr/feeds.py @@ -5,11 +5,11 @@ import datetime class LatestIprDisclosures(Feed): feed_type = Atom1Feed - feed_url = "/feeds/ipr/" title = "IPR Disclosures to the IETF" link = "/ipr/" description = "Updates on new IPR Disclosures made to the IETF." language = "en" + feed_url = "/feeds/ipr/" def items(self): return IprDetail.objects.order_by('-submitted_date')[:5] diff --git a/ietf/ipr/models.py b/ietf/ipr/models.py index 369fd57b8..454642e87 100644 --- a/ietf/ipr/models.py +++ b/ietf/ipr/models.py @@ -128,7 +128,7 @@ class IprContact(models.Model): address2 = models.CharField(blank=True, maxlength=255) telephone = models.CharField(maxlength=25) fax = models.CharField(blank=True, maxlength=25) - email = models.CharField(maxlength=255) + email = models.EmailField(maxlength=255) def __str__(self): return self.name class Meta: diff --git a/ietf/ipr/views.py b/ietf/ipr/views.py index 53d5eda12..55835fd89 100644 --- a/ietf/ipr/views.py +++ b/ietf/ipr/views.py @@ -2,6 +2,7 @@ import models from django.shortcuts import render_to_response as render import django.newforms as forms import ietf.utils +import syslog def default(request): """Default page, with links to sub-pages""" @@ -61,35 +62,27 @@ def update(request, ipr_id=None): return show(request, ipr_id) def new(request, type): - """Form to make a new IPR disclosure""" + """Make a new IPR disclosure""" 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 - # work with multiple classes with the same elements. - for prefix in ["ph", "ietf", "sub"]: - for field in ContactForm.base_fields: - IprForm.base_fields[prefix + "_" + field] = ContactForm.base_fields[field] +# CustomForm = mk_formatting_form(format="%(errors)s%(field)s%(help_text)s") + CustomForm = ietf.utils.makeFormattingForm(template="ipr/formfield.html") + BaseIprForm = forms.form_for_model(models.IprDetail, form=CustomForm, formfield_callback=detail_field_fixup) + ContactForm = forms.form_for_model(models.IprContact, form=CustomForm) - # Some extra fields which will get post-processing to generate the IprRfcs - # and IprDrafts entries which go into the database: - IprForm.base_fields["rfclist"] = forms.CharField(required=False) - IprForm.base_fields["draftlist"] = forms.CharField(required=False) - IprForm.base_fields["stdonly_license"] = forms.BooleanField(required=False) + # Some subclassing: + class IprForm(BaseIprForm): + holder_contact = None + rfclist = forms.CharField(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': form = IprForm(request.POST) @@ -99,9 +92,7 @@ def new(request, type): else: form = IprForm() - blocks = ietf.utils.split_form(form.as_table(), sections ) - - return render("ipr/new_%s.html" % type, {"ipr": form, "form": blocks}) + return render("ipr/new_%s.html" % type, {"ipr": form, "debug": ""}) def detail_field_fixup(field): if field.name == "licensing_option": diff --git a/ietf/templates/ipr/details.html b/ietf/templates/ipr/details.html index b5f9ddffe..9ea3da34d 100644 --- a/ietf/templates/ipr/details.html +++ b/ietf/templates/ipr/details.html @@ -6,10 +6,10 @@ .ipr { width: 101ex; } .even { } .odd { } - .even th { background: #aaa; color: #336; font-family: Arial, sans-serif; font-size: small; text-align: left; font-weight: bold; } - .odd th { background: #cca; color: #336; font-family: Arial, sans-serif; font-size: small; text-align: left; font-weight: bold; } - .even td { background: #eee; color: #000; font-family: Arial, sans-serif; font-size: small; text-align: left; vertical-align: top; } - .odd td { background: #eed; color: #000; font-family: Arial, sans-serif; font-size: small; text-align: left; vertical-align: top; } + .even td,th { background: #eee; color: #000; font-family: Arial, sans-serif; font-size: small; text-align: left; vertical-align: top; } + .odd td,th { background: #eed; 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 tr:first-child th { background: #cca; color: #336; font-family: Arial, sans-serif; font-size: small; text-align: left; font-weight: bold; } table.ipr { padding:2px; border-width:1px; @@ -19,7 +19,8 @@ .ipr th { border: 0px; margin: 0px; padding: 4px; } .ipr td { border: 0px; margin: 0px; padding: 4px; } 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; } input { width: 72ex; font-family: sans-serif; font-size: 11pt; font-weight: normal; } input[type="radio"] { width: auto; } @@ -27,6 +28,7 @@ input[type="submit"] { width: auto; } textarea { width: 72ex; height: 5em; font-family: sans-serif; font-size: 11pt; font-weight: normal; } .required { color: red; } + .errorlist { background: red; padding: 0 0 0 2px; border: 0px; margin: 0px; } {% block top_info %} @@ -147,7 +149,6 @@ {% block section3 %} - {% if not ipr.is_bound or not ipr.old_ipr_url %}
@@ -157,7 +158,7 @@ {% block section3_data %} - {% if ipr.unbond_form or ipr.ietf_contact.name %} + {% if not ipr.is_bound or ipr.ietf_contact.name %} @@ -172,9 +173,6 @@ {% endblock %}
Name: {{ ipr.ietf_contact.name }}
Title: {{ ipr.ietf_contact.title }}
Department: {{ ipr.ietf_contact.department }}
- {% else %} - - {% endif %} {% endblock %} @@ -203,8 +201,6 @@ {% endblock %} - {% if not ipr.is_bound or not ipr.old_ipr_url %} - {% block section5 %}
@@ -245,9 +241,9 @@ {% if ipr.discloser_identify %} - + {% else %} - + {% endif %} {% endblock %} {% else %} @@ -370,7 +366,6 @@ {% endblock %} - {% endif %} {{ debug }} {% block bot_info %} diff --git a/ietf/templates/ipr/formfield.html b/ietf/templates/ipr/formfield.html new file mode 100644 index 000000000..880868b3d --- /dev/null +++ b/ietf/templates/ipr/formfield.html @@ -0,0 +1,8 @@ + {% if errors %} + + {% endif %} + {{ field }}{{ help_text }} diff --git a/ietf/templates/ipr/new.html b/ietf/templates/ipr/new.html index 19fbc2ff8..14691cde6 100644 --- a/ietf/templates/ipr/new.html +++ b/ietf/templates/ipr/new.html @@ -1,4 +1,4 @@ -{% extends "ipr/details.html" %} + {% extends "ipr/details.html" %} {% block title %}IPR Disclosure Page{% endblock %} {% block top_info %} {% if not ipr %} @@ -53,17 +53,9 @@

{% endif %} - + {% 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 %}
diff --git a/ietf/utils.py b/ietf/utils.py index 05e34c4a7..9eb9c498e 100644 --- a/ietf/utils.py +++ b/ietf/utils.py @@ -176,3 +176,91 @@ def split_form(html, blocks): output[block] = "\n".join(output[block]) return output + +def mk_formatting_form(format="%(label)s
    %(errors)s
%(field)s%(help_text)s
", + labelfmt="%s:", fieldfmt="%s", errfmt="
  • %s
  • ", error_wrap="", 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
    {{ ipr.discloser_identify|escape|linebreaks }}
    {{ ipr.discloser_identify|escape|linebreaks }}
    No information submitted
    No information submitted