知道了。我相信还有更优雅的方法。如果您知道如何改进代码,请给我一些指示或提供更好的解决方案:
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 %}