iiuni / projektzapisy

System Zapisów na zajęcia w Instytucie Informatyki Uniwersytetu Wrocławskiego
https://zapisy.ii.uni.wroc.pl
32 stars 10 forks source link

AttributeError: 'SingleVoteForm' object has no attribute 'template' #1502

Open rollbar[bot] opened 1 year ago

rollbar[bot] commented 1 year ago

View details in Rollbar: https://rollbar.com/iiuni/projektzapisy/items/516/

Traceback (most recent call last):
  File "/home/zapisy/deploy/releases/20220914100634/venv/lib/python3.8/site-packages/django/core/handlers/base.py", line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/zapisy/deploy/releases/20220914100634/venv/lib/python3.8/site-packages/newrelic/hooks/framework_django.py", line 554, in wrapper
    return wrapped(*args, **kwargs)
  File "/home/zapisy/deploy/releases/20220914100634/venv/lib/python3.8/site-packages/django/contrib/auth/decorators.py", line 21, in _wrapped_view
    return view_func(request, *args, **kwargs)
  File "/home/zapisy/deploy/releases/20220914100634/zapisy/apps/offer/vote/views.py", line 62, in vote
    return render(request, template_name, {
  File "/home/zapisy/deploy/releases/20220914100634/venv/lib/python3.8/site-packages/django/shortcuts.py", line 19, in render
    content = loader.render_to_string(template_name, context, request, using=using)
  File "/home/zapisy/deploy/releases/20220914100634/venv/lib/python3.8/site-packages/django/template/loader.py", line 62, in render_to_string
    return template.render(context, request)
  File "/home/zapisy/deploy/releases/20220914100634/venv/lib/python3.8/site-packages/django/template/backends/django.py", line 61, in render
    return self.template.render(context)
  File "/home/zapisy/deploy/releases/20220914100634/venv/lib/python3.8/site-packages/django/template/base.py", line 170, in render
    return self._render(context)
  File "/home/zapisy/deploy/releases/20220914100634/venv/lib/python3.8/site-packages/newrelic/api/function_trace.py", line 143, in dynamic_wrapper
    return wrapped(*args, **kwargs)
  File "/home/zapisy/deploy/releases/20220914100634/venv/lib/python3.8/site-packages/django/template/base.py", line 162, in _render
    return self.nodelist.render(context)
  File "/home/zapisy/deploy/releases/20220914100634/venv/lib/python3.8/site-packages/django/template/base.py", line 938, in render
    bit = node.render_annotated(context)
  File "/home/zapisy/deploy/releases/20220914100634/venv/lib/python3.8/site-packages/django/template/base.py", line 905, in render_annotated
    return self.render(context)
  File "/home/zapisy/deploy/releases/20220914100634/venv/lib/python3.8/site-packages/django/template/loader_tags.py", line 150, in render
    return compiled_parent._render(context)
  File "/home/zapisy/deploy/releases/20220914100634/venv/lib/python3.8/site-packages/newrelic/api/function_trace.py", line 143, in dynamic_wrapper
    return wrapped(*args, **kwargs)
  File "/home/zapisy/deploy/releases/20220914100634/venv/lib/python3.8/site-packages/django/template/base.py", line 162, in _render
    return self.nodelist.render(context)
  File "/home/zapisy/deploy/releases/20220914100634/venv/lib/python3.8/site-packages/django/template/base.py", line 938, in render
    bit = node.render_annotated(context)
  File "/home/zapisy/deploy/releases/20220914100634/venv/lib/python3.8/site-packages/django/template/base.py", line 905, in render_annotated
    return self.render(context)
  File "/home/zapisy/deploy/releases/20220914100634/venv/lib/python3.8/site-packages/django/template/loader_tags.py", line 150, in render
    return compiled_parent._render(context)
  File "/home/zapisy/deploy/releases/20220914100634/venv/lib/python3.8/site-packages/newrelic/api/function_trace.py", line 143, in dynamic_wrapper
    return wrapped(*args, **kwargs)
  File "/home/zapisy/deploy/releases/20220914100634/venv/lib/python3.8/site-packages/django/template/base.py", line 162, in _render
    return self.nodelist.render(context)
  File "/home/zapisy/deploy/releases/20220914100634/venv/lib/python3.8/site-packages/django/template/base.py", line 938, in render
    bit = node.render_annotated(context)
  File "/home/zapisy/deploy/releases/20220914100634/venv/lib/python3.8/site-packages/django/template/base.py", line 905, in render_annotated
    return self.render(context)
  File "/home/zapisy/deploy/releases/20220914100634/venv/lib/python3.8/site-packages/newrelic/hooks/framework_django.py", line 778, in wrapper
    return wrapped(*args, **kwargs)
  File "/home/zapisy/deploy/releases/20220914100634/venv/lib/python3.8/site-packages/django/template/loader_tags.py", line 62, in render
    result = block.nodelist.render(context)
  File "/home/zapisy/deploy/releases/20220914100634/venv/lib/python3.8/site-packages/django/template/base.py", line 938, in render
    bit = node.render_annotated(context)
  File "/home/zapisy/deploy/releases/20220914100634/venv/lib/python3.8/site-packages/django/template/base.py", line 905, in render_annotated
    return self.render(context)
  File "/home/zapisy/deploy/releases/20220914100634/venv/lib/python3.8/site-packages/django/template/defaulttags.py", line 350, in render
    obj_list = self.target.resolve(context, ignore_failures=True)
  File "/home/zapisy/deploy/releases/20220914100634/venv/lib/python3.8/site-packages/django/template/base.py", line 698, in resolve
    new_obj = func(obj, *arg_vals)
  File "/home/zapisy/deploy/releases/20220914100634/venv/lib/python3.8/site-packages/django/template/defaultfilters.py", line 499, in dictsort
    return sorted(value, key=_property_resolver(arg))
  File "/home/zapisy/deploy/releases/20220914100634/venv/lib/python3.8/site-packages/django/template/base.py", line 796, in resolve
    value = self._resolve_lookup(context)
  File "/home/zapisy/deploy/releases/20220914100634/venv/lib/python3.8/site-packages/django/template/base.py", line 877, in _resolve_lookup
    current = context.template.engine.string_if_invalid
AttributeError: 'SingleVoteForm' object has no attribute 'template'Traceback (most recent call last):
  File "/home/zapisy/deploy/releases/20220914100634/venv/lib/python3.8/site-packages/django/template/base.py", line 837, in _resolve_lookup
    current = getattr(current, bit)
  File "/home/zapisy/deploy/releases/20220914100634/venv/lib/python3.8/site-packages/django/db/models/fields/related_descriptors.py", line 197, in __get__
    raise self.RelatedObjectDoesNotExist(
RelatedObjectDoesNotExist: SingleVote has no proposal.Traceback (most recent call last):
  File "/home/zapisy/deploy/releases/20220914100634/venv/lib/python3.8/site-packages/django/template/base.py", line 829, in _resolve_lookup
    current = current[bit]
TypeError: 'SingleVote' object is not subscriptable
lgpawel commented 1 year ago

Na szczęście cały czas mamy tylko jedno wystąpienie problemu (jeszcze odezwę się do osoby, której się ono przytrafiło, może będzie mieć jakieś dodatkowe informacje). Rzecz dotyczy odesłanego (metoda żądania to POST) formularza głosowania na przedmioty, czyli FormSetu jakoś tam podobnego do tego, który równolegle rozpracowujemy w #1322.

Najciekawsza rzecz, którą widzę w informacjach zebranych przez Rollbar to to, że w żądaniu ustawione są wartości form-0-id i form-0-value, form-3-id i form-3-value, ale już tylko form-5-value (równe 3, gdy obie poprzednie są 0. choć z tym niekoniecznie wiązałbym jakiś głębszy sens) bez jakiegokolwiek form-5-id (więcej wartości o nazwach zaczynających się od form-<N>- nie ma).

lgpawel commented 1 year ago

A oto informacja od sprawcy:

Żeby ułatwić sobie podejmowanie decyzji postanowiłem "oczyścić" formularz głosowania z przedmiotów, które już zaliczyłem lub którymi na pewno nie jestem zainteresowany. W tym celu usunąłem z drzewa DOM elementy <tr class="... subject-id-*">​​​. Następnie przydzieliłem punkty i kliknąłem "Głosuj​".

Czyli tak: na jakimś poziomie "wina" nie jest po naszej stronie – jak ktoś majstruje w formularzu i go odsyła, to może uzyskać dziwne efekty i tego się nie uniknie. Z drugiej strony to pokazuje, że nasi użytkownicy nawet w dobrej wierze mogą mieć ciekawe pomysły na interakcję z systemem i w takich sytuacjach ten system powinien jednak pokazywać im jakiś czytelny komunikat o zdarzeniu, a nie tylko blankietowe "coś poszło nie tak".

Innymi słowy, trzeba złapać jakiś wyjątek, natomiast głównym zadaniem jest rozgryzienie, jaki i gdzie. Oczywiście tutaj, jak i wszędzie, trzeba złapać jak najmniejszą klasę wyjątków, którą zidentyfikujemy jako wynikającą z opisanego scenariusza, żeby nie odciąć się od ew. przyszłych komunikatów o innych scenariuszach, które mogą wymagać innego podejścia.

Utwierdzam się w przekonaniu, że temat ma część wspólną z #1322, nawet jeśli zarówno geneza błędu jak i ostatecznie raportowane wyjątki są inne. Jest tu też ukryty feature request: jak już kiedyś będziemy mieć nietrywialną zawartość modelu CompletedCourses, to można dodać na jej podstawie jakieś proste filtrowanie / stylowanie na stronie formularza głosowania na przedmioty.