Django form does not render email field - python

I have a simple password reset form where I take a user's email as input. The relevant class is as below. The code works well on my local machine but the exact code doesn't work in production server. Upon inspecting source of rendered view, I see the value field missing.
Expected o/p is
<form method="POST" action="/accounts/password/reset/" class="password_reset">
<ul class="errorlist"><li>The e-mail address is not assigned to any user account</li></ul>
<p><label for="id_email">E-mail:</label> <input id="id_email" name="email" size="30" type="email" value="someemail#gmail.com" /></p>
<input type="submit" value="Reset My Password" />
In production server, value for the email field is missing. I am totally lost why this may be the case. Any pointers will be appreciated.
class PasswordResetView(FormView):
template_name = "account/password_reset.html"
form_class = ResetPasswordForm
success_url = reverse_lazy("account_reset_password_done")
def get_form_class(self):
return get_form_class(app_settings.FORMS,
'reset_password',
self.form_class)
def form_valid(self, form):
form.save()
return super(PasswordResetView, self).form_valid(form)
def get_context_data(self, **kwargs):
ret = super(PasswordResetView, self).get_context_data(**kwargs)
# NOTE: For backwards compatibility
ret['password_reset_form'] = ret.get('form')
# (end NOTE)
return ret
password_reset = PasswordResetView.as_view()

Related

Having two different forms in a Django template

In my project, i have a template where i'm trying to put two forms for different use cases. I've never come across this problem before, so i don't really know where to go from here to use two forms in the same page.
At first i thought of creating another view to handle each form, but i think that this solution would create problems with the rendering of my templates, other than not being sustainable if i should have this problem again with another template.
After making some research, i found a solution but it works for class based views, but i'd like to avoid that since my view is already a function based view, and i would have to make a lot of changes in my code. However, if CBV is the best way to go, i can make the change.
Every advice is appreciated
First field
class FirstForm(forms.ModelForm):
firstfield = forms.CharField()
secondfield = forms.CharField()
class Meta:
model = MyModel
fields = ("firstfield", "secondfield")
def save(self, commit=True):
send = super(FirstForm, self).save(commit=False)
if commit:
send.save()
return send**
Second Form
class SecondForm(forms.ModelForm):
firstfield = forms.FloatField()
secondfield = forms.Floatfield()
thirdfield = forms.CharField()
class Meta:
model = MyModelTwo
fields = ("firstfield", "secondfield", "thirdfield")
def save(self, commit=True):
send = super(SecondForm, self).save(commit=False)
if commit:
send.save()
return send
Template
<h3> First Form </h3>
<form method="post" novalidate>
{% csrf_token %}
{% include 'main/includes/bs4_form.html' with form=form %}
<button type="submit" class="btn btn-danger" style="background-color: red;">SUBMIT</button>
</form>
<h3> Second Form </h3>
<form method="post" novalidate>
{% csrf_token %}
{% include 'main/includes/bs4_form.html' with form=form %}
<button type="submit" class="btn btn-danger" style="background-color: red;">SUBMIT</button>
</form>
views.py
def myview(request):
# if this is a POST request we need to process the form data
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = FirstForm(request.POST)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
# ...
# redirect to a new URL:
send = form.save()
send.save()
messages.success(request, f"Success")
# if a GET (or any other method) we'll create a blank form
else:
form = FirstForm()
return render(request,
"main/mytemplate.html",
context={"form":form})
I have been told to use a context in my view, but i don't know how to integrate it in my view. Is this a doable solution, or is there a better way to do this?
context = {
'first_form': TradingForm(request.POST or None),
'second_form': LimitSellForm(request.POST or None),
}
Here's one approach. Add a name attribute to your buttons, like this:
<button name="button1" type="submit" class="btn btn-danger" style="background-color: red;">SUBMIT</button>
...
<button name="button2" type="submit" class="btn btn-danger" style="background-color: red;">SUBMIT</button>
Then in your view, you can check which form has been submitted by looking for the button name in the post:
def myview(request):
if request.method == 'POST':
if 'button1' in request.POST:
form1 = FirstForm(request.POST)
if form1.is_valid():
# do what needs to be done and redirect
if 'button2' in request.POST:
form2 = form = SecondForm(request.POST)
if form2.is_valid():
# do what needs to be done and redirect
else:
form1 = FirstForm()
form2 = SecondForm()
return render(request, "main/mytemplate.html",
context={'form1': form1, 'form2': form2})
you can use TemplateView instead for normal view function and add this below
def get_context_data(self, **kwargs):
context = {
'first_form': TradingForm(request.POST or None),
'second_form': LimitSellForm(request.POST or None),
}
you can check in the documentation:
https://docs.djangoproject.com/en/2.2/ref/class-based-views/base/#templateview

How to save form data to my model in django

I am creating a newsletter application that requires the user's name and email. However each time I input form data . no change is reflected in the database
models.py
class NewUsers(models.Model):
name = models.CharField(max_length=50)
email = models.EmailField()
date_added = models.DateField(auto_now_add= True)
class Meta:
verbose_name = "NewUser"
verbose_name_plural = "NewUsers"
def __str__(seld):
return self.email
views.py
def newsletter_subscribe(request):
if request.method == 'POST' :
form = NewUserForm(request.POST)
if form.is_valid():
name = form.cleaned_data['name'] #variable to store cleaned data
email = form.cleaned_data['email']
instance = NewUsers(name= name, email = email)
instance.save()
if NewUsers.objects.filter(email = instance.email).exists():
print("Your email is already added to our database")
else:
instance.save()
print("Thank you for subscribing")
else:
form = NewUserForm()#display empty form
context = {'form':form}
template = "index.html"
return render(request ,template ,context )
Here is my template code
template
<form method="post" action="{%url 'subscribe'%}">
{% csrf_token %}
<label for="id_email_field">Name:</label> <input type="text"
name=""
required="" id="">
<label for="id_email_field">E-mail:</label> <input type="email"
name="email_field"
required="" id="id_email_field">
<button id="id_submit" name="submit" value="Subscribe"
type="submit">Subscribe
</button>
</form>
A few things I notice: First, a view must return an HttpResponse object. E.g., I recommend reading up here: https://docs.djangoproject.com/en/2.1/topics/http/views/ and here: https://docs.djangoproject.com/en/2.1/topics/forms/
So, since apparently you didnt get an error thrown at you pointing to this fact, I assume that the request.method never has been equal "POST". Maybe you could try to find out if this is the case? Therefore: could you also provide your template code, please.
Next, your code in the if form.is_valid() is quite contrived. The most natural thing to do here is just calling form.save(). This will create an instance in your db out of the cleaned form-data. In case, you need to do some adjustments, you can extend like this:
instance = form.save(commit=False)
# add some adjustments (instance.foo = bar)
instance.save()
Last, as noted before, you need to return an HttpResponse object which is usually done via
return redirect(url_name, ..)
Edit: since you now added the template code: Try to first let django render the fields for you: https://docs.djangoproject.com/en/2.1/topics/forms/#rendering-fields-manually
and then have a look at the source code of the template. Your name-input-field is missing a name tag and your email-input-field should have name="email" I think. You can django even let the whole form render for you (see docs again...) Without (correct) name tags in the input fields - it will not be possible to send or correctly assign the data inputted by the user.

Django: invalid form

I am new to Django and is currently trying to make a user registration form for my application. Does anyone know why form.is_valid() is returning False?
forms.py
class RegistrationForm(forms.ModelForm):
username = forms.CharField(widget=forms.TextInput)
password = forms.CharField(widget=forms.PasswordInput)
email = forms.CharField(widget=forms.EmailInput)
class Meta:
model = User
fields = ['username', 'password', 'email']
views.py
def registration(request):
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
print "valid"
username = form.cleaned_data['username']
email = form.cleaned_data['email']
password = form.cleaned_data['password']
User.objects.create_user(username=username, email=email, password=password)
user = authenticate(username=username, passsword=password)
if user is not None:
login(request, user)
return redirect('/admin')
else:
# return a blank form
print "invalid"
return render(request, 'registration/register.html', {'form': form})
register.html
<div class="container ">
<form method="post" action=".">
{% csrf_token %}
<h2 class="form-signin-heading">Register</h2>
<input type="text" id="inputUsername" class="form-control" placeholder="Username" required autofocus>
<input type="password" id="inputPassword" class="form-control" placeholder="Password" required>
<input type="email" id="inputEmail" class="form-control" placeholder="Email" required autofocus>
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
</form>
I see that you defined the form in the view, but you are not using it inside the template (register.html). I would have done something more like this:
<div class="container">
<h2 class="form-signin-heading">Register</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign Up</button>
</form>
</div>
Also, if you haven't noticed, your "return render(...)" line is within the else block. And while not necessary, I think it's good practice to define context as a dict and pass it in using context=context in the view or whatever you name it. However, for the case you have here, I'd suggest using a class-based view. It's much cleaner for signing a user up.
from django.views.generic import CreateView
from django.urls import reverse_lazy
class Registration(CreateView):
form_class = RegistrationForm
template_name = 'register.html'
success_url = reverse_lazy('login')
# in the urls.py, set name='login' for the login page
# signing a user up will not grant admin priveleges, that is only done through the
# creation of a super user or if you coded your model to do so (not recommended)
and as for any validation, look into creating a clean(self) method inside the forms.py Like this:
# this will be on the same block as class Meta you defined
# ensures no other user has the username with a different case
def clean(self):
cleaned_data = super(RegistrationForm, self).clean()
username = cleaned_data.get('username')
email = cleaned_data.get('email')
# checks if username is provided and ensures the username is not already in use
if username and User.objects.filter(username__iexact=username).exists():
self.add_error('username', 'A user with that username already exists.')
# checks if email is provided and ensures this email is not already in use
if email and User.objects.filter(email__iexact=email).exists():
self.add_error('email', 'That email address is already in use.')
return cleaned_data
I saw that you were setting some labels in your template, this can be done within the forms.py on the same block as the class Meta and def clean(self) I just provided:
# method to overwrite the form label names
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['username'].label = 'Username'
self.fields['email'].label = 'Email Address'
I have not tested this, I'm going off of memory but I think this is a route similar to your use case, and it's utilizing the Django resources available to you :) Good Luck and I hope this helps!
P.S: You should look into django-crispy-forms since you're using bootstrap.
You haven't given any of your HTML input elements a name attribute. Without that, the browser can't send any data to the server.
Note that if you had used Django itself to produce the fields, they would not only include the name, but would also be populated when the invalid form was redisplayed.

Django: Use same view to process same form on two separate pages

I may be overthinking this one or maybe not. I have a registration form that I want to use on the index page and as a standalone form. For some reason, the standalone form works just fine but the form on the index page gives me a 403 error when it's submitted. I will be using jQuery later on, but I need things to also work without JavaScript.
Renders Sign-Up form similar to Facebook homepage
# views.py snippet
class IndexPageTemplateView(TemplateView): # index page(http://localhost)
template_name = 'fld/index.html'
def get(self, request, *args, **kwargs):
# prevent logged in users from accessing welcome page
if self.request.user.is_authenticated():
return HttpResponse(reverse("member_homepage", args=some_args))
else:
return render_to_response(self.template_name)
# Account view
class AccountCreateView(CreateView): # standalone(http://localhost/signup)
model = Account
form_class = CreateAccountForm
template_name = 'fld2/account_form'
success_url = 'thanks'
def get(self, request, *args, **kwargs):
# prevent logged in users from seeing this form
if self.request.user.is_authenticated():
# get the username of logged in user
...
# redirect to homepage
return HttpResponseRedirect(reverse('some_args', args=(args,)))
else:
# display form to non members
return render(request, self.template_name, {'form': self.get_form_class()})
def form_valid(self, form):
clean = form.cleaned_data
form.instance = form.save()
if form.instance:
try:
# send email
except Account.DoesNotExist:
...
return super(AccountCreateView, self).form_valid(form)
I'm literally using the same exact forms with different action attributes. I've tried swapping the attribute values, using the same attribute values, and using no attribute values. I can't seem to access my view from the index page at all, even when I hard code it in I get the 403 error. Basically a visitor should be able to register on the homepage(like Facebook) or on the sign-up page( like Twitter). I'm thinking that I might have to use signals to make this work.
http://localhost/
<!--index.html snippet-->
<form action="{% url "create_account" %}" method="post">{% csrf_token %}
<input name="username" type="text" required>
<input name="password" type="password" required>
<input name="email" type="email" required>
<input name="signup1" type="submit" value="Create account">
</form>
http://localhost/signup
<!--account_form.html-->
<form action="." method="post">{% csrf_token %}
<input name="username" type="text" required>
<input name="password" type="password" required>
<input name="email" type="email" required>
<input name="signup2" value="Create account" type="submit">
</form>
main urls.py snippet
url(
regex=r'^$',
view=WelcomePageTemplateView.as_view(),
name='index'
),
url(
regex=r'^signup$',
view=include('account.urls'),
# name='signup'
),
url(
regex=r'^(?P<slug>[\w]+)/settings/?',
view=include('account.urls'),
)
account urls.py
url(
regex=r'^$',
view=AccountCreateView.as_view(),
name="create_account"
),
The {% csrf_token %} tag needs access to the request object in the template. You have used render in your AccountCreateView which includes the request by default, but in your IndexPageTemplateView you have used your render_to_response, which does not.
The easiest way to fix the index view is to use render instead of render_to_response.
def get(self, request, *args, **kwargs):
# prevent logged in users from accessing welcome page
if self.request.user.is_authenticated():
return HttpResponse(reverse("member_homepage", args=some_args))
else:
return render(request, self.template_name)
When you override class based views, it's usually a bad idea to override get and post, because you end up duplicating (or breaking) functionality. In your case, it would be better to call super() instead of writing your own code to return a response.
def get(self, request, *args, **kwargs):
# prevent logged in users from accessing welcome page
if self.request.user.is_authenticated():
return HttpResponse(reverse("member_homepage", args=some_args))
else:
return super(IndexPageTemplateView, self).get(request, *args, **kwargs)

problem with accesing multiple values using django

I am new to python and I am using django for student database application .
Student database application must show id, firstname,lastname,subjectnames,marks.
Single student is having multiple subjects and their marks.
I am getting problem with accessing multiple values that student is having multiple subjects and marks.
models.py
class Person(models.Model):
firstname=models.CharField(max_length=50)
lastname=models.CharField(max_length=50)
def __unicode__(self):
return (self.firstname,self.lastname)
class Marksheet(models.Model):
subname=models.CharField(max_length=50)
marks=models.IntegerField(max_length=10)
person=models.ForeignKey(Person)
def __unicode__(self):
return self.subname
views.py
def add_page(request,page_name): # function for creating the new records
p1=None
p2=None
if request.method=='POST':
p1=Person(firstname=request.POST['firstname'],lastname=request.POST['lastname'])
p1.save()
p2=Marksheet(subname=request.POST.getlist('subnames'),person=Person(person_id))
p2.save()
return render_to_response("add.html",{"page_name":page_name})
creating a records I am using form in html which is shown below....
Templates
add.html
<form method="post" action="/newdcl/{{page_name}}/add/" > {% csrf_token %}
First name: <input type="text" name="firstname" /> <br />
Last name: <input type="text" name="lastname" /> <br />
Operating System <input value="os" name="subnames" type="checkbox"><br />
System Programming <input value="sp" name="subnames" type="checkbox"> <br />
Maths <input value="maths" name="subnames" type="checkbox"> <br />
<input type="submit" value="save" >
</form>
Can anyone help me in this????
Your problem seems to lie in your how you try to create Marksheet, you can't assign a list of values to one field like that.
Using your currently formless, scary, no-validation, setup... you can do something like this-
p1=Person(firstname=request.POST['firstname'],
lastname=request.POST['lastname'])
p1.save()
for subname in request.POST.getlist('subnames'):
new = MarkSheet(subname=subname, person=p1)
#no data for marks, must define it to be able to be blank/null
new.save()
You will need to add blank=True, null=True to you marks field in your models.py if you intend to not have any initial mark.
Please look at Making Queries and Forms
In my opinion it should be done by using many-to-many relation in Person, and form should be defined as a form class, because you don't have any validation in your form, and you are writing some html, which could be generated by putting one line of code in template. I would do it like this:
models.py
class Marksheet(models.Model):
subname=models.CharField(max_length=50)
marks=models.IntegerField(max_length=10)
def __unicode__(self):
return self.subname
class Person(models.Model):
firstname=models.CharField(max_length=50)
lastname=models.CharField(max_length=50)
marksheets = models.ManyToManyField(Marksheet)
def __unicode__(self):
return (self.firstname,self.lastname)
forms.py
from models import Person
class PersonForm(ModelForm):
def __init__(self, *args, **kwargs):
super(PersonForm, self).__init__(*args, **kwargs)
# by default m2m relation is rendered with SelectMultiple widget -
# - below line is changing it to checkbox list
self.fields['marksheets'].widget = forms.CheckboxSelectMultiple()
class Meta:
model = Person
views.py
#inside your view function
if request.method == 'POST':
form = PersonForm(request.POST)
if form.is_valid():
form.save()
# pass form to template in render_to_response
add.html
<form method="post" action="/newdcl/{{page_name}}/add/" > {% csrf_token %}
{{ form }}
<input type="submit" value="save" >
</form>

Categories

Resources