#POST method doesn't work when I run test function with invalid data

40 messages · Page 1 of 1 (latest)

alpine musk
#

Hello. I have the following issue with my test function concerning updating worker with invalid data.
Here is code with my test function:

    def test_worker_update_post_invalid(self):
        user = Worker.objects.get(pk=1)

        self.client.force_login(user)
        url = f"/workers/{user.id}/update/"
        data = model_to_dict(user)
        data.pop("password")
        data.pop("teams")
        data["email"] = "test"
        resp = self.client.post(url, data)
        user.refresh_from_db()
        self.assertEqual(user.email, data["email"])
        self.assertEqual(resp.status_code, 200)

Here is code of my view

class WorkerUpdate(LoginRequiredMixin, generic.UpdateView):
    model = Worker
    form_class = WorkerCreateForm
    template_name = "assignment_handler/worker_form.html"
    success_url = reverse_lazy("assignment_handler:worker-detail")

    def post(self, request, *args, **kwargs):
        form = WorkerUpdateForm(request.POST, instance=self.get_object())
        if form.is_valid():
            return self.form_valid(form)
        else:
            return self.form_invalid(form)

    def form_valid(self, form):
        self.object = form.save()
        return super().form_valid(form)

    def form_invalid(self, form):
        self.object = self.get_object()
        return super().form_invalid(form)
#

So now, when I enter an invalid email, the POST method does not work, although in theory the code passes into the conditional operator else that the form is invalid. But in theory, even if the data is invalid, the POST method should work, but the object simply should not be updated.
The terminal displays an error - AttributeError: 'str' object has no attribute 'form'
This is, of course, natural, but even in this case, the POST method should work, and an error about the invalidity of the form data should simply be displayed at the level of view.
How can I solve this problem?

white matrix
#

Please post complete tracebacks when posting an error. It's much easier to find an error than guessing.

true gale
#

I personally am going to ask you to put all your code on github, so I can see it

#

maybe Pat can figure it out without the code, but I almost certainly can't

alpine musk
true gale
#

if only there were some way to update the code on github 🤔

alpine musk
true gale
#

if only there were some way to make, I dunno, a "branch" or something

#

type three backticks, then paste, then type three more backticks

alpine musk
#
Traceback (most recent call last):
  File "C:\Users\Dell\PycharmProjects\Endeavor_passion\workflow_organizer\tests\test_views.py", line 116, in test_worker_update_post_invalid
    resp = self.client.post(url, data)
  File "C:\Users\Dell\PycharmProjects\Endeavor_passion\workflow_organizer\venv\lib\site-packages\django\test\client.py", line 1070, in post
    response = super().post(
  File "C:\Users\Dell\PycharmProjects\Endeavor_passion\workflow_organizer\venv\lib\site-packages\django\test\client.py", line 490, in post
    return self.generic(
  File "C:\Users\Dell\PycharmProjects\Endeavor_passion\workflow_organizer\venv\lib\site-packages\django\test\client.py", line 617, in generic
    return self.request(**r)
  File "C:\Users\Dell\PycharmProjects\Endeavor_passion\workflow_organizer\venv\lib\site-packages\django\test\client.py", line 1013, in request
    self.check_exception(response)
  File "C:\Users\Dell\PycharmProjects\Endeavor_passion\workflow_organizer\venv\lib\site-packages\django\test\client.py", line 743, in check_exception
    raise exc_value
  File "C:\Users\Dell\PycharmProjects\Endeavor_passion\workflow_organizer\venv\lib\site-packages\django\core\handlers\exception.py", line 55, in inner
    response = get_response(request)
  File "C:\Users\Dell\PycharmProjects\Endeavor_passion\workflow_organizer\venv\lib\site-packages\django\core\handlers\base.py", line 220, in _get_response
    response = response.render()
  File "C:\Users\Dell\PycharmProjects\Endeavor_passion\workflow_organizer\venv\lib\site-packages\django\template\response.py", line 114, in render
    self.content = self.rendered_content
  File "C:\Users\Dell\PycharmProjects\Endeavor_passion\workflow_organizer\venv\lib\site-packages\django\template\response.py", line 92, in rendered_content
    return template.render(context, self._request)
true gale
#

well if you do wind up pushing your code to github, ping me; until then I'm outta here

alpine musk
#
File "C:\Users\Dell\PycharmProjects\Endeavor_passion\workflow_organizer\venv\lib\site-packages\django\template\backends\django.py", line 61, in render
    return self.template.render(context)
  File "C:\Users\Dell\PycharmProjects\Endeavor_passion\workflow_organizer\venv\lib\site-packages\django\template\base.py", line 171, in render
    return self._render(context)
  File "C:\Users\Dell\PycharmProjects\Endeavor_passion\workflow_organizer\venv\lib\site-packages\django\test\utils.py", line 111, in instrumented_test_render
    return self.nodelist.render(context)
  File "C:\Users\Dell\PycharmProjects\Endeavor_passion\workflow_organizer\venv\lib\site-packages\django\template\base.py", line 1000, in render
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "C:\Users\Dell\PycharmProjects\Endeavor_passion\workflow_organizer\venv\lib\site-packages\django\template\base.py", line 1000, in <listcomp>
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "C:\Users\Dell\PycharmProjects\Endeavor_passion\workflow_organizer\venv\lib\site-packages\django\template\base.py", line 961, in render_annotated
    return self.render(context)
  File "C:\Users\Dell\PycharmProjects\Endeavor_passion\workflow_organizer\venv\lib\site-packages\django\template\loader_tags.py", line 159, in render
    return compiled_parent._render(context)
  File "C:\Users\Dell\PycharmProjects\Endeavor_passion\workflow_organizer\venv\lib\site-packages\django\test\utils.py", line 111, in instrumented_test_render
    return self.nodelist.render(context)
#
File "C:\Users\Dell\PycharmProjects\Endeavor_passion\workflow_organizer\venv\lib\site-packages\django\template\backends\django.py", line 61, in render
    return self.template.render(context)
  File "C:\Users\Dell\PycharmProjects\Endeavor_passion\workflow_organizer\venv\lib\site-packages\django\template\base.py", line 171, in render
    return self._render(context)
  File "C:\Users\Dell\PycharmProjects\Endeavor_passion\workflow_organizer\venv\lib\site-packages\django\test\utils.py", line 111, in instrumented_test_render
    return self.nodelist.render(context)
  File "C:\Users\Dell\PycharmProjects\Endeavor_passion\workflow_organizer\venv\lib\site-packages\django\template\base.py", line 1000, in render
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "C:\Users\Dell\PycharmProjects\Endeavor_passion\workflow_organizer\venv\lib\site-packages\django\template\base.py", line 1000, in <listcomp>
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "C:\Users\Dell\PycharmProjects\Endeavor_passion\workflow_organizer\venv\lib\site-packages\django\template\base.py", line 961, in render_annotated
    return self.render(context)
  File "C:\Users\Dell\PycharmProjects\Endeavor_passion\workflow_organizer\venv\lib\site-packages\django\template\loader_tags.py", line 159, in render
    return compiled_parent._render(context)
  File "C:\Users\Dell\PycharmProjects\Endeavor_passion\workflow_organizer\venv\lib\site-packages\django\test\utils.py", line 111, in instrumented_test_render
    return self.nodelist.render(context)
alpine musk
# white matrix Please post complete tracebacks when posting an error. It's much easier to find ...
File "C:\Users\Dell\PycharmProjects\Endeavor_passion\workflow_organizer\venv\lib\site-packages\django\template\base.py", line 1000, in render
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "C:\Users\Dell\PycharmProjects\Endeavor_passion\workflow_organizer\venv\lib\site-packages\django\template\base.py", line 1000, in <listcomp>
    return SafeString("".join([node.render_annotated(context) for node in self]))
  File "C:\Users\Dell\PycharmProjects\Endeavor_passion\workflow_organizer\venv\lib\site-packages\django\template\base.py", line 961, in render_annotated
    return self.render(context)
  File "C:\Users\Dell\PycharmProjects\Endeavor_passion\workflow_organizer\venv\lib\site-packages\django\template\base.py", line 1059, in render
    output = self.filter_expression.resolve(context)
  File "C:\Users\Dell\PycharmProjects\Endeavor_passion\workflow_organizer\venv\lib\site-packages\django\template\base.py", line 737, in resolve
    new_obj = func(obj, *arg_vals)
  File "C:\Users\Dell\PycharmProjects\Endeavor_passion\workflow_organizer\venv\lib\site-packages\crispy_forms\templatetags\crispy_forms_filters.py", line 108, in as_crispy_field
    helper = getattr(field.form, "helper", None)
AttributeError: 'str' object has no attribute 'form'
white matrix
alpine musk
#
class WorkerCreate(generic.CreateView):
    model = Worker
    form_class = WorkerCreateForm
    template_name = "registration/register.html"
    success_url = reverse_lazy("assignment_handler:index")

    def post(self, request, *args, **kwargs):
        form = self.get_form()

        if form.is_valid():
            return self.form_valid(form)
        else:
            self.object = None
            return self.form_invalid(form)

    def form_valid(self, form):
        self.object = form.save(commit=False)
        self.object.save()
        form.save_m2m()
        return super().form_valid(form)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        teams = Team.objects.all()
        context["teams"] = teams
        return context
white matrix
#

Is this problem related to template?
Seeing as the exception is raised in "C:\Users\Dell\PycharmProjects\Endeavor_passion\workflow_organizer\venv\lib\site-packages\crispy_forms\templatetags\crispy_forms_filters.py", which is a template tag, the error might be coming from the template getting a string where it expects a field...

alpine musk
timid phoenix
#

And the WorkerCreateForm code?

alpine musk
# timid phoenix And the WorkerCreateForm code?
class WorkerCreateForm(UserCreationForm):
    username = forms.CharField(
        max_length=255,
        widget=forms.TextInput(
            attrs={"placeholder": "Username*", "style": "padding: 10px"}
        ),
        label="",
        required=True,
    )
    first_name = forms.CharField(
        max_length=255,
        widget=forms.TextInput(
            attrs={"placeholder": "First Name*", "style": "padding: 10px"}
        ),
        label="",
        required=True,
    )
    last_name = forms.CharField(
        max_length=255,
        widget=forms.TextInput(
            attrs={"placeholder": "Last Name*", "style": "padding: 10px"}
        ),
        label="",
        required=True,
    )
    email = forms.EmailField(
        widget=forms.EmailInput(
            attrs={"placeholder": "Email*", "style": "padding: 10px"}
        ),
        required=True,
        label="",
    )
    password1 = forms.CharField(
        widget=forms.PasswordInput(
            attrs={"placeholder": "Password*", "style": "padding: 10px"}
        ),
        label="",
        required=True,
    )
    password2 = forms.CharField(
        widget=forms.PasswordInput(
            attrs={"placeholder": "Confirm password*", "style": "padding: 10px"}
        ),
        label="",
        required=True,
    )
    position = forms.ModelChoiceField(
        widget=forms.Select(attrs={"style": "padding: 10px;"}),
        queryset=Position.objects.all(),
        required=False,
    )
    teams = forms.ModelMultipleChoiceField(
        widget=forms.SelectMultiple(attrs={"style": "padding: 10px;"}),
        queryset=Team.objects.all(),
        required=False,
    )
    rating_points = forms.IntegerField(initial=0, required=False)
timid phoenix
#

You’ve pasted the code for the WorkerCreate view, but the view you’re testing is the update view. Can we see that code instead?

alpine musk
# timid phoenix You’ve pasted the code for the WorkerCreate view, but the view you’re testing is...
class WorkerUpdate(LoginRequiredMixin, generic.UpdateView):
    model = Worker
    form_class = WorkerUpdateForm
    template_name = "assignment_handler/worker_form.html"
    success_url = reverse_lazy("assignment_handler:worker-detail")

    def post(self, request, *args, **kwargs):
        form = WorkerUpdateForm(request.POST, instance=self.get_object())
        if form.is_valid():
            return self.form_valid(form)
        else:
            return self.form_invalid(form)

    def form_valid(self, form):
        self.object = form.save()
        return super().form_valid(form)

    def form_invalid(self, form):
        self.object = self.get_object()
        return super().form_invalid(form)
alpine musk
#

I am not sure*

timid phoenix
#

I’m not sure why you’re overriding so many methods in UpdateView, it seems that all they’re doing is replicating the built in behaviour

#

But the exception you pasted is 100% about your template expecting a field and finding a string.

#

Thing is, I have little faith at this point that that’s actually the error you’re seeing or the code you’re running 😆

alpine musk
#

I mean generally even in case of invalid inputs post method should work

timid phoenix
#

It should, yes. And does this exception only happen in the test? Or can you replicate it in the browser?

alpine musk
#

It's about situation that I have one template form for worker create and worker update cases

#

And fields like username, password can't be updated

#

But they are included in this form as well

alpine musk
alpine musk
white matrix
#

Figure out why your template renders a string rather than a field instance 🤷‍♂️