Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug when calling a function multiple times #77

Closed
nyradr opened this issue Nov 30, 2020 · 4 comments
Closed

Bug when calling a function multiple times #77

nyradr opened this issue Nov 30, 2020 · 4 comments
Assignees

Comments

@nyradr
Copy link

nyradr commented Nov 30, 2020

Template :

<button unicorn:click="set({{ pk }})">
<p>{{ obj.name }} </p>

View :

class TestView(UnicornView):
  obj = None
  pk = 42 # object ID as int from elsewere

  def set(self, pk):
    self.obj = Model.objects.get(pk=pk)

When I click (at least) two times on the button, I get the error : AttributeError: 'int' object has no attribute 'keys'.

Traceback (most recent call last):
web_1     |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 47, in inner
web_1     |     response = get_response(request)
web_1     |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py", line 179, in _get_response
web_1     |     response = wrapped_callback(request, *callback_args, **callback_kwargs)
web_1     |   File "/usr/local/lib/python3.6/site-packages/django_unicorn/views.py", line 25, in wrapped_view
web_1     |     return view_func(*args, **kwargs)
web_1     |   File "/usr/local/lib/python3.6/site-packages/django/utils/decorators.py", line 130, in _wrapped_view
web_1     |     response = view_func(request, *args, **kwargs)
web_1     |   File "/usr/local/lib/python3.6/site-packages/django/views/decorators/http.py", line 40, in inner
web_1     |     return func(request, *args, **kwargs)
web_1     |   File "/usr/local/lib/python3.6/site-packages/django_unicorn/views.py", line 225, in message
web_1     |     _set_property_from_data(component, name, value)
web_1     |   File "/usr/local/lib/python3.6/site-packages/django_unicorn/views.py", line 48, in _set_property_from_data
web_1     |     _set_property_from_data(field, key, key_value)
web_1     |   File "/usr/local/lib/python3.6/site-packages/django_unicorn/views.py", line 46, in _set_property_from_data
web_1     |     for key in value.keys():
web_1     | AttributeError: 'int' object has no attribute 'keys'

Clicking only once the component works fine and the object is fetch. After that, any call to a component function triggers the exception.
The exception is triggered before entering the function but only when self.obj is set inside the function.

The object with the given ID exist in the database and is fetched correctly the first time the function is called.

@adamghill
Copy link
Owner

Can you give me a screenshot or the JSON that gets passed in the XHR request/responses when you are clicking the button?

I've tried to replicate the best I can with the following code:

class TestView(UnicornView):
    obj = None
    pk = 2

    def set(self, pk):
        print("set called with pk: " + str(pk))
        self.obj = Flavor.objects.get(pk=pk)
        print("self.obj set to: " + str(self.obj))
<div>
        TEST<br />
        <button unicorn:click="set({{ pk }})">
        <p>{{ obj.name }} </p>
    </div>

It seems to be working ok for me as shown in this gif. But, maybe with more information I can figure out what is going on. My hunch is that a component field is originally a Django model, but that for some reason the JSON data only has an integer (maybe the pk?) come across the wire. django-unicorn assumes that a model will have a dictionary representation that is created from the Django serialization framework. Maybe there is something custom in your model?

multiple-clicks

@adamghill adamghill self-assigned this Nov 30, 2020
@nyradr
Copy link
Author

nyradr commented Dec 1, 2020

The model is pretty standard :

class ObjA(models.Model):
  name = models.CharField(max_length=42)

class ObjB(models.Model):
  name = models.CharField(max_length=42)

class ObjC(models.Model):
  relA = models.ForeignKey(ObjA, on_delete=models.CASCADE, related_name='objcs')
  relB = models.ForeignKey(ObjB, on_delete=models.CASCADE, related_name='objcs')
  value = models.FloatField()

The unicorn view :

class UView(UnicornView):
  name = "uview"
  obja = None
  objc_left = None
  objc_right = None

  def __init__(self, *args, **kwargs):
    super(self).__init__(*args, **kwargs)
    self.obja = ObjA.objects.get(pk=kwargs["pk"])

  def set_left(self, pk):
    self.objc_left = ObjC.objects.get(pk=pk)

  def set_right(self, pk):
    self.objc_right = ObjC.objects.get(pk=pk)

The template looks like that :

<select name="left">
{% for x in obja.sub.all %}
  <option value="{{ x.id }}" unicorn:click="set_left({{ x.id }})">
{% endfor %}
</select>

<select name="right">
{% for x in obja.sub.all %}
  <option value="{{ x.id }}" unicorn:click="set_right({{ x.id }})">
{% endfor %}
</select>

@adamghill
Copy link
Owner

@nyradr Ok, I created #80 which has basically the code above so I should be able to replicate. I tweaked a few things and changed the selects to use model instead of unicorn:click (https://github.com/adamghill/django-unicorn/pull/80/files#diff-de05051bdc2595d517d19cd1625b613e9b90836255d675df2d9ddcd9c67e6c31R16-R26) because the click event doesn't fire on options.

Can you grab that branch and 1) add some code that shows the bug or 2) give me exact steps to reproduce? Thank you!

@adamghill
Copy link
Owner

This ended up being two different bugs. Checksums wouldn't match if the float fields ended in .0 which would get rendered as an integer in JavaScript (fixed in #82). Related models are rendered as a pk of the model, not a dictionary representation, so that needed to be handled in aaf62e8.

Both fixes are published in version 0.10.1 which has been published to pypi.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants