Why are you creating two groups of tags ? Why not use a specific widgets like a tree widget ?
The models
class TagGroup(models.Model):
name = models.SlugField(max_length=50, unique=True, db_index=True)
class Tag(models.Model):
name = models.SlugField(max_length=50, unique=True, db_index=True)
group = models.ForeignKey(TagGroup)
def __unicode__(self):
class Album(models.Model):
name = models.CharField(max_length=64, blank=True)
tags = models.ManyToManyField(Tag, blank=True)
The idea is to have some groups of tags, for example, season (with the following tags: winter, summer, etc.) and place (with tags like Europe, America) for each album.
The problem is I can't find a way to have a separate form for each group of tags in Django Admin.
I've been reading docs for many hours trying to find the solution and here is where I come.
First approach
First of all I decided to create a separate form for tags:
class AlbumAdminForm(forms.ModelForm):
class Meta:
model = Album
tags = forms.ModelMultipleChoiceField(queryset=Tag.objects.all(), required=False, widget=FilteredSelectMultiple('tags', False ))
class AlbumAdmin(admin.ModelAdmin):
form = AlbumAdminForm
It works good. Trying to add another form like this:
class AlbumAdminForm(forms.ModelForm):
class Meta:
model = Album
tags = forms.ModelMultipleChoiceField(queryset=Tag.objects.filter(group = 1), required=False, widget=FilteredSelectMultiple('tags', False ))
tags_2 = forms.ModelMultipleChoiceField(queryset=Tag.objects.filter(group = 2), required=False, widget=FilteredSelectMultiple('tags', False ))
In this case I see two forms in django admin with tags I can select, but can't save the contents of the second form because of it's property name 'tags_2' - django relies on this name. Unfortunately, I didn't find any way to make this form use Album.tags to save it's values.
Second approach
As far as I couldn't find the right way with AlbumAdminForm itself I decided to change html code it generates. First form looks like this:
<select multiple="multiple" class="selectfilter" name="tags" id="id_tags">
</select><script type="text/javascript">
addEvent(window, "load", function(e) {SelectFilter.init("id_tags", "tags", 0, "/static/admin/"); });
</script>
I was trying to make the second one as similar as possible, but the only thing I could change is it's id:
class AlbumAdminForm(forms.ModelForm):
class Meta:
model = Album
tags = forms.ModelMultipleChoiceField(queryset=Tag.objects.filter(group = 1), required=False, widget=FilteredSelectMultiple('tags', False ))
tags_2 = forms.ModelMultipleChoiceField(queryset=Tag.objects.filter(group = 2), required=False, widget=FilteredSelectMultiple('tags', False ))
def __init__(self, *args, **kwargs):
super(AlbumAdminForm, self).__init__(*args, **kwargs)
self.fields['tags_2'].widget.attrs['id'] = 'id_tags'
I couldn't change it's name or 'SelectFilter.init' call. Don't know if it would be any useful if I could. So, still no luck.
Third approach
Trying to use MultiWidget and MultiValueField:
class My(object):
def __init__(self, val1=EmptyQuerySet(), val2=EmptyQuerySet):
self.val1=val1
self.val2=val2
class MyWidget(widgets.MultiWidget):
def __init__(self, attrs=None):
widget = (
FilteredSelectMultiple('tags1', False),
FilteredSelectMultiple('tags2', False)
)
super(MyWidget, self).__init__(widget, attrs=attrs)
def decompress(self,value):
if value:
return value.val1 + value.val2
return None
class MyField(forms.MultiValueField):
widget = MyWidget
def __init__(self, required=True, widget=None, label=None, initial=None, help_text=None, queryset=None):
field = (
ModelMultipleChoiceField(queryset=queryset),
ModelMultipleChoiceField(queryset=queryset)
)
super(MyField, self).__init__(fields=field, widget=widget, label=label, initial=initial, help_text=help_text)
class AlbumAdminForm(forms.ModelForm):
class Meta:
model = Album
tags = MyField(queryset=Tag.objects.all())
In this case I have two forms but both are empty, I have nothing to choose. No luck =(
Are you sure you use the good parameter to pass the queryset to the underlying Field
An hack that could probably work is the create a copy the tags field into a tags_2 field in class model definition but it's kind of ugly ;)