とった。もっとエレガントな方法があると確信しています。コードを改善する方法を知っている場合は、私にいくつかの指針を与えるか、より良い解決策を提供してください。
class ManyToManyTagField(ManyToManyField):
def formfield(self, **kwargs):
defaults = {
'form_class': TagField,
}
return super(ManyToManyTagField, self).formfield(**defaults)
def save_form_data(self, instance, data):
tags = []
for tag_id in data:
autocompletedTag = tag_id.find('___')
if autocompletedTag > 0:
parts = tag_id.split('___')
tags.append(parts[0])
else:
newTag = Tag(name=tag_id, category=TagCategory.objects.get(name='New'))
newTag.save()
tags.append(newTag.id)
return super(ManyToManyTagField, self).save_form_data(instance, tags)
関連する部分はメソッドsave_form_data
です。
完全を期すために、他のクラスを次に示します。
タグウィジェット:
class TagWidget(SelectMultiple):
"""
Widget for Tag input fields.
"""
queryset = []
def render(self, name, value, attrs=None):
final_attrs = self.build_attrs(attrs, name=name)
final_attrs['class'] = 'tag-input'
selectedTags = []
if value:
for tag_id in value:
if isinstance(tag_id, (int, long)) or tag_id.isdigit():
tag_name = Tag.objects.get(pk=tag_id).name
selectedTags.append({ 'value': str(tag_id) + '___' + tag_name, 'label': tag_name })
else:
autocompletedTag = tag_id.find('___')
if autocompletedTag > 0:
parts = tag_id.split('___')
selectedTags.append({ 'value': parts[0] + '___' + parts[1], 'label': parts[1] })
else:
selectedTags.append({ 'value': tag_id, 'label': tag_id })
allTags = []
for tag in self.queryset:
allTags.append({ 'value': str(tag.id) + '___' + str(tag.name), 'label': str(tag.name) });
allTagsJson = simplejson.dumps(allTags)
return render_to_string('form/tagwidget.html',
{'attrs': flatatt(final_attrs), 'selectedTags': selectedTags, 'allTags': allTagsJson})
タグフィールド:
class TagField(ModelMultipleChoiceField):
widget = TagWidget
def __init__(self, queryset, *args, **kwargs):
self.widget.queryset = queryset
super(TagField, self).__init__(queryset, *args, **kwargs)
def clean(self, value):
if self.required and not value:
raise ValidationError(self.error_messages['required'])
elif not self.required and not value:
return []
if not isinstance(value, (list, tuple)):
raise ValidationError(self.error_messages['list'])
# Since this overrides the inherited ModelChoiceField.clean
# we run custom validators here
self.run_validators(value)
return value
タグウィジェット.html:
{% autoescape off %}
<ul{{ attrs }}>
{% for tag in selectedTags %}
<li tagValue="{{ tag.value }}">{{ tag.label }}</li>
{% endfor %}
</ul>
<script type="text/javascript">
var autocompletionData = {{ allTags }};
</script>
{% endautoescape %}