From d7d4d16a3aaf6d572e86c78b45d93b8bb065d23d Mon Sep 17 00:00:00 2001 From: Stephen Burrows Date: Tue, 12 Oct 2010 12:30:34 -0400 Subject: [PATCH] Added AttributeForm to elegantly handle all the fields that should be displayed in the admin related to the instance's value. Tweaked the tabular_collapse template (which was only used for attributes) to display the extra fields. Added the "value_formfield" method to Attribute Value models to allow for the possible future addition of value types. --- admin/base.py | 17 +++------- forms.py | 31 ++++++++++++++++++- models/base.py | 13 +++++++- ...r_collapse.html => tabular_attribute.html} | 4 +++ 4 files changed, 51 insertions(+), 14 deletions(-) rename templates/admin/philo/edit_inline/{tabular_collapse.html => tabular_attribute.html} (97%) diff --git a/admin/base.py b/admin/base.py index 3b2deba..d9249e5 100644 --- a/admin/base.py +++ b/admin/base.py @@ -1,6 +1,7 @@ from django.contrib import admin from django.contrib.contenttypes import generic from philo.models import Tag, Attribute +from philo.forms import AttributeForm COLLAPSE_CLASSES = ('collapse', 'collapse-closed', 'closed',) @@ -11,23 +12,15 @@ class AttributeInline(generic.GenericTabularInline): ct_fk_field = 'entity_object_id' model = Attribute extra = 1 - template = 'admin/philo/edit_inline/tabular_collapse.html' + template = 'admin/philo/edit_inline/tabular_attribute.html' allow_add = True classes = COLLAPSE_CLASSES - - -#class RelationshipInline(generic.GenericTabularInline): -# ct_field = 'entity_content_type' -# ct_fk_field = 'entity_object_id' -# model = Relationship -# extra = 1 -# template = 'admin/philo/edit_inline/tabular_collapse.html' -# allow_add = True -# classes = COLLAPSE_CLASSES + form = AttributeForm + exclude = ['value_object_id'] class EntityAdmin(admin.ModelAdmin): - inlines = [AttributeInline] #, RelationshipInline] + inlines = [AttributeInline] save_on_top = True diff --git a/forms.py b/forms.py index 0e034df..c864f31 100644 --- a/forms.py +++ b/forms.py @@ -7,7 +7,7 @@ from django.forms.formsets import TOTAL_FORM_COUNT from django.template import loader, loader_tags, TemplateDoesNotExist, Context, Template as DjangoTemplate from django.utils.datastructures import SortedDict from philo.admin.widgets import ModelLookupWidget -from philo.models import Entity, Template, Contentlet, ContentReference +from philo.models import Entity, Template, Contentlet, ContentReference, Attribute from philo.utils import fattr @@ -95,6 +95,35 @@ class EntityForm(EntityFormBase): # Would inherit from ModelForm directly if it return instance +class AttributeForm(ModelForm): + def __init__(self, *args, **kwargs): + super(AttributeForm, self).__init__(*args, **kwargs) + if self.instance.value is not None: + value_field = self.instance.value.value_formfield() + if value_field: + self.fields['value'] = value_field + if hasattr(self.instance.value, 'content_type'): + self.fields['content_type'] = self.instance.value._meta.get_field('content_type').formfield(initial=getattr(self.instance.value.content_type, 'pk', None)) + + def save(self, *args, **kwargs): + instance = super(AttributeForm, self).save(*args, **kwargs) + + if self.cleaned_data['value_content_type'] != self.instance.value_content_type: + if self.instance.value is not None: + self.instance.value.delete() + del(self.cleaned_data['value']) + elif 'content_type' in self.cleaned_data and self.cleaned_data['content_type'] != self.instance.value.content_type: + self.instance.value.content_type = self.cleaned_data['content_type'] + self.instance.value.save() + elif 'value' in self.cleaned_data: + self.instance.set_value(self.cleaned_data['value']) + + return instance + + class Meta: + model = Attribute + + class ContainerForm(ModelForm): def __init__(self, *args, **kwargs): super(ContainerForm, self).__init__(*args, **kwargs) diff --git a/models/base.py b/models/base.py index 145c1ee..cd25357 100644 --- a/models/base.py +++ b/models/base.py @@ -1,3 +1,4 @@ +from django import forms from django.db import models from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes import generic @@ -50,6 +51,10 @@ class JSONValue(models.Model): def __unicode__(self): return self.value_json + def value_formfield(self, *args, **kwargs): + kwargs['initial'] = self.value_json + return self._meta.get_field('value').formfield(*args, **kwargs) + class Meta: app_label = 'philo' @@ -62,6 +67,12 @@ class ForeignKeyValue(models.Model): def __unicode__(self): return unicode(self.value) + def value_formfield(self, form_class=forms.ModelChoiceField, **kwargs): + if self.content_type is None: + return None + kwargs.update({'initial': self.object_id, 'required': False}) + return form_class(self.content_type.model_class()._default_manager.all(), **kwargs) + class Meta: app_label = 'philo' @@ -108,7 +119,7 @@ class Attribute(models.Model): def get_value_class(self, value): if isinstance(value, models.query.QuerySet): return ManyToManyValue - elif isinstance(value, models.Model): + elif isinstance(value, models.Model) or (value is None and self.value_content_type.model_class() is ForeignKeyValue): return ForeignKeyValue else: return JSONValue diff --git a/templates/admin/philo/edit_inline/tabular_collapse.html b/templates/admin/philo/edit_inline/tabular_attribute.html similarity index 97% rename from templates/admin/philo/edit_inline/tabular_collapse.html rename to templates/admin/philo/edit_inline/tabular_attribute.html index 6aecaf5..defdffb 100644 --- a/templates/admin/philo/edit_inline/tabular_collapse.html +++ b/templates/admin/philo/edit_inline/tabular_attribute.html @@ -12,6 +12,8 @@ {{ field.label|capfirst }} {% endif %} {% endfor %} + Content Type + Value {% if inline_admin_formset.formset.can_delete %}{% trans "Delete?" %}{% endif %} @@ -53,6 +55,8 @@ {% endfor %} {% endfor %} {% endfor %} + {{ inline_admin_form.form.content_type }} + {{ inline_admin_form.form.value }} {% if inline_admin_formset.formset.can_delete %} {% if inline_admin_form.original %}{{ inline_admin_form.deletion_field.field }}{% endif %} {% endif %} -- 2.20.1