class NodeTag(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
node = models.ForeignKey(Node, on_delete=models.CASCADE, related_name='node_tags', related_query_name='node_tag')
tag = models.CharField(max_length=64)
In forms.py I have a form
class NodeTagForm(ModelForm):
tag = ModelChoiceField(queryset=models.Tag.objects.none(), to_field_name="name")
class Meta:
model = models.NodeTag
fields = (
'tag',
'order_by',
)
Using Select2 I made the tag field an autocomplete field. The problem is that when I submit the form, I get the following error:
Select a valid choice. That choice is not one of the available choices.
The issue is solved by setting none() to all() in the form
tag = ModelChoiceField(queryset=models.Tag.objects.all(), to_field_name="name")
However, this results in a with a 1000+ options. I wonder whether there is a better way to implement the autocomplete.
So the core issue here is that you’re using standard widgets to render the form field - which by default is going to include the contents of the queryset as the select options.
What I’d recommend would be to leave the queryset the same (using all so that validation works correctly), and modify the __init__ method of the form class to set the choices attribute of the tag field to be an empty list.
In the future, I would recommend using django-select2 for integrating Select2 in your Django projects. (I’m just not sure it’s worth the effort to do that now given the work you’ve already invested in your current solution.)
Before investing the work in my current solution I explored django-select2 amongst others. Since I need a text editor as well, I also had a look at django-tinymce.
Reading the docs I realized that all these django- packages have their own approach to solving the issue at hand. After having a look at Django admin’s implementation of autocomplete, I decided to implement my current solution.
After modifying the __init()__ method, everything works fine.
tag = models.ForeignKey(Tag, on_delete=models.CASCADE, related_name='node_tag_tags', related_query_name='node_tag_tag')
Consequently, I had to make some changes to the code in forms.py and views.py. Everything works, except this line of code in the form’s __init__ method.
If self.instance.tag_id is the FK to Tag, then self.instance.tag is a reference to the Tag object - which means you can call any model method on that object or access any field.
So all these are available: self.instance.tag.name str(self.instance.tag) self.instance.tag.__str__()
etc, etc.