Django formset not rendering with django-widget-tweaks - django

I am getting the error 'LoginForm' object has no attribute 'as_widget' whenever I use formset. I really do not know what is the problem as the forms renders properly with normal Django forms. I am trying to see what characteristics in the formset is giving this problem with django-widget-tweaks, but up until now it is hard to figure out. I am getting the error at {% render_field field class="form-control" placeholder=field.label %} in the HTML code.
forms.py:
class LoginForm(ModelForm):
user_login = forms.HiddenInput()
prefix = 'prefix_login'
class Meta:
model = Usermie
fields = ['email', 'password']
widgets = {'password': forms.PasswordInput(),
'email': forms.EmailInput()}
views.py
def manage_articles(request):
article_formset = formset_factory(LoginForm)
book_formset = formset_factory(SignUpForm)
if request.method == 'POST':
if 'login' in request.POST:
login = article_formset(request.POST, request.FILES, prefix='login')
if login.is_valid():
email = request.POST.get('prefix_login-email', '')
password = request.POST.get('prefix_login-password', '')
# Return a user_obj object if the username and password are valid
# otherwise it will return null, the null variable is called None in python
user_obj = auth.authenticate(email=email, password=password)
# return HttpResponse("inside form if condition")
if user_obj is not None:
if user_obj.is_active:
login_usermie(request, user_obj)
return HttpResponseRedirect('/home/')
else:
# pass
return HttpResponse("Your account is inactive.")
elif 'signup' in request.POST:
signup = book_formset(request.POST, request.FILES)
if signup.is_valid():
pass
else:
login = article_formset
signup = book_formset
return render(request, 'usermie/formtest.html', {
'login': login,
'signup': signup,
})
HTML:
<div class="navbar navbar-default nav-links navbar-static-top page-nav">
<div class="container">
<a class="mini-navbar navbar-brand" href="/">
<img src="http://i.imgur.com/GAQSCtB.png" width="25"
alt="Driven Car Sales Logo"
class="img-rounded logo-nav mini-navbar" />
</a>
<ul class="nav navbar-nav nav-form-out pull-right">
<li>
<form class="navbar-form navbar-form-out login" action="" method="POST">
{% csrf_token %}
{% load widget_tweaks %}
{% for field in login %}
{% if login.errors %}
<div class="form-group">
<label class="sr-only" for="{{ field.auto_id }}">{{ field.label }}</label>
{% render_field field class="form-control" placeholder=field.label %}
{% if field == login.password %}
{% for hidden in field.hidden_fields %}
{{ hidden }}
{% endfor %}
{% endif %}
<div class="help-block with-errors">{{ field.errors }}</div>
</div>
{% else %}
<div class="form-group">
<label class="sr-only" for="{{ field.auto_id }}">{{ field.label }}</label>
{% render_field field class="form-control" placeholder=field.label %}
{% if field == login.password %}
{% for hidden in field.hidden_fields %}
{{ hidden }}
{% endfor %}
{% endif %}
</div>
{% endif %}
{% endfor %}
<div class="checkbox">
<label>
<input type="checkbox"> Remember me
</label>
</div>
<button type="submit" name="action" value="login" class="btn btn-default">Sign in</button>
</form>
</li>
</ul>
</div>
<form class="signup" method="POST" action="">
{% csrf_token %}
{{ signup.as_p }}
<button name='action' value='signup' type="submit">Sign up</button>
</form>

login variable in template is a formset. So when you do following:
{% for field in login %}
{% render_field field class="form-control" placeholder=field.label %}
{% endfor %}
you have form as field value and not a field.
Try do this:
{% for form in login %}
{% for field in form %}
{% render_field field class="form-control" placeholder=field.label %}
{% endfor %}
{% endfor %}

Related

Unable to save my form field getting error again and again

I built a simple signup form that will take data as the user will click submit it and will save it in the database. But for some reason, I am able to validate it. I removed all the validations and added them again too. Not sure where I am missing?
it is not saving and giving the error Error Processing Your Request. which is in the else block of the code
Forms.py:
class RegisterForm(UserCreationForm):
email = forms.EmailField(max_length=100,help_text='Enter Email Address', required=True,widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Email'}))
first_name = forms.CharField(max_length=100,help_text='Enter First Name', required=True,widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'First Name'}))
last_name = forms.CharField(max_length=100,help_text='Enter Last Name', required=True,widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Last Name'}))
username = forms.CharField(max_length=100,help_text='Enter Username', required=True,widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Username'}))
password = forms.CharField(max_length=200,help_text='Enter Password', required=True,widget=forms.PasswordInput(attrs={'class': 'form-control', 'placeholder': 'Password'}))
password2 = forms.CharField(max_length=200,help_text='Enter your Password again', required=True,widget=forms.PasswordInput(attrs={'class': 'form-control', 'placeholder': 'Password'}))
#check = forms.BooleanField(required = True)
class Meta:
model = User
fields = [
'username', 'email', 'first_name', 'last_name', 'password', 'password2' #, 'check'
]
Views.py:
def register(request):
if request.method == 'GET': #when you request a form it is in a get request
form = RegisterForm()
context = {'form' : form} #this creates a object which you want to send to the front end
return render(request, 'signup-login.html', context) # here we pushing that form to the html page
if request.method == 'POST': #when you submit a form it is POST request
form = RegisterForm(request.POST)
if form.is_valid():
form.save()
user = form.cleaned_data.get('username')
messages.success(request, 'Account was created for' + user)
return redirect('home_page')
else:
messages.error(request, 'Error Processing Your Request')
context = {'form' : form}
return render(request, 'signup-login.html', context)
return render(request, 'signup-login.html', {})
form HTML(added just the HTML part):
<form action="#" class="p-4 border rounded" method = 'POST'>
{% csrf_token %}
<div class="row form-group">
<div class="col-md-12 mb-3 mb-md-0">
<label class="text-black" for="fname">Email</label>
{{ form.email }} {% comment %}removed the input and added this do for all {% endcomment %}
</div>
{% if form.email.errors %}
{% for error in form.email.errors %}
<div class "alert">
{{ error|escape }}
</div>
{% endfor %}
{% endif %} {% comment %} do this for all {% endcomment %}
</div>
<div class="row form-group">
<div class="col-md-12 mb-3 mb-md-0">
<label class="text-black" for="fname">Password</label>
{{ form.password }}
</div>
{% if form.email.password %}
{% for error in form.password.errors %}
<div class "alert">
{{ error|escape }}
</div>
{% endfor %}
{% endif %}
</div>
<div class="row form-group mb-4">
<div class="col-md-12 mb-3 mb-md-0">
<label class="text-black" for="fname">Re-Type Password</label>
{{ form.password2 }}
</div>
{% if form.password2.errors %}
{% for error in form.password.errors %}
<div class "alert">
{{ error|escape }}
</div>
{% endfor %}
{% endif %}
</div>
<div class="row form-group">
<div class="col-md-12 mb-3 mb-md-0">
<label class="text-black" for="fname">First Name</label>
{{ form.first_name}}
</div>
{% if form.first_name.errors %}
{% for error in form.first_name.errors %}
<div class "alert">
{{ error|escape }}
</div>
{% endfor %}
{% endif %}
</div>
<div class="row form-group">
<div class="col-md-12 mb-3 mb-md-0">
<label class="text-black" for="fname">Last Name</label>
{{ form.last_name}}
</div>
{% if form.last_name.errors %}
{% for error in form.last_name.errors %}
<div class "alert">
{{ error|escape }}
</div>
{% endfor %}
{% endif %}
</div>
<div class="row form-group">
<div class="col-md-12">
<input type="submit" value="Sign Up" class="btn px-4 btn-primary text-white">
</div>
</div>
</form>
The code is displaying so I am assuming there is no error in the html side of it
What I have tried:
I tried several different values again and again but it is not validating.
Thank you so much for helping!!
Updated Answer
Try adding the non-field-errors to your form HTML template and check if there is any message printed.
<form action="." class="p-4 border rounded" method="POST">
{% csrf_token %}
{{ form.non_field_errors }}
<!-- DEBUG -->
{% for field in form %}
{% if field.errors %}{{ field.html_name }}: {{ field.errors }}{% endif %}
{% endfor %}
<!-- DEBUG -->
<!-- ... your markup ... -->
</form>
Docs: https://docs.djangoproject.com/en/4.0/topics/forms/#looping-over-the-form-s-fields
Error in your markup
There is a error in your template code. You are checking for the errors of password2 but printing only the errors for password
{% if form.password2.errors %}
{% for error in form.password.errors %}
<div class "alert">
{{ error|escape }}
</div>
{% endfor %}
{% endif %}
should be
{% if form.password2.errors %}
{% for error in form.password2.errors %}
<div class "alert">
{{ error|escape }}
</div>
{% endfor %}
{% endif %}

'str' object has no attribute 'socialaccount_set' django allauth

I am trying to change my function based views to class based views
I have this profile view as function based:
#verified_email_required
#login_required
def profile(request, username):
if request.method == 'POST':
u_form = UserUpdateForm(request.POST, instance=request.user)
p_form = ProfileUpdateForm(request.POST, request.FILES, instance=request.user.profile)
if u_form.is_valid and p_form.is_valid():
u_form.save()
p_form.save()
message = messages.success(request, f'Your profile has been updated')
return redirect('profile', username=username)
else:
u_form = UserUpdateForm(instance=request.user)
p_form = ProfileUpdateForm(instance=request.user.profile)
try:
profile = User.objects.get(username=username)
except User.DoesNotExist:
message = messages.warning(request,f'Profile not found for {username}')
return redirect('home')
profile = ''
all_post_by_user = Log.objects.filter(author__username=username)
context = {
'u_form' : u_form,
'p_form' : p_form,
'profile' : profile,
'all_post_by_user' : all_post_by_user
}
return render(request, 'users/profile.html', context)
And this is my class based for the same :
class ProfileDetailView(DetailView):
model = Profile
template_name = "users/profile.html"
context_object_name = 'profile'
def get_object(self):
username = self.kwargs.get('username')
view_profile = Profile.objects.get(user__username=username)
So, I am getting this error:
profile.html:
{% extends 'log/base.html' %}
{% block content %}
{% load socialaccount %}
{% get_social_accounts profile as accounts %}
{%load crispy_forms_tags %}
<title>Error logger - Profile {{ profile.username }}</title>
<div id='profile' class="content-section card p-4">
<div class="media">
{% if profile.username == user.username %}
{% if accounts %}
<img class='rounded-circle account-img' src="{{ profile.socialaccount_set.all.0.get_avatar_url }}" />
{% else %}
<img class="rounded-circle account-img" src="{{ profile.profile.avatar.url }}">
{% endif %}
{% else %}
{% if accounts %}
<img class='rounded-circle account-img' src="{{ profile.socialaccount_set.all.0.get_avatar_url }}" />
{% else %}
<img class="rounded-circle account-img" src="{{ profile.profile.avatar.url }}">
{% endif %}
{% endif %}
<div class="media-body">
<h2 class="account-heading">{{profile.username}}</h2>
<p >{{profile.email}}</p>
<p>Created on: {{ profile.profile.created }}</p>
{% if profile.username == user.username %}
<p>Last updated on : {{ profile.profile.updated }}</p>
{% endif %}
</div>
</div>
<!-- FORM HERE -->
{% if profile.username == user.username %}
<form method='POST' autocomplete="off" enctype="multipart/form-data" >
{% csrf_token %}
<fieldset class='form-group'>
<legend class='border-bottom mb-4'>Update Profile</legend>
{{ u_form | crispy }}
{{ p_form | crispy }}
</fieldset>
<div class='form-group'>
<button class='btn btn-outline-info' type='submit'>Update</button>
</div>
</form>
{% endif %}
<div class="container border-top mt-4 pt-4">
<legend>Posts</legend>
{% for i in all_post_by_user %}
<div id="you-want-lazyload" data-lazyload="<p>Anything you want to lazyload</p>" class='m-4'>
<div class="container main m-4" style="width: 50vw;">
<a class='link' href="{% url 'log-detail' i.slug %}"><h2 >{{ i.title }}</h2></a>
<p>{{ i.content }}</p>
<p class='small'>{{ i.created }}</p>
</div>
</div>
{% endfor %}
</div>
</div>
{% endblock content %}
How to solve the error that I am getting?
I am using django allauth for social login with google
Also can someone explain why I have to query it is user__username=username?
Thanks
Ok, so the error tells us that you've got a string somewhere you aren't expecting it, because you're trying to access an attribute of a variable that is provided by allauth.
This is happening due to your exception handling here;
try:
profile = User.objects.get(username=username)
except User.DoesNotExist:
message = messages.warning(request, f'Profile not found for {username}')
return redirect('home')
profile = ''
If a user doesn't exist, you set profile to an empty string and that gets passed in the context.
So I'd change this a little bit, to fix this error and also to avoid the confusion of looking up User objects and calling them profile (I'd assume a User to be called user or similar)
try:
user = User.objects.get(username=username)
except User.DoesNotExist:
message = messages.warning(request, f'User not found for {username}')
return redirect('home')
user = None
all_post_by_user = Log.objects.filter(author__username=username)
context = {
'u_form' : u_form,
'p_form' : p_form,
'user' : user,
'all_post_by_user' : all_post_by_user
}
return render(request, 'users/profile.html', context)
profile.html:
{% extends 'log/base.html' %}
{% load crispy_forms_tags socialaccount %}
{% block content %}
{% get_social_accounts profile as accounts %}
<title>Error logger - Profile {{ profile.username }}</title>
<div id='profile' class="content-section card p-4">
<div class="media">
{% if profile and profile.username == user.username %}
{% if accounts %}
<img class='rounded-circle account-img' src="{{ profile.socialaccount_set.all.0.get_avatar_url }}" />
{% else %}
<img class="rounded-circle account-img" src="{{ profile.profile.avatar.url }}">
{% endif %}
{% else %}
{% if accounts and profile %}
<img class='rounded-circle account-img' src="{{ profile.socialaccount_set.all.0.get_avatar_url }}" />
{% elif profile %}
<img class="rounded-circle account-img" src="{{ profile.profile.avatar.url }}">
{% endif %}
{% endif %}
{% if profile %}
<div class="media-body">
<h2 class="account-heading">{{profile.username}}</h2>
<p >{{profile.email}}</p>
<p>Created on: {{ profile.profile.created }}</p>
{% if profile.username == user.username %}
<p>Last updated on : {{ profile.profile.updated }}</p>
{% endif %}
</div>
</div>
<!-- FORM HERE -->
{% if profile.username == user.username %}
<form method='POST' autocomplete="off" enctype="multipart/form-data" >
{% csrf_token %}
<fieldset class='form-group'>
<legend class='border-bottom mb-4'>Update Profile</legend>
{{ u_form | crispy }}
{{ p_form | crispy }}
</fieldset>
<div class='form-group'>
<button class='btn btn-outline-info' type='submit'>Update</button>
</div>
</form>
{% endif %} <!-- end username check -->
{% endif %} <!-- end profile check -->
<div class="container border-top mt-4 pt-4">
<legend>Posts</legend>
{% for i in all_post_by_user %}
<div id="you-want-lazyload" data-lazyload="<p>Anything you want to lazyload</p>" class='m-4'>
<div class="container main m-4" style="width: 50vw;">
<a class='link' href="{% url 'log-detail' i.slug %}"><h2 >{{ i.title }}</h2></a>
<p>{{ i.content }}</p>
<p class='small'>{{ i.created }}</p>
</div>
</div>
{% endfor %}
</div>
</div>
{% endblock content %}

How to show django form in django template?

I am trying to create a form using django and css.
views.py
from django.shortcuts import render
from .forms import ContactForm
def home(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
pass
else:
form = ContactForm()
return render(request, 'home.html', {'form':form})
forms.py
from django import forms
class ContactForm(forms.Form):
name = forms.CharField(max_length = 30)
email = forms.EmailField(max_length = 254)
message = forms.CharField(max_length = 2000, widget = forms.Textarea(),help_text = "Write Your Message here")
def clean(self):
cleaned_data = super(ContactForm, self).clean()
name = cleaned_data.get('name')
email = cleaned_data.get('email')
message = cleaned_data.get('message')
if not name and not email and not message:
raise forms.ValidationError('You have to write something!')
When I try to add the form to my html page like the following it doesn't show up. Just the button shows up, no form fields -
{% extends 'store/main.html' %}
{% load static %}
{% block content %}
<h3>Store</h3>
<form method = "post" novalidate>
{% csrf_token %}
{{ form }}
<button type='submit'>Submit</button>
</form>
{% endblock content %}
If I do css form instead it obviously show up the way it should.
{% extends 'store/main.html' %}
{% load static %}
{% block content %}
<h3>Store</h3>
<form>
<label for="fname">First Name</label>
<input type="text" id="fname" name="fname">
<button type='submit'>Submit</button>
</form>
{% endblock content %}
So I decided to add the form fields individually to the css form. Where does the {{form.name}} or {{form.email}} tag go?
EDIT:
Hey Vivek, the contact form code is this -
class ContactForm(forms.Form):
name = forms.CharField(max_length = 30)
email = forms.EmailField(max_length = 254)
message = forms.CharField(max_length = 2000, widget = forms.Textarea(),help_text = "Write Your Message here")
The html template looks like this-
{% extends 'store/main.html' %}
{% load static %}
{% block content %}
<h3>Store</h3>
<form method = "post" novalidate>
{% csrf_token %}
<label class="float-left" for="name">Name</label>
{{ form.name }}
<button type='submit'>Submit</button>
</form>
{% endblock content %}
Thanks for any input.
Accessing form fields individually will make you to render the form errors individually as well. {{form}} encapsulates everything:- Form fields , errors, non_field_errors..So if you have to access the fields individually do not forget to add the form errors.
I have written a sample code which will server the purpose.
{% csrf_token %}
{% if form.errors %}
<div class="alert alert-danger" style="text-align:left">
<ul>
{% for field in form %}
{% for error in field.errors %}
<li><strong>{{ error|escape }}</strong></li>
{% endfor %}
{% endfor %}
{% for error in form.non_field_errors %}
<li><strong>{{ error|escape }}</strong></li>
{% endfor %}
</ul>
</div>
{% endif %}
<div class="form-row">
<div class="col-md-4 mb-3">
<label class="float-left" for="id_name">Name</label>
{{ form.name }}
</div>
<div class="col-md-8 mb-3">
<label class="float-left" for="id_email">Email ID</label>
{{ form.email }}
</div>
</div>
<br>
<input type="submit" class="btn btn-primary" value="Pay" id="submit">
</form>

My django form is not working when i iterate through it using for loop

Basically if I tried to use this code
{% for field in form %}
<div class="input">
<label for="" class="labelinput">{{field.label}}</label>
{{field}}
</div>
{% endfor %}
the form data wont make it pass is_valid().But it renders out the form fine. and if I use this code
<form action="" method="post"> {% csrf_token %}
{{form}}
<input type="submit" value="">
it worked perfectly fine. How do I get the first code to work because I want to add classes between the label and the input field
and here's my view
def booklist_view(request):
bkff = BookListForm()
if request.method == 'POST':
bkff = BookListForm(request.POST)
if bkff.is_valid():
bkff.save()
bkff = BookListForm()
context = {
'form': bkff,
}
return render(request, 'booklist1st/booklist.html', context)
Please try this.
views.py
def booklist_view(request):
form = BookListForm(request.POST or None)
if request.method == 'POST':
if form.is_valid():
form.save()
context = {'form': form }
return render(request, 'booklist1st/booklist.html', context)
Here we render field according according to field type(hidden_fields,visible_fields).
html template:
<form method="post">
{% csrf_token %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% for field in form.visible_fields %}
<div class="input">
{{field.label}}
{{field}}
</div>
{% endif %}
<input class="btn btn-primary" type="submit" name="add_book" value="Save and add book" />
</form>
You need to specify each field relate data like for=, id=, etc. To have maximum control over how your form is rendered, specify each field and control its style, for example, as we can't see your Form definition, this is an example on how it would be for a title field:
<form method="post">{% csrf_token %}
{# Include the hidden fields #}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{# Include the visible fields #}
{{ form.non_field_errors }}
{{ form.title.errors }}
<label for="{{ form.title.id_for_label }}">Title</label>
{{ form.title }}
{% if form.title.help_text %}
<small id="titleHelp">{{ form.title.help_text|safe }}</small>
{% endif %}
</div>
<input class="btn btn-primary" type="submit" name="add_book" value="Save and add book" />
</form>
<form method="post">
{% csrf_token %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% for field in form.visible_fields %}
<div class="input">
<label for="" class="label">{{field.label}}</label>
{{field}}
</div>
{% endfor %}
<input class="btn btn-primary" type="submit" name="add_book" value="Save and add book" />
</form>
View.py
from django.views.decorators.csrf import csrf_protect
#csrf_protect
def booklist_view(request):
bkff = BookListForm()
if request.method == 'POST':
bkff = BookListForm(request.POST)
if bkff.is_valid():
bkff.save()
context = {
'form': bkff,
}
return render(request, 'booklist1st/booklist.html', context)

Why forms.ModelForm loss data from FileField in Django 2.0

I have a CustomForm that extends from forms.ModelForm and use a FileField like this:
avatar = forms.FileField(required=False, label="avatar")
When I save the model, everything works, and file was saved in directory. But when I re-enter in view (file is over there), and just click in "Save", the file is lost. My views.py is:
def edit_user(request):
if request.method == "POST":
form = CustomForm(request.POST, request.FILES)
if form.is_valid():
user = form.save(commit=False)
user.save()
else:
user= User\
.objects\
.get_or_create(user=request.user,
defaults={'name':request.user.first_name,
'email':request.user.email})
form = CustomForm(instance=user)
return render(request, 'user.html', {'form':form, 'user':user})
I'm using Python 3.6 and Django 2.0.
HTML:
<form method="post" action="{% url 'myprofile' %}"
class="form-horizontal" role="form"
enctype="multipart/form-data">
{% csrf_token %}
{% for field in form %}
<div class="form-group row">
<label class="col-2 col-form-label">{{ field.label_tag }}</label>
<div class="col-10">
{% render_field field class+="form-control" %}
{% if field.errors %}
<br/>
{% for error in field.errors %}
<div class="alert alert-danger alert-dismissable">
<p><strong>{{ error|escape }}</strong></p>
</div>
{% endfor %}
{% endif %}
</div>
{% if field.help_text %}
<p class="help">{{ field.help_text|safe }}</p>
{% endif %}
</div>
{% endfor %}
<input type="submit" value="{% trans 'save' %}" >
</form>