开发者

Display a comma separated list of ManyToMany items in a Charfield on a ModelForm

开发者 https://www.devze.com 2023-02-10 06:12 出处:网络
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 charfi

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))
0

精彩评论

暂无评论...
验证码 换一张
取 消