I have a model containing a ManyToMany field to a table "Tags". Since this table could be huge, I don't want to display a select in the form, but a coma separated list of tags, provided by a charfield (I suppose).
On the saving, I woul开发者_如何转开发d split the list by their comma and then add them one by one (using get_or_create). I already did that.
But when I want to change data, instead of having a list of tags, I have a list of IDs.
How can I display a list of comma separated tags? Do I have to create a new specific Field for that ? or is there already something that do what I'm looking for?
Thanks for your help!
You'll want to create a custom widget (I'm not aware of a built-in widget that will do exactly what you want). The most useful examples would probably be the widgets that come with Django (in forms/widgets.py). You can also see an example of creating a custom widget here.
I did a little fiddling, and after adapting the built-in Input
widget this is what I came up with; I did some testing and it works for me:
class CommaTags(Widget):
def render(self, name, value, attrs=None):
final_attrs = self.build_attrs(attrs, type='text', name=name)
objects = []
for each in value:
try:
object = Tag.objects.get(pk=each)
except:
continue
objects.append(object)
values = []
for each in objects:
values.append(str(each))
value = ', '.join(values)
if value: # only add 'value' if it's nonempty
final_attrs['value'] = force_unicode(value)
return mark_safe(u'<input%s />' % flatatt(final_attrs))
Note that in this example, the widget is hardcoded to use a hypothetical Tag
model, and it's just using the str()
method of each object as what will show up in the comma-separated list. You'll probably want to change these to fit your use. Also, I had this directly in forms/widgets.py, so if you put it somewhere else (like you probably should), you'll need to import a few of the things I used.
Once you have that created, you can specify it as the widget for your ModelMultipleChoiceField in your form, like so:
from django import forms
class TagForm(forms.ModelForm):
tags = forms.ModelMultipleChoiceField(queryset=Tag.objects.all(),
widget=CommaTags)
class Meta:
model = Tag
The code above could use queries in a more optimal way, something like
class CommaTags(Widget): def render(self, name, value, attrs=None): value = Tag.objects.filter(pk__in=each) \ .exclude(name__exact='') \ .values_list("name") \ .join(", ") if value: final_attrs['value'] = force_unicode(value) return mark_safe(u'<input%s />' % flatatt(final_attrs))
精彩评论