Skip to content

Commit

Permalink
Added support for multiple formsets on a single page; updated documen…
Browse files Browse the repository at this point in the history
…tation

Added two new examples: "using multiple formsets on a single page" and "using the admin datefield widget"
Tested with the latest version of jQuery (currently 1.3.2)


git-svn-id: https://django-dynamic-formset.googlecode.com/svn/trunk@6 9f2ace40-7153-11de-83e1-4fc93b4a6815
  • Loading branch information
stan.madueke committed Nov 30, 2009
1 parent 1f495fc commit 3fe1184
Show file tree
Hide file tree
Showing 18 changed files with 443 additions and 56 deletions.
8 changes: 4 additions & 4 deletions INSTALL.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ projects; the first is to do a Subversion checkout::
svn co http://django-dynamic-formset.googlecode.com/svn/trunk/ django-dynamic-formset

The second method is to download a packaged release. The latest
release is 1.0. You can download the source and documentation only,
release is 1.1. You can download the source and documentation only,
or include the demo project::

wget http://django-dynamic-formset.googlecode.com/files/jquery.formset-1.0.zip
unzip jquery.formset-1.0.zip -d jquery.formset-1.0
cd jquery.formset-1.0
wget http://django-dynamic-formset.googlecode.com/files/jquery.formset-1.1.zip
unzip jquery.formset-1.1.zip -d jquery.formset-1.1
cd jquery.formset-1.1

The plugin files are in the ``src/`` directory. If you downloaded
the archive with the demo project, you'll need to set it up first.
Expand Down
34 changes: 34 additions & 0 deletions demo/example/forms.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
from django import forms
from django.forms import fields, models, formsets, widgets
from django.contrib.admin.widgets import AdminDateWidget
from django.conf import settings
from example.models import Product, Order, OrderedItem

############################
## Inline Formset Example ##
############################

class OrderForm(models.ModelForm):
class Meta:
model = Order
Expand Down Expand Up @@ -32,6 +38,10 @@ def __init__(self, *args, **kwargs):
def get_ordereditem_formset(form, formset=models.BaseInlineFormSet, **kwargs):
return models.inlineformset_factory(Order, OrderedItem, form, formset, **kwargs)

################################
## Plain 'ole Formset example ##
################################

CONTACT_INFO_TYPES = (
('Phone', 'Phone'),
('Fax', 'Fax'),
Expand All @@ -47,3 +57,27 @@ class ContactInfoForm(forms.Form):
preferred = fields.BooleanField(required=False)

ContactFormset = formsets.formset_factory(ContactInfoForm)

###############################################
## Plain 'ole Formset with Javascript Widget ##
###############################################

class EventForm(forms.Form):
name = fields.CharField(max_length=150, label='display name')
start_date = fields.DateField(widget=AdminDateWidget)
end_date = fields.DateField(widget=AdminDateWidget)

def _get_media(self):
# The "core.js" file is required by the Admin Date widget, yet for
# some reason, isn't included in the widgets media definition.
# We override "_get_media" because core.js needs to appear BEFORE
# the widget's JS files, and the default order puts the form's
# media AFTER that of its fields.
media = widgets.Media(
js=('%sjs/core.js' % settings.ADMIN_MEDIA_PREFIX,)
)
media += super(EventForm, self)._get_media()
return media
media = property(_get_media)

EventFormset = formsets.formset_factory(EventForm, extra=2)
8 changes: 5 additions & 3 deletions demo/example/urls.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from django.conf.urls.defaults import *
from example.forms import AutoCompleteOrderedItemForm, OrderedItemForm
from example.forms import AutoCompleteOrderedItemForm, OrderedItemForm, ContactFormset, EventFormset

urlpatterns = patterns('example.views',
url(r'^stacked/$', 'formset', {'template': 'example/formset-stacked.html'}, name='example_stacked'),
url(r'^table/$', 'formset', {'template': 'example/formset-table.html'}, name='example_table'),
url(r'^stacked/$', 'formset', {'formset_class': ContactFormset, 'template': 'example/formset-stacked.html'}, name='example_stacked'),
url(r'^table/$', 'formset', {'formset_class': ContactFormset, 'template': 'example/formset-table.html'}, name='example_table'),
url(r'^admin-widget/$', 'formset', {'formset_class': EventFormset, 'template': 'example/formset-admin-widget.html'}, name='example_admin_widget'),
url(r'^multiple-formsets/$', 'multiple_formsets', {'template': 'example/formset-multiple-formsets.html'}, name='example_multiple_formsets'),
url(r'^inline-formset/$', 'inline_formset',
{'form_class': OrderedItemForm, 'template': 'example/inline-formset.html'}, name='example_inline_formset'),
url(r'^inline-formset-autocomplete/$', 'inline_formset',
Expand Down
23 changes: 17 additions & 6 deletions demo/example/views.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from django.http import HttpResponse
from django.shortcuts import render_to_response
from django.template.context import RequestContext
from example.forms import ContactFormset, Order, OrderForm, get_ordereditem_formset
from example.forms import ContactFormset, EventFormset, Order, OrderForm, get_ordereditem_formset
from example.models import Order, Product

def autocomplete_products(request):
Expand All @@ -10,18 +10,18 @@ def autocomplete_products(request):
output = u'\n'.join([u'%d|%s' % tuple(product) for product in products])
return HttpResponse(output, mimetype='text/plain')

def display_data(request, data):
return render_to_response('example/posted-data.html', {'data': data},
def display_data(request, data, **kwargs):
return render_to_response('example/posted-data.html', dict(data=data, **kwargs),
context_instance=RequestContext(request))

def formset(request, template):
def formset(request, formset_class, template):
if request.method == 'POST':
formset = ContactFormset(request.POST)
formset = formset_class(request.POST)
if formset.is_valid():
data = formset.cleaned_data
return display_data(request, data)
else:
formset = ContactFormset()
formset = formset_class()
return render_to_response(template, {'formset': formset},
context_instance=RequestContext(request))

Expand All @@ -38,3 +38,14 @@ def inline_formset(request, form_class, template):
formset = OrderedItemFormset()
return render_to_response(template, {'form': form, 'formset': formset},
context_instance=RequestContext(request))

def multiple_formsets(request, template):
if request.method == 'POST':
contact_formset, event_formset = ContactFormset(request.POST, prefix='contact_form'), EventFormset(request.POST, prefix='event_form')
if contact_formset.is_valid() and event_formset.is_valid():
data = [contact_formset.cleaned_data, event_formset.cleaned_data]
return display_data(request, data, multiple_formsets=True)
else:
contact_formset, event_formset = ContactFormset(prefix='contact_form'), EventFormset(prefix='event_form')
return render_to_response(template, {'contact_formset': contact_formset, 'event_formset': event_formset},
context_instance=RequestContext(request))
13 changes: 7 additions & 6 deletions demo/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@

# If you set this to False, Django will make some optimizations so as not
# to load the internationalization machinery.
USE_I18N = True
USE_I18N = False

# Absolute path to the directory that holds media.
# Example: "/home/media/media.lawrence.com/"
Expand Down Expand Up @@ -75,17 +75,18 @@
)

TEMPLATE_CONTEXT_PROCESSORS = (
'django.core.context_processors.auth',
'django.core.context_processors.media',
#'django.core.context_processors.i18n',
#'django.core.context_processors.request',
#'django.core.context_processors.debug',
'django.core.context_processors.auth',
'django.core.context_processors.media',
#'django.core.context_processors.i18n',
#'django.core.context_processors.request',
#'django.core.context_processors.debug',
)

INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
#'django.contrib.admin',
'example',
)
11 changes: 5 additions & 6 deletions demo/static/js/jquery.formset.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion demo/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>{% block title %}Velkomm{% endblock %} :: Django Dynamic Formset Examples</title>
<link href="{{ MEDIA_URL }}css/default.css" rel="stylesheet" type="text/css" media="screen" />
<script type="text/javascript" src="{{ MEDIA_URL }}js/jquery.js"></script>
<script type="text/javascript" src="{{ MEDIA_URL }}js/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="{{ MEDIA_URL }}js/jquery.formset.min.js"></script>
{% block extrahead %}{% endblock %}
</head>
Expand Down
90 changes: 90 additions & 0 deletions demo/templates/example/formset-admin-widget.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
{% extends "base.html" %}

{% block title %}Basic Formset with Admin Widget{% endblock %}

{% block extrahead %}
<script type="text/javascript">
// Define this so we don't have to bother with the admin jsi18n stuff:
function gettext(msgid) { return msgid; }
</script>
{{ formset.media }}
<script type="text/javascript">
$(function() {
$('.form-container').formset({
added: function(row) {
// Find the fields with the calendar widget
$(row).find('.vDateField').each(function(i) {
// Remove the cloned spam element: it links to an incorrect calendar
$(this).parent().find('span').remove();
// DateTimeShortcuts is defined in DateTimeShortcuts.js in the Django admin media
DateTimeShortcuts.addCalendar(this);
});
}
});
});
</script>
<!-- Here's an example of how you can style add/delete buttons with CSS -->
<style type="text/css">
.add-row {
padding-left:18px;
background:url({{ MEDIA_URL }}images/add.png) no-repeat left center;
}
.delete-row {
float:right;
display:block;
padding-left:18px;
background:url({{ MEDIA_URL }}images/delete.png) no-repeat left center;
}
th {
text-align:right;
font-weight:bold;
}
td span img {
vertical-align:middle;
border:0;
}
</style>
{% endblock %}

{% block content %}
<div>
<div class="entry">
<form method="post" action="">
{% for form in formset.forms %}
<table id="{{ form.prefix }}-row" class="form-container" border="0" cellpadding="0" cellspacing="5">
<tbody>
<tr>
<th scope="row">Name</th>
<td>{{ form.name }}</td>
</tr>
<tr>
<th scope="row">Start Date</th>
<td>{{ form.start_date }}</td>
</tr>
<tr>
<th scope="row">End Date</th>
<td>{{ form.end_date }}</td>
</tr>
</tbody>
</table>
{% endfor %}
<p>
{{ formset.management_form }}
<input type="submit" value="Submit" />
</p>
</form>
</div>
</div>
{% endblock %}

{% block sidebar %}
<p>
Here's another example that uses the "added" callback, based on <a href="http://elo80ka.wordpress.com/2009/10/10/jquery-plugin-django-dynamic-formset/#comment-18">a comment</a>
submitted by <a href="http://escolareadevelopment.blogspot.com/">lfborjas</a>.
</p>
<p>
I apologize for not styling the calendar popup properly -- didn't really have much time.
Sure, it'd have made the demo prettier, but I think you'll still get the idea, ugly calendar
or no.
</p>
{% endblock %}
Loading

0 comments on commit 3fe1184

Please sign in to comment.