Alp
Alp

Reputation: 29749

Adding tags: Django custom form widget for ManyToMany model field

I am currently creating my own Tagging app for Django.

Here are the models:

class Tag(models.Model):
    name = models.CharField(max_length=100)

class Book(models.Model):
    title = models.CharField(max_length=100)
    tags = models.ManyToManyField(Tag)

I created a form for my model Book and a widget for Tag inputs:

class BookForm(ModelForm):
    class Meta:
        model = Book
        fields = ('title', 'tags')
        widgets = {
            'tags': TagWidget
        }

class TagWidget(Widget):
    """
    Widget for Tag input fields.
    """
    def render(self, name, value, attrs=None):
        final_attrs = self.build_attrs(attrs, name=name)
        final_attrs['class'] = 'tag-input'
        options = []

        # TODO the following tags should be assigned from the model directly
        options.append('tag1');
        options.append('tag2');

        list_element = u'<ul%s>' % flatatt(final_attrs)
        return mark_safe(list_element + '\n<li>' + (u'</li>\n<li>'.join(options)) + '</li>\n</ul>')

Questions

  1. How can i add the currently existing tags to the options array (options.append(...))?
  2. Also, how can i improve the creation of the html code (see last line mark_safe)? I'd like to put all html code somewhere else (preferably in my templates folder).

Upvotes: 0

Views: 2051

Answers (1)

DrTyrsa
DrTyrsa

Reputation: 31991

  1. You can pass additional data in widget's constructor. Something like

    class TagWidget(Widget):
        def __init__(self, initial_tags, *args, **kwargs)
            self.initial_tags = initial_tags
            super(TagWidget, self).__init__(*args, **kwargs)
    
    # ...
    
    widgets = {
        'tags': TagWidget(initial_tags=('one', 'two', 'three'))
    }
    

    Then the data will be accessible in self.initial_tags.

  2. You can use render_to_string function.

Upvotes: 3

Related Questions