PHACDataHub / django-htmx-autocomplete

A Django autocomplete component powered by htmx
MIT License
50 stars 4 forks source link

Error when selecting a result #18

Closed raratiru closed 1 year ago

raratiru commented 1 year ago

Having implemented the example with the modelform, when I click on a result to select it, I receive a 500 error:

ValueError: Field 'id' expected a number but got ''.

This is a ForeignKey to another app and I use to to avoid circular dependency error. Could this be the issue?

models.py:

class Feed(models.Model):
    partner_key = models.ForeignKey(  # OneToOne will not save reverse relation
        to="other_app.Partner", verbose_name=_("Partner"), on_delete=models.PROTECT
    )
    date_record_saved = models.DateTimeField(
        _("Date the Record was Saved"), auto_now=True
    )
    feed = models.JSONField(_("Feed"))

    def __str__(self):
        return f"{self.date_record_saved}"

    class Meta:
        verbose_name = _("Feed")
        verbose_name_plural = _("Feeds")

forms.py:

class FeedForm(forms.ModelForm):
    class Meta:
        model = models.Feed
        fields = "__all__"
        widgets = {
            'partner_key': widgets.Autocomplete(
                name='partner_key',
                options=dict(multiselect=False, model=Partner)
            )
        }

This is the complete stack:

Traceback (most recent call last):
  File "/home/flyer/poet-calm/.venv/lib/python3.10/site-packages/django/db/models/fields/__init__.py", line 2018, in get_prep_value
    return int(value)
ValueError: invalid literal for int() with base 10: ''

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/flyer/poet-calm/.venv/lib/python3.10/site-packages/django/core/handlers/exception.py", line 55, in inner
    response = get_response(request)
  File "/home/flyer/poet-calm/.venv/lib/python3.10/site-packages/django/core/handlers/base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/flyer/poet-calm/.venv/lib/python3.10/site-packages/django/views/generic/base.py", line 103, in view
    return self.dispatch(request, *args, **kwargs)
  File "/home/flyer/poet-calm/.venv/lib/python3.10/site-packages/django/views/generic/base.py", line 142, in dispatch
    return handler(request, *args, **kwargs)
  File "/home/flyer/poet-calm/.venv/lib/python3.10/site-packages/autocomplete/autocomplete.py", line 442, in put
    self.get_items(values=items_selected + [item]), items_selected
  File "/home/flyer/poet-calm/.venv/lib/python3.10/site-packages/autocomplete/autocomplete.py", line 371, in get_items
    items = self.Meta.model.objects.filter(**search_dict)
  File "/home/flyer/poet-calm/.venv/lib/python3.10/site-packages/django/db/models/manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/home/flyer/poet-calm/.venv/lib/python3.10/site-packages/django/db/models/query.py", line 1421, in filter
    return self._filter_or_exclude(False, args, kwargs)
  File "/home/flyer/poet-calm/.venv/lib/python3.10/site-packages/django/db/models/query.py", line 1439, in _filter_or_exclude
    clone._filter_or_exclude_inplace(negate, args, kwargs)
  File "/home/flyer/poet-calm/.venv/lib/python3.10/site-packages/django/db/models/query.py", line 1446, in _filter_or_exclude_inplace
    self._query.add_q(Q(*args, **kwargs))
  File "/home/flyer/poet-calm/.venv/lib/python3.10/site-packages/django/db/models/sql/query.py", line 1532, in add_q
    clause, _ = self._add_q(q_object, self.used_aliases)
  File "/home/flyer/poet-calm/.venv/lib/python3.10/site-packages/django/db/models/sql/query.py", line 1562, in _add_q
    child_clause, needed_inner = self.build_filter(
  File "/home/flyer/poet-calm/.venv/lib/python3.10/site-packages/django/db/models/sql/query.py", line 1478, in build_filter
    condition = self.build_lookup(lookups, col, value)
  File "/home/flyer/poet-calm/.venv/lib/python3.10/site-packages/django/db/models/sql/query.py", line 1303, in build_lookup
    lookup = lookup_class(lhs, rhs)
  File "/home/flyer/poet-calm/.venv/lib/python3.10/site-packages/django/db/models/lookups.py", line 27, in __init__
    self.rhs = self.get_prep_lookup()
  File "/home/flyer/poet-calm/.venv/lib/python3.10/site-packages/django/db/models/lookups.py", line 426, in get_prep_lookup
    return super().get_prep_lookup()
  File "/home/flyer/poet-calm/.venv/lib/python3.10/site-packages/django/db/models/lookups.py", line 276, in get_prep_lookup
    rhs_value = self.lhs.output_field.get_prep_value(rhs_value)
  File "/home/flyer/poet-calm/.venv/lib/python3.10/site-packages/django/db/models/fields/__init__.py", line 2020, in get_prep_value
    raise e.__class__(
ValueError: Field 'id' expected a number but got ''.
ERROR django.request 241 Internal Server Error: /en/inhouse/ac/partner_key/toggle
Traceback (most recent call last):
  File "/home/flyer/poet-calm/.venv/lib/python3.10/site-packages/django/db/models/fields/__init__.py", line 2018, in get_prep_value
    return int(value)
ValueError: invalid literal for int() with base 10: ''

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/flyer/poet-calm/.venv/lib/python3.10/site-packages/django/core/handlers/exception.py", line 55, in inner
    response = get_response(request)
  File "/home/flyer/poet-calm/.venv/lib/python3.10/site-packages/django/core/handlers/base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/flyer/poet-calm/.venv/lib/python3.10/site-packages/django/views/generic/base.py", line 103, in view
    return self.dispatch(request, *args, **kwargs)
  File "/home/flyer/poet-calm/.venv/lib/python3.10/site-packages/django/views/generic/base.py", line 142, in dispatch
    return handler(request, *args, **kwargs)
  File "/home/flyer/poet-calm/.venv/lib/python3.10/site-packages/autocomplete/autocomplete.py", line 442, in put
    self.get_items(values=items_selected + [item]), items_selected
  File "/home/flyer/poet-calm/.venv/lib/python3.10/site-packages/autocomplete/autocomplete.py", line 371, in get_items
    items = self.Meta.model.objects.filter(**search_dict)
  File "/home/flyer/poet-calm/.venv/lib/python3.10/site-packages/django/db/models/manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/home/flyer/poet-calm/.venv/lib/python3.10/site-packages/django/db/models/query.py", line 1421, in filter
    return self._filter_or_exclude(False, args, kwargs)
  File "/home/flyer/poet-calm/.venv/lib/python3.10/site-packages/django/db/models/query.py", line 1439, in _filter_or_exclude
    clone._filter_or_exclude_inplace(negate, args, kwargs)
  File "/home/flyer/poet-calm/.venv/lib/python3.10/site-packages/django/db/models/query.py", line 1446, in _filter_or_exclude_inplace
    self._query.add_q(Q(*args, **kwargs))
  File "/home/flyer/poet-calm/.venv/lib/python3.10/site-packages/django/db/models/sql/query.py", line 1532, in add_q
    clause, _ = self._add_q(q_object, self.used_aliases)
  File "/home/flyer/poet-calm/.venv/lib/python3.10/site-packages/django/db/models/sql/query.py", line 1562, in _add_q
    child_clause, needed_inner = self.build_filter(
  File "/home/flyer/poet-calm/.venv/lib/python3.10/site-packages/django/db/models/sql/query.py", line 1478, in build_filter
    condition = self.build_lookup(lookups, col, value)
  File "/home/flyer/poet-calm/.venv/lib/python3.10/site-packages/django/db/models/sql/query.py", line 1303, in build_lookup
    lookup = lookup_class(lhs, rhs)
  File "/home/flyer/poet-calm/.venv/lib/python3.10/site-packages/django/db/models/lookups.py", line 27, in __init__
    self.rhs = self.get_prep_lookup()
  File "/home/flyer/poet-calm/.venv/lib/python3.10/site-packages/django/db/models/lookups.py", line 426, in get_prep_lookup
    return super().get_prep_lookup()
  File "/home/flyer/poet-calm/.venv/lib/python3.10/site-packages/django/db/models/lookups.py", line 276, in get_prep_lookup
    rhs_value = self.lhs.output_field.get_prep_value(rhs_value)
  File "/home/flyer/poet-calm/.venv/lib/python3.10/site-packages/django/db/models/fields/__init__.py", line 2020, in get_prep_value
    raise e.__class__(
ValueError: Field 'id' expected a number but got ''.
lucbelliveau commented 1 year ago

The code that determines which field to use as an "ID" is still fairly primitive - it sounds like the default primary key field in this case is not appropriate? I don't see the Partner model definition but you can override the field by setting item_value like this:

class FeedForm(forms.ModelForm):
    class Meta:
        model = models.Feed
        fields = "__all__"
        widgets = {
            'partner_key': widgets.Autocomplete(
                name='partner_key',
                options=dict(
                    multiselect=False,
                    model=Partner,
                    item_value='partner_id_or_whatever',
                )
            )
        }

If you can share the Partner model's class I can investigate further - an possibly improve the code that determines which field to use...

raratiru commented 1 year ago

Oh I see, thank you!

The Partner model has only a name attribute. I will give it a try and then I will close the issue.

It is very possible that it will work.