AttributeError: 'str' object has no attribute 'field'

Im trying to make a custom change password page but the page with the “PasswortConfirmView” prints this error

Internal Server Error: /reset/confirm/MQ/atg5tq-aa6bcab1c34d1228cdd1970aaaa45252/
Traceback (most recent call last):
  File "C:\Users\Finn\AppData\Local\Programs\Python\Python39\lib\site-packages\django\core\handlers\exception.py", line 47, in inner
    response = get_response(request)
  File "C:\Users\Finn\AppData\Local\Programs\Python\Python39\lib\site-packages\django\core\handlers\base.py", line 204, in _get_response
    response = response.render()
  File "C:\Users\Finn\AppData\Local\Programs\Python\Python39\lib\site-packages\django\template\response.py", line 105, in render
    self.content = self.rendered_content
  File "C:\Users\Finn\AppData\Local\Programs\Python\Python39\lib\site-packages\django\template\response.py", line 83, in rendered_content
    return template.render(context, self._request)
  File "C:\Users\Finn\AppData\Local\Programs\Python\Python39\lib\site-packages\django\template\backends\django.py", line 61, in render
    return self.template.render(context)
  File "C:\Users\Finn\AppData\Local\Programs\Python\Python39\lib\site-packages\django\template\base.py", line 170, in render
    return self._render(context)
  File "C:\Users\Finn\AppData\Local\Programs\Python\Python39\lib\site-packages\django\template\base.py", line 162, in _render
    return self.nodelist.render(context)
  File "C:\Users\Finn\AppData\Local\Programs\Python\Python39\lib\site-packages\django\template\base.py", line 938, in render
    bit = node.render_annotated(context)
  File "C:\Users\Finn\AppData\Local\Programs\Python\Python39\lib\site-packages\django\template\base.py", line 905, in render_annotated
    return self.render(context)
  File "C:\Users\Finn\AppData\Local\Programs\Python\Python39\lib\site-packages\widget_tweaks\templatetags\widget_tweaks.py", line 220, in render
    bounded_field.field.widget.input_type = v.resolve(context)
AttributeError: 'str' object has no attribute 'field'

forms.py

class CaptchaPasswordResetForm(SetPasswordForm):
    new_password1 = forms.forms.CharField(max_length=100, widget=forms.forms.PasswordInput(attrs={"class": "form-control", 'type':'password'}))
    new_password2 = forms.forms.CharField(max_length=100, widget=forms.forms.PasswordInput(attrs={"class": "form-control", 'type':'password'}))

forms.py


urls.py

from StartSite.views import password_reset_view
from StartSite.forms import NewPasswordResetForm
from StartSite.forms import CaptchaPasswordResetForm
from django.contrib import admin
from django.urls import path, include
from django.urls.base import reverse_lazy
from django.contrib.auth import views as auth_views
from StartSite.views import PasswordResetView, password_reset_email_view

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('StartSite.urls')),

    path('reset_password/',
        password_reset_email_view.as_view(template_name="home/password_reset.html", form_class=NewPasswordResetForm),
        name="reset_password"),

    path('reset_password_sent/', 
        auth_views.PasswordResetDoneView.as_view(template_name="home/password_reset_sent.html"), 
        name="password_reset_done"),

    path('reset/confirm/<uidb64>/<token>/',
        password_reset_view.as_view(template_name="home/password_reset_form.html", form_class=CaptchaPasswordResetForm), 
        name="password_reset_confirm"),

    path('reset_password_complete/', 
        auth_views.PasswordResetCompleteView.as_view(template_name="home/password_reset_done.html"), 
        name="password_reset_complete"),
]

views.py

class password_reset_view(PasswordResetConfirmView):
    form_class = CaptchaPasswordResetForm
    success_url = reverse_lazy('home:login')  

template

                  <form method="post" class="id_password_reset_form">
                      {% csrf_token %}
                      <p>Please enter your new password</p>
                      <h6 class="mb-0">New Password</h6>
                      <div class="pw_space2"></div>
                      {% render_field form.new_password1 class="form-control" type="password" placeholder="New Password" data-form-field="password"%}
                      <div class="pw_space"></div>
                      <h6 class="mb-0">Repeat New Password</h6>
                      <div class="pw_space2"></div>
                      {% render_field form.new_password2 class="form-control" type="password" placeholder="Repeat New Password" data-form-field="password"%}
                      {{form.errors}}
                      <div class="pw_space2"></div>
                      <button style="background-color:#7231aa; border:#7231aa; color:white;" class="btn btn-secondary " type="submit">Change Password</button>
                      <a style="background-color:#7231aa; border:#7231aa; color:white;" class="btn btn-secondary " target="__blank" href="{% url 'home:profilesettings' %}">Cancel</a>
                </form>  

What are your imports in your forms.py file that make it appear necessary to use forms.forms.CharField and forms.forms.PasswordInput?

from django.contrib.auth import forms
from django.contrib.auth.forms import PasswordResetForm, SetPasswordForm, UserCreationForm
from django.contrib.auth.models import User
from django.contrib.auth.views import PasswordResetConfirmView, PasswordResetView
from django.forms import ModelForm
from django.forms.fields import CharField, EmailField
from StartSite.models import Account
from django.contrib.auth.forms import PasswordChangeForm

Ok, so then you should be able to use:
new_password1 = CharField(..., widget=PasswordInput)
by adding
from django.forms.widgets import PasswordInput

Also, you’re not rendering the attributes from the form field - you already have the class and type attributes specified in the template - you can probably remove that attrs dict making your definition:

new_password1 = CharField(..., widget=PasswordInput)
instead of:
new_password1 = CharField(..., widget=PasswordInput(attrs=...))

And not knowing this third-party library that gives you the render_field tag, it’s probably worth trying this by rendering the field directly to see if it works. If it does, then the issue is either with that library or how you’re using it on this form.

so I tried that but the error still appears so it has to be something with the render field, I tried to show the input without the render thing like

                  <form method="post" class="id_password_reset_form">
                      {% csrf_token %}
                      <p>Please enter your new password</p>
                      <h6 class="mb-0">New Password</h6>
                      <div class="pw_space2"></div>
                      {{ form.new_password1 }}
                      <div class="pw_space"></div>
                      <h6 class="mb-0">Repeat New Password</h6>
                      <div class="pw_space2"></div>
                      {{ form.new_password2 }}
                      {{ form.errors }}
                      <div class="pw_space2"></div>
                      <button style="background-color:#7231aa; border:#7231aa; color:white;" class="btn btn-secondary " type="submit">Change Password</button>
                      <a style="background-color:#7231aa; border:#7231aa; color:white;" class="btn btn-secondary " target="__blank" href="{% url 'home:profilesettings' %}">Cancel</a>
                </form>

But now the input field doesnt show up

But are you still getting that previous error?

On another note - I know these tokens expire, have you verified that this is still a valid token?

nope the previous error is gone

and the token is valid I think this hasnt to do something with the visibility of the input field

As a diagnostic measure, try rendering the entire form in your template:
{{ form }}

If you don’t get two visible fields, then the View is at some point not creating the context expected.

This is what got me looking at the token possibly not being valid. If you look at PasswordResetConfirmView.get_context_data, it checks self.validlink. If that is false, it updates the context with form: None, which would explain the behavior you are seeing.

This self.validlink gets set in the PasswordResetConfirmView.dispatch method, if self.token_generator.check_token(self.user, session_token) is true.

So, if the token isn’t valid, or if it can’t store the current token in session for whatever reason (a part of this process that I skipped over), then one or the other of these tests fail and the form is not to be rendered.

If you wanted to diagnose this in more detail you could override the get_context_data method of your view, call super on it (it returns the context), print the context and then return that context from your method.

okay, so I made a new account now and tried again and it works, also with 2 seperate fields. But I’m not using the render field thing so how can I add classes to the field now?

At this point, now that it appears to have been a token issue, you can go back to trying your original method. I’d be willing to guess that the invalid token is the root cause.

However, if you go back to your original method, a person letting the token expire before using it will get that error.