django-extra-views-0.2.4/0000755000076500000240000000000011726005144017034 5ustar andrewingramstaff00000000000000django-extra-views-0.2.4/django_extra_views.egg-info/0000755000076500000240000000000011726005144024410 5ustar andrewingramstaff00000000000000django-extra-views-0.2.4/django_extra_views.egg-info/dependency_links.txt0000644000076500000240000000000111726005144030456 0ustar andrewingramstaff00000000000000 django-extra-views-0.2.4/django_extra_views.egg-info/PKG-INFO0000644000076500000240000000720411726005144025510 0ustar andrewingramstaff00000000000000Metadata-Version: 1.0 Name: django-extra-views Version: 0.2.4 Summary: Extra class-based views for Django Home-page: https://github.com/AndrewIngram/django-extra-views Author: Andrew Ingram Author-email: andy@andrewingram.net License: MIT Description: django-extra-views - The missing class-based generic views for Django ===================================================================== Django's class-based generic views are great, they let you accomplish a large number of web application design patterns in relatively few lines of code. They do have their limits though, and that's what this library of views aims to overcome. Installation ------------ Installing from pypi (using pip). :: pip install django-extra-views Installing from github. :: pip install -e git://github.com/AndrewIngram/django-extra-views.git#egg=django-extra-views Features so far ------------------ - FormSet and ModelFormSet views - The formset equivalents of FormView and ModelFormView. - InlineFormSetView - Lets you edit formsets related to a model (uses inlineformset_factory) - CreateWithInlinesView and UpdateWithInlinesView - Lets you edit a model and its relations - GenericInlineFormSetView, the equivalent of InlineFormSetView but for GenericForeignKeys - Support for generic inlines in CreateWithInlinesView and UpdateWithInlinesView Still to do ----------- I'd like to add support for pagination in ModelFormSetView and its derivatives, the goal being to be able to mimic the change_list view in Django's admin. Currently this is proving difficult because of how Django's MultipleObjectMixin handles pagination. Examples -------- Defining a FormSetView. :: from extra_views import FormSetView class AddressFormSet(FormSetView): form_class = AddressForm template_name = 'address_formset.html' Defining a ModelFormSetView. :: from extra_views import ModelFormSetView: class ItemFormSetView(ModelFormSetView): model = Item template_name = 'item_formset.html' Defining a CreateWithInlinesView and an UpdateWithInlinesView. :: from extra_views import CreateWithInlinesView, UpdateWithInlinesView, InlineFormSet from extra_views.generic import GenericInlineFormSet class ItemInline(InlineFormSet): model = Item class TagInline(GenericInlineFormSet): model = Tag class CreateOrderView(CreateWithInlinesView): model = Order inlines = [ItemInline, TagInline] class UpdateOrderView(UpdateWithInlinesView): model = Order inlines = [ItemInline, TagInline] # Example URLs. urlpatterns = patterns('', url(r'^orders/new/$', CreateOrderView.as_view()), url(r'^orders/(?P\d+)/$', UpdateOrderView.as_view()), ) More descriptive examples to come. Platform: UNKNOWN Classifier: Development Status :: 3 - Alpha Classifier: Environment :: Web Environment Classifier: Framework :: Django Classifier: Intended Audience :: Developers Classifier: Programming Language :: Python django-extra-views-0.2.4/django_extra_views.egg-info/SOURCES.txt0000644000076500000240000000057411726005144026302 0ustar andrewingramstaff00000000000000LICENSE MANIFEST.in README.rst setup.py ./extra_views/__init__.py ./extra_views/advanced.py ./extra_views/dates.py ./extra_views/formsets.py ./extra_views/generic.py ./extra_views/models.py ./extra_views/multi.py django_extra_views.egg-info/PKG-INFO django_extra_views.egg-info/SOURCES.txt django_extra_views.egg-info/dependency_links.txt django_extra_views.egg-info/top_level.txtdjango-extra-views-0.2.4/django_extra_views.egg-info/top_level.txt0000644000076500000240000000001411726005144027135 0ustar andrewingramstaff00000000000000extra_views django-extra-views-0.2.4/extra_views/0000755000076500000240000000000011726005144021374 5ustar andrewingramstaff00000000000000django-extra-views-0.2.4/extra_views/__init__.py0000644000076500000240000000034511726004221023502 0ustar andrewingramstaff00000000000000from extra_views.formsets import FormSetView, ModelFormSetView, InlineFormSetView from extra_views.advanced import CreateWithInlinesView, UpdateWithInlinesView, InlineFormSet from extra_views.dates import CalendarMonthArchiveViewdjango-extra-views-0.2.4/extra_views/advanced.py0000644000076500000240000000626511726004221023517 0ustar andrewingramstaff00000000000000from django.views.generic.edit import FormView, ModelFormMixin from django.views.generic.detail import SingleObjectTemplateResponseMixin from extra_views.formsets import BaseInlineFormSetMixin from django.http import HttpResponseRedirect from django.forms.formsets import all_valid class InlineFormSet(BaseInlineFormSetMixin): def __init__(self, parent_model, request, instance): self.inline_model = self.model self.model = parent_model self.request = request self.object = instance class ModelFormWithInlinesMixin(ModelFormMixin): def forms_valid(self, form, inlines): self.object = form.save() form.save_m2m() for formset in inlines: formset.save() return HttpResponseRedirect(self.get_success_url()) def forms_invalid(self, form, inlines): return self.render_to_response(self.get_context_data(form=form, inlines=inlines)) def construct_inlines(self): inline_formsets = [] for inline_class in self.inlines: inline_instance = inline_class(self.model, self.request, self.object) inline_formset = inline_instance.construct_formset() inline_formsets.append(inline_formset) return inline_formsets class ProcessFormWithInlinesView(FormView): def get(self, request, *args, **kwargs): form_class = self.get_form_class() form = self.get_form(form_class) inlines = self.construct_inlines() return self.render_to_response(self.get_context_data(form=form, inlines=inlines)) def post(self, request, *args, **kwargs): form_class = self.get_form_class() form = self.get_form(form_class) if form.is_valid(): self.object = form.save(commit=False) form_validated = True else: form_validated = False inlines = self.construct_inlines() if all_valid(inlines) and form_validated: return self.forms_valid(form, inlines) return self.forms_invalid(form, inlines) def put(self, *args, **kwargs): return self.post(*args, **kwargs) class BaseCreateWithInlinesView(ModelFormWithInlinesMixin, ProcessFormWithInlinesView): def get(self, request, *args, **kwargs): self.object = None return super(BaseCreateWithInlinesView, self).get(request, *args, **kwargs) def post(self, request, *args, **kwargs): self.object = None return super(BaseCreateWithInlinesView, self).post(request, *args, **kwargs) class CreateWithInlinesView(SingleObjectTemplateResponseMixin, BaseCreateWithInlinesView): template_name_suffix = '_form' class BaseUpdateWithInlinesView(ModelFormWithInlinesMixin, ProcessFormWithInlinesView): def get(self, request, *args, **kwargs): self.object = self.get_object() return super(BaseUpdateWithInlinesView, self).get(request, *args, **kwargs) def post(self, request, *args, **kwargs): self.object = self.get_object() return super(BaseUpdateWithInlinesView, self).post(request, *args, **kwargs) class UpdateWithInlinesView(SingleObjectTemplateResponseMixin, BaseUpdateWithInlinesView): template_name_suffix = '_form' django-extra-views-0.2.4/extra_views/dates.py0000644000076500000240000000403011726004221023036 0ustar andrewingramstaff00000000000000from django.views.generic.dates import BaseMonthArchiveView from django.views.generic.list import MultipleObjectTemplateResponseMixin from django.core.exceptions import ImproperlyConfigured from calendar import Calendar from collections import defaultdict import datetime class BaseCalendarMonthArchiveView(BaseMonthArchiveView): first_of_week = 0 # 0 = Monday, 6 = Sunday paginate_by = None def get_paginate_by(self, queryset): if self.paginate_by is not None: raise ImproperlyConfigured(u"'%s' cannot be paginated, it is a calendar view" % self.__class__.__name__) return None def get_first_of_week(self): return self.first_of_week def get_context_data(self, **kwargs): data = super(BaseCalendarMonthArchiveView, self).get_context_data(**kwargs) date = data['date_list'][0] cal = Calendar(self.get_first_of_week()) month_calendar = [] now = datetime.datetime.utcnow() date_lists = defaultdict(list) for obj in data['object_list']: obj_date = getattr(obj, self.get_date_field()) try: obj_date = obj_date.date() except AttributeError: # It's a date rather than datetime, so we use it as is pass date_lists[obj_date].append(obj) for week in cal.monthdatescalendar(date.year, date.month): week_calendar = [] for day in week: week_calendar.append({ 'day': day, 'object_list': date_lists[day], 'today': day == now.date(), 'is_current_month': day.month == date.month, }) month_calendar.append(week_calendar) data['calendar'] = month_calendar return data class CalendarMonthArchiveView(MultipleObjectTemplateResponseMixin, BaseCalendarMonthArchiveView): template_name_suffix = '_calendar_month' django-extra-views-0.2.4/extra_views/formsets.py0000644000076500000240000001647411726004222023620 0ustar andrewingramstaff00000000000000from django.views.generic.base import TemplateResponseMixin, View from django.http import HttpResponseRedirect from django.forms.formsets import formset_factory from django.forms.models import modelformset_factory, inlineformset_factory from django.views.generic.detail import SingleObjectMixin, SingleObjectTemplateResponseMixin from django.views.generic.list import MultipleObjectMixin, MultipleObjectTemplateResponseMixin from django.forms.models import BaseInlineFormSet class BaseFormSetMixin(object): """ Base class for constructing a FormSet within a view """ initial = [] form_class = None formset_class = None success_url = None extra = 2 max_num = None can_order = False can_delete = False def construct_formset(self): return self.get_formset()(initial=self.get_initial(), **self.get_formset_kwargs()) def get_initial(self): return self.initial def get_formset_class(self): return self.formset_class def get_form_class(self): return self.form_class def get_formset(self): return formset_factory(self.get_form_class(), **self.get_factory_kwargs()) def get_formset_kwargs(self): kwargs = {} if self.request.method in ('POST', 'PUT'): kwargs.update({ 'data': self.request.POST, 'files': self.request.FILES, }) return kwargs def get_factory_kwargs(self): kwargs = { 'extra': self.extra, 'max_num': self.max_num, 'can_order': self.can_order, 'can_delete': self.can_delete, } if self.get_formset_class(): kwargs['formset'] = self.get_formset_class() return kwargs class FormSetMixin(BaseFormSetMixin): def get_context_data(self, **kwargs): return kwargs def get_success_url(self): if self.success_url: url = self.success_url else: # Default to returning to the same page url = self.request.get_full_path() return url def formset_valid(self, formset): return HttpResponseRedirect(self.get_success_url()) def formset_invalid(self, formset): return self.render_to_response(self.get_context_data(formset=formset)) class ModelFormSetMixin(FormSetMixin, MultipleObjectMixin): exclude = None fields = None formfield_callback = None def get_context_data(self, **kwargs): context = kwargs if self.object_list: context['object_list'] = self.object_list context_object_name = self.get_context_object_name(self.get_queryset()) if context_object_name: context[context_object_name] = self.object_list return context def construct_formset(self): return self.get_formset()(queryset=self.get_queryset(), **self.get_formset_kwargs()) def get_factory_kwargs(self): kwargs = super(ModelFormSetMixin, self).get_factory_kwargs() kwargs.update({ 'exclude': self.exclude, 'fields': self.fields, 'formfield_callback': self.formfield_callback, }) if self.get_form_class(): kwargs['form'] = self.get_form_class() if self.get_formset_class(): kwargs['formset'] = self.get_formset_class() return kwargs def get_formset(self): return modelformset_factory(self.model, **self.get_factory_kwargs()) def formset_valid(self, formset): self.object_list = formset.save() return super(ModelFormSetMixin, self).formset_valid(formset) class BaseInlineFormSetMixin(BaseFormSetMixin): model = None inline_model = None fk_name = None formset_class = BaseInlineFormSet exclude = None fields = None formfield_callback = None can_delete = True def get_context_data(self, **kwargs): context = kwargs if self.object: context['object'] = self.object context_object_name = self.get_context_object_name(self.object) if context_object_name: context[context_object_name] = self.object return context def construct_formset(self): return self.get_formset()(instance=self.object, **self.get_formset_kwargs()) def get_factory_kwargs(self): kwargs = super(BaseInlineFormSetMixin, self).get_factory_kwargs() kwargs.update({ 'exclude': self.exclude, 'fields': self.fields, 'formfield_callback': self.formfield_callback, 'fk_name': self.fk_name, }) if self.get_form_class(): kwargs['form'] = self.get_form_class() if self.get_formset_class(): kwargs['formset'] = self.get_formset_class() return kwargs def get_formset(self): return inlineformset_factory(self.model, self.inline_model, **self.get_factory_kwargs()) class InlineFormSetMixin(BaseInlineFormSetMixin, FormSetMixin, SingleObjectMixin): def formset_valid(self, formset): self.object_list = formset.save() return super(BaseInlineFormSetMixin, self).formset_valid(formset) class ProcessFormSetView(View): """ A mixin that processes a fomset on POST. """ def get(self, request, *args, **kwargs): formset = self.construct_formset() return self.render_to_response(self.get_context_data(formset=formset)) def post(self, request, *args, **kwargs): formset = self.construct_formset() if formset.is_valid(): return self.formset_valid(formset) else: return self.formset_invalid(formset) def put(self, *args, **kwargs): return self.post(*args, **kwargs) class BaseFormSetView(FormSetMixin, ProcessFormSetView): """ A base view for displaying a formset """ class FormSetView(TemplateResponseMixin, BaseFormSetView): """ A view for displaying a formset, and rendering a template response """ class BaseModelFormSetView(ModelFormSetMixin, ProcessFormSetView): """ A base view for displaying a modelformset """ def get(self, request, *args, **kwargs): self.object_list = self.get_queryset() return super(BaseModelFormSetView, self).get(request, *args, **kwargs) def post(self, request, *args, **kwargs): self.object_list = self.get_queryset() return super(BaseModelFormSetView, self).post(request, *args, **kwargs) class ModelFormSetView(MultipleObjectTemplateResponseMixin, BaseModelFormSetView): """ A view for displaying a modelformset, and rendering a template response """ class BaseInlineFormSetView(InlineFormSetMixin, ProcessFormSetView): """ A base view for displaying a modelformset for a queryset belonging to a parent model """ def get(self, request, *args, **kwargs): self.object = self.get_object() return super(BaseInlineFormSetView, self).get(request, *args, **kwargs) def post(self, request, *args, **kwargs): self.object = self.get_object() return super(BaseInlineFormSetView, self).post(request, *args, **kwargs) class InlineFormSetView(SingleObjectTemplateResponseMixin, BaseInlineFormSetView): """ A view for displaying a modelformset for a queryset belonging to a parent model """ django-extra-views-0.2.4/extra_views/generic.py0000644000076500000240000000252611714563277023404 0ustar andrewingramstaff00000000000000from django.contrib.contenttypes.generic import generic_inlineformset_factory, BaseGenericInlineFormSet from extra_views.formsets import BaseInlineFormSetMixin, InlineFormSetMixin, BaseInlineFormSetView, InlineFormSetView class BaseGenericInlineFormSetMixin(BaseInlineFormSetMixin): ct_field = "content_type" ct_fk_field = "object_id" formset_class = BaseGenericInlineFormSet def get_factory_kwargs(self): kwargs = super(BaseGenericInlineFormSetMixin, self).get_factory_kwargs() del kwargs['fk_name'] kwargs.update({ "ct_field": self.ct_field, "fk_field": self.ct_fk_field, }) return kwargs def get_formset(self): result = generic_inlineformset_factory(self.inline_model, **self.get_factory_kwargs()) return result class GenericInlineFormSet(BaseGenericInlineFormSetMixin): def __init__(self, parent_model, request, instance): self.inline_model = self.model self.model = parent_model self.request = request self.object = instance class GenericInlineFormSetMixin(BaseGenericInlineFormSetMixin, InlineFormSetMixin): pass class BaseGenericInlineFormSetView(GenericInlineFormSetMixin, BaseInlineFormSetView): pass class GenericInlineFormSetView(BaseGenericInlineFormSetView, InlineFormSetView): passdjango-extra-views-0.2.4/extra_views/models.py0000644000076500000240000000000011714563277023234 0ustar andrewingramstaff00000000000000django-extra-views-0.2.4/extra_views/multi.py0000644000076500000240000001501111714563277023113 0ustar andrewingramstaff00000000000000from django.views.generic.base import TemplateResponseMixin, View from django.core.exceptions import ImproperlyConfigured from django.http import HttpResponseRedirect, Http404 from django.forms.formsets import formset_factory from django.forms.models import modelformset_factory from django.forms import models as model_forms from django.forms import ValidationError class FormProvider(object): def __init__(self, form_class, context_suffix, init_args={}): self.form_class = form_class self.context_suffix = context_suffix self.init_args = init_args def get_context_suffix(self): return self.context_suffix def get_form(self, caller, prefix): kwargs = {} for k,v in self.init_args.iteritems(): method_name = v % prefix try: kwargs[k] = getattr(caller, method_name)() except AttributeError: msg = '%s must implement method "%s" ' % (caller.__class__.__name__, method_name) raise ImproperlyConfigured(msg) kwargs.update(caller.get_form_kwargs(prefix)) try: form = self.form_class(prefix=prefix, **kwargs) except ValidationError, e: # This is nasty. Basically a formset will throw a validation error on instantiation # if the management form is missing, but we expect it to be empty if it wasn't one # of the POSTed forms, so we have to catch the error and deal with it later. form = e form.prefix = prefix return form class MultiFormMixin(object): """ Handle multiple forms in a single view """ forms = {} initial = {} success_url = None groups = None @staticmethod def form(form): return FormProvider(form_class=form, context_suffix='form') @staticmethod def modelform(model, form=None, **kwargs): if not form: form = model_forms.modelform_factory(model, **kwargs) return FormProvider(form_class=form, context_suffix='form' , init_args={'instance': 'get_%s_instance'}) @staticmethod def formset(form, **kwargs): generated_formset = formset_factory(form, **kwargs) return FormProvider(form_class=generated_formset, context_suffix='formset') @staticmethod def modelformset(model, **kwargs): generated_formset = modelformset_factory(model, **kwargs) return FormProvider(form_class=generated_formset, context_suffix='formset', init_args={'queryset': 'get_%s_queryset'}) def get_initial(self,prefix): handler = 'get_initial_%s' % prefix if hasattr(self, handler): return getattr(self, handler)() return self.initial.get(prefix,{}) def get_form_definitions(self): return self.forms def get_groups(self): if not self.groups: return { 'all': self.forms } return self.groups def construct_forms(self): forms = {} definitions = self.get_form_definitions() for prefix, provider in definitions.iteritems(): context_name = '%s_%s' % (prefix, provider.get_context_suffix()) forms[context_name] = provider.get_form(self, prefix) return forms def get_form_kwargs(self,prefix): kwargs = {'initial': self.get_initial(prefix)} if self.request.method in ('POST', 'PUT'): kwargs.update({ 'data': self.request.POST, 'files': self.request.FILES, }) return kwargs def get_context_data(self, **kwargs): return kwargs def get_success_url(self): if self.success_url: url = self.success_url else: raise ImproperlyConfigured( "No URL to redirect to. Provide a success_url.") return url def forms_valid(self): return HttpResponseRedirect(self.get_success_url()) def forms_invalid(self, forms): return self.render_to_response(self.get_context_data(**forms)) class ProcessMultiFormView(View): """ The equivalent of Django's ProcessFormView but for MultiForms """ def get(self, request, *args, **kwargs): forms = self.construct_forms() return self.render_to_response(self.get_context_data(**forms)) def post(self, request, *args, **kwargs): forms = self.construct_forms() forms_dict = dict([(x.prefix, x) for x in forms.values()]) valid = True valid_forms = {} invalid_forms = {} posted_prefixes = [] # First we detect which prefixes were POSTed for prefix in self.get_form_definitions().keys(): for field in self.request.POST: if field.startswith(prefix): posted_prefixes.append(prefix) break # Now we iterated over the groups until we find one that matches the POSTed prefixes for label, prefixes in self.get_groups().iteritems(): if label == 'all' or list(prefixes) == posted_prefixes: # We've found the group, now check if all its forms are valid for prefix in prefixes: form = forms_dict[prefix] # FormSets force us to do this... if isinstance(form, ValidationError): raise form if form.is_valid(): valid_forms[prefix] = form else: valid = False invalid_forms[prefix] = form if valid: handler = 'valid_%s' % label if hasattr(self, handler): getattr(self, handler)(valid_forms) return self.forms_valid() else: handler = 'invalid_%s' % label if hasattr(self, handler): getattr(self, handler)(invalid_forms) return self.forms_invalid(forms) break # If we got here, it means we couldn't find a matching group for the POST data raise Http404() def put(self, request, *args, **kwargs): return self.post(request, *args, **kwargs) class BaseMultiFormView(MultiFormMixin, ProcessMultiFormView): pass class MultiFormView(TemplateResponseMixin, BaseMultiFormView): pass django-extra-views-0.2.4/LICENSE0000644000076500000240000000206111726004221020033 0ustar andrewingramstaff00000000000000The MIT License Copyright (c) 2012 Andrew Ingram Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.django-extra-views-0.2.4/MANIFEST.in0000644000076500000240000000004211726004221020561 0ustar andrewingramstaff00000000000000include LICENSE include README.rstdjango-extra-views-0.2.4/PKG-INFO0000644000076500000240000000720411726005144020134 0ustar andrewingramstaff00000000000000Metadata-Version: 1.0 Name: django-extra-views Version: 0.2.4 Summary: Extra class-based views for Django Home-page: https://github.com/AndrewIngram/django-extra-views Author: Andrew Ingram Author-email: andy@andrewingram.net License: MIT Description: django-extra-views - The missing class-based generic views for Django ===================================================================== Django's class-based generic views are great, they let you accomplish a large number of web application design patterns in relatively few lines of code. They do have their limits though, and that's what this library of views aims to overcome. Installation ------------ Installing from pypi (using pip). :: pip install django-extra-views Installing from github. :: pip install -e git://github.com/AndrewIngram/django-extra-views.git#egg=django-extra-views Features so far ------------------ - FormSet and ModelFormSet views - The formset equivalents of FormView and ModelFormView. - InlineFormSetView - Lets you edit formsets related to a model (uses inlineformset_factory) - CreateWithInlinesView and UpdateWithInlinesView - Lets you edit a model and its relations - GenericInlineFormSetView, the equivalent of InlineFormSetView but for GenericForeignKeys - Support for generic inlines in CreateWithInlinesView and UpdateWithInlinesView Still to do ----------- I'd like to add support for pagination in ModelFormSetView and its derivatives, the goal being to be able to mimic the change_list view in Django's admin. Currently this is proving difficult because of how Django's MultipleObjectMixin handles pagination. Examples -------- Defining a FormSetView. :: from extra_views import FormSetView class AddressFormSet(FormSetView): form_class = AddressForm template_name = 'address_formset.html' Defining a ModelFormSetView. :: from extra_views import ModelFormSetView: class ItemFormSetView(ModelFormSetView): model = Item template_name = 'item_formset.html' Defining a CreateWithInlinesView and an UpdateWithInlinesView. :: from extra_views import CreateWithInlinesView, UpdateWithInlinesView, InlineFormSet from extra_views.generic import GenericInlineFormSet class ItemInline(InlineFormSet): model = Item class TagInline(GenericInlineFormSet): model = Tag class CreateOrderView(CreateWithInlinesView): model = Order inlines = [ItemInline, TagInline] class UpdateOrderView(UpdateWithInlinesView): model = Order inlines = [ItemInline, TagInline] # Example URLs. urlpatterns = patterns('', url(r'^orders/new/$', CreateOrderView.as_view()), url(r'^orders/(?P\d+)/$', UpdateOrderView.as_view()), ) More descriptive examples to come. Platform: UNKNOWN Classifier: Development Status :: 3 - Alpha Classifier: Environment :: Web Environment Classifier: Framework :: Django Classifier: Intended Audience :: Developers Classifier: Programming Language :: Python django-extra-views-0.2.4/README.rst0000644000076500000240000000500711726004221020520 0ustar andrewingramstaff00000000000000django-extra-views - The missing class-based generic views for Django ===================================================================== Django's class-based generic views are great, they let you accomplish a large number of web application design patterns in relatively few lines of code. They do have their limits though, and that's what this library of views aims to overcome. Installation ------------ Installing from pypi (using pip). :: pip install django-extra-views Installing from github. :: pip install -e git://github.com/AndrewIngram/django-extra-views.git#egg=django-extra-views Features so far ------------------ - FormSet and ModelFormSet views - The formset equivalents of FormView and ModelFormView. - InlineFormSetView - Lets you edit formsets related to a model (uses inlineformset_factory) - CreateWithInlinesView and UpdateWithInlinesView - Lets you edit a model and its relations - GenericInlineFormSetView, the equivalent of InlineFormSetView but for GenericForeignKeys - Support for generic inlines in CreateWithInlinesView and UpdateWithInlinesView Still to do ----------- I'd like to add support for pagination in ModelFormSetView and its derivatives, the goal being to be able to mimic the change_list view in Django's admin. Currently this is proving difficult because of how Django's MultipleObjectMixin handles pagination. Examples -------- Defining a FormSetView. :: from extra_views import FormSetView class AddressFormSet(FormSetView): form_class = AddressForm template_name = 'address_formset.html' Defining a ModelFormSetView. :: from extra_views import ModelFormSetView: class ItemFormSetView(ModelFormSetView): model = Item template_name = 'item_formset.html' Defining a CreateWithInlinesView and an UpdateWithInlinesView. :: from extra_views import CreateWithInlinesView, UpdateWithInlinesView, InlineFormSet from extra_views.generic import GenericInlineFormSet class ItemInline(InlineFormSet): model = Item class TagInline(GenericInlineFormSet): model = Tag class CreateOrderView(CreateWithInlinesView): model = Order inlines = [ItemInline, TagInline] class UpdateOrderView(UpdateWithInlinesView): model = Order inlines = [ItemInline, TagInline] # Example URLs. urlpatterns = patterns('', url(r'^orders/new/$', CreateOrderView.as_view()), url(r'^orders/(?P\d+)/$', UpdateOrderView.as_view()), ) More descriptive examples to come. django-extra-views-0.2.4/setup.cfg0000644000076500000240000000007311726005144020655 0ustar andrewingramstaff00000000000000[egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 django-extra-views-0.2.4/setup.py0000755000076500000240000000116411726004335020554 0ustar andrewingramstaff00000000000000from setuptools import setup setup( name='django-extra-views', version='0.2.4', url='https://github.com/AndrewIngram/django-extra-views', description="Extra class-based views for Django", long_description=open('README.rst', 'r').read(), license="MIT", author="Andrew Ingram", author_email="andy@andrewingram.net", packages=['extra_views'], package_dir={'': '.'}, classifiers=[ 'Development Status :: 3 - Alpha', 'Environment :: Web Environment', 'Framework :: Django', 'Intended Audience :: Developers', 'Programming Language :: Python'] )