django-unicorn icon indicating copy to clipboard operation
django-unicorn copied to clipboard

How to pass a form from a template to a unicorn component.

Open Joetib opened this issue 3 years ago • 7 comments

I have been trying to pass a form from my template to a unicorn template

class UnicornCreateStudentFormView(UnicornView):
    form = None

    def __init__(self, form, *args, **kwargs):
        super().__init__(*args, **kwargs)
        print(form, type(form))
        self.form = form

The component template

<div class="py-5">
    {% load crispy_forms_tags %}
    <style>
        [unicorn\:error\:invalid] {
          border: 1px solid red !important;
        }
        [unicorn\:error\:required] {
          border: 1px solid red !important;
        }
      </style>
    <form action="." method="POST" enctype="multipart/form-data">
        {% csrf_token %}
        <div class="row">
            <div class="col-12">
                <div class="shadow p-3">

                <div class="row ">

                    <div class="col-md-6">
                        <label for="id_username">Username:</label>
                        <input unicorn:model="username" class="form-control" type="text" name="username"
                            id="id_username" />
                        <span class="text-danger">{{ username_message }}</span>

                    </div>
                    <div class="col-md-6">
                        <label for="id_password">Password:</label>
                        <input unicorn:model="password" class="form-control" type="password" name="password"
                            id="id_password" />
                            <span class="text-danger">{{ password_message }}</span>
                            {{ form }}
                    </div>
                </div>

                </div>
            </div>

            <button unicorn:click="$validate">Validate</button>
        </div>
    </form>

</div>

I pass in the form as

{% unicorn 'unicorn-create-student-form' form=student_create_form %}

where student_create_form was passed into the template from the view context.

However the page displays the error


Request Method: | GET
-- | --
http://127.0.0.1:8000/administrator/student/create/
3.1.7
PicklingError
Can't pickle <function capfirst at 0x0000023A1F737678>: it's not the same object as django.utils.text.capfirst
C:\Users\user\Desktop\projects\school\venv\lib\site-packages\django_unicorn\utils.py, line 55, in get_cacheable_component
C:\Users\user\Desktop\projects\school\venv\Scripts\python.exe
3.7.7


The terminal error is

maxlength="150" required id="id_username"><br><span class="helptext">Required. 150 characters 
or fewer. Letters, digits and @/./+/-/_ only.</span></td></tr>
<tr><th><label for="id_email">Email address:</label></th><td><input type="email" name="email" 
maxlength="254" id="id_email"></td></tr>
<tr><th><label for="id_first_name">First name:</label></th><td><input type="text" name="first_name" maxlength="200" required id="id_first_name"></td></tr>
<tr><th><label for="id_last_name">Last name:</label></th><td><input type="text" name="last_name" maxlength="200" required id="id_last_name"></td></tr>
<tr><th><label for="id_password">Password:</label></th><td><input type="password" name="password" required id="id_password"></td></tr>
<tr><th><label for="id_picture">Picture:</label></th><td><input type="file" name="picture" accept="image/*" id="id_picture"></td></tr> <class 'administrator.forms.StudentCreateForm'>
Internal Server Error: /administrator/student/create/
Traceback (most recent call last):
  File "C:\Users\user\Desktop\projects\school\venv\lib\site-packages\django\core\handlers\exception.py", line 47, in inner
    response = get_response(request)
  File "C:\Users\user\Desktop\projects\school\venv\lib\site-packages\django\core\handlers\base.py", line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "C:\Users\user\Desktop\projects\school\venv\lib\site-packages\django\contrib\auth\decorators.py", line 21, in _wrapped_view
    return view_func(request, *args, **kwargs)
  File "C:\Users\user\Desktop\projects\school\administrator\utils.py", line 7, in __inner__   
    return function(request, *args, **kwargs)
  File "C:\Users\user\Desktop\projects\school\administrator\views.py", line 25, in create_student
    return render(request, 'administrator/create_student.html', {'student_form': student_form})
  File "C:\Users\user\Desktop\projects\school\venv\lib\site-packages\django\shortcuts.py", line 19, in render
    content = loader.render_to_string(template_name, context, request, using=using)
  File "C:\Users\user\Desktop\projects\school\venv\lib\site-packages\django\template\loader.py", line 62, in render_to_string
    return template.render(context, request)
  File "C:\Users\user\Desktop\projects\school\venv\lib\site-packages\django\template\backends\django.py", line 61, in render
    return self.template.render(context)
  File "C:\Users\user\Desktop\projects\school\venv\lib\site-packages\django\template\base.py", line 170, in render
    return self._render(context)
  File "C:\Users\user\Desktop\projects\school\venv\lib\site-packages\django\test\utils.py", line 96, in instrumented_test_render
    return self.nodelist.render(context)
  File "C:\Users\user\Desktop\projects\school\venv\lib\site-packages\django\template\base.py", line 938, in render
    bit = node.render_annotated(context)
  File "C:\Users\user\Desktop\projects\school\venv\lib\site-packages\django\template\base.py", line 905, in render_annotated
    return self.render(context)
  File "C:\Users\user\Desktop\projects\school\venv\lib\site-packages\django\template\loader_tags.py", line 150, in render
    return compiled_parent._render(context)
  File "C:\Users\user\Desktop\projects\school\venv\lib\site-packages\django\test\utils.py", line 96, in instrumented_test_render
    return self.nodelist.render(context)
  File "C:\Users\user\Desktop\projects\school\venv\lib\site-packages\django\template\base.py", line 938, in render
    bit = node.render_annotated(context)
  File "C:\Users\user\Desktop\projects\school\venv\lib\site-packages\django\template\base.py", line 905, in render_annotated
    return self.render(context)
  File "C:\Users\user\Desktop\projects\school\venv\lib\site-packages\django\template\loader_tags.py", line 62, in render
    result = block.nodelist.render(context)
  File "C:\Users\user\Desktop\projects\school\venv\lib\site-packages\django\template\base.py", line 938, in render
    bit = node.render_annotated(context)
  File "C:\Users\user\Desktop\projects\school\venv\lib\site-packages\django\template\base.py", line 905, in render_annotated
    return self.render(context)
  File "C:\Users\user\Desktop\projects\school\venv\lib\site-packages\django_unicorn\templatetags\unicorn.py", line 137, in render
    request=request,
  File "C:\Users\user\Desktop\projects\school\venv\lib\site-packages\django_unicorn\decorators.py", line 59, in timed
    result = wrapped(*args, **kwargs)
  File "C:\Users\user\Desktop\projects\school\venv\lib\site-packages\django_unicorn\components\unicorn_view.py", line 742, in create
    cacheable_component = get_cacheable_component(component)
  File "C:\Users\user\Desktop\projects\school\venv\lib\site-packages\django_unicorn\utils.py", line 55, in get_cacheable_component
    pickle.dumps(component)
_pickle.PicklingError: Can't pickle <function capfirst at 0x000001FD91EB7678>: it's not the same object as django.utils.text.capfirst

Joetib avatar Mar 04 '21 18:03 Joetib

I have resorted to a different solution where I do not pass the form to a component. But j still think being able to pass the form would be great.

Joetib avatar Mar 05 '21 22:03 Joetib

Hmm, I'm not sure what is going here. Can you post the form that has capfirst? Unicorn pickles components to keep state in cache for performance reasons. It will log a warning if it can't pickle the component, but everything should still "work".

But, I can check into it if I see the code. Thanks!

adamghill avatar Mar 07 '21 02:03 adamghill

Rendering the form normally in a Django template works perfectly. And post it also

Joetib avatar Mar 07 '21 08:03 Joetib

I see why it's breaking now. Unfortunately, I don't currently know how I would serialize/deserialize an instantiated form class although it might be possible. I'll let you know if I can figure out how to make it work!

adamghill avatar Mar 11 '21 03:03 adamghill

I have resorted to a different solution where I do not pass the form to a component

Are you instantiating the form inside the component view init method, or something else?

adamghill avatar Mar 13 '21 03:03 adamghill

I instantiated it in a regular Django view.

Joetib avatar Mar 13 '21 08:03 Joetib

I think that is needed use javascript_exclude when passing not serializables objects to unicorn. I had a similar problem.

from django_unicorn.components import UnicornView


class CheckoutPaymentMethodView(UnicornView):

    length = ''

    class Meta:
        exclude = ()
        javascript_exclude = ('form', 'wizard')

Calling from html.

{% unicorn 'checkout/checkout_payment_method' form=form wizard=wizard %}

nielsonsantana avatar Jul 22 '21 08:07 nielsonsantana