I made a basic Django form and implemented that into my HTML. In my views.py, I am trying to send an email out, and I know even if I can't send the email, I should still see a successful POST submission and email detail in terminal. However, the page simply refreshes and nothing happens.
views.py snippet:
def ticket(request, room_name):
form_class = TicketForm
if request.method == 'GET':
form = TicketForm()
else:
form = TicketForm(request.POST)
# validating and cleaning data
if form.is_valid():
type_of_issue = form.cleaned_data['type_of_issue']
#a lot of fields are cleaned, irrelevant to question
try:
send_mail("Issue/Feedback for Room " + room_name, message, from_email, ['admin#example.com'])
except BadHeaderError:
return HttpResponse('Invalid header found')
return redirect('index') #index is my homepage separate from my form/ticket page
return render(request, 'ticket.html', context={'room_name': room_name, 'room': room, 'form': form_class, })
ticket.html (where my form is located) snippet:
<form id="ticket-border" class="" method="post">
{% csrf_token %}
<!--a lot of form data goes here, irrelevant to question-->
<input type="submit" value="Submit">
</form>
settings.py snippet that has to do with sending email
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_HOST_USER = 'example#gmail.com'
EMAIL_HOST_PASSWORD = 'notmyrealpassword'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
I've looked at many examples and YouTube videos online, but I seem to be missing why nothing shows up on my console after submitting. The page simply refreshes after hitting submit. It shouldn't be going into my if == GET statement, but I checked that it isn't by changing the criteria and sending it somewhere else, which it didn't do.
Can a fresh pair of eyes help me see the problem?
Edit: Forgot to add, I've also tried adding either
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
or
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
into my settings.py, but it makes no difference. The page still refreshes and nothing shows up in my console or inbox.
Added TicketForm upon request:
class TicketForm(forms.Form):
type_of_issue = forms.ChoiceField(
choices=ISSUE_CHOICES, widget=forms.RadioSelect(), required=True)
first_name = forms.CharField(required=False, widget=forms.TextInput(attrs={
'class': 'form-control', 'id': 'first-name', 'type': 'text', 'name': 'first-name', 'maxlength': '50', 'placeholder': 'First name'}))
last_name = forms.CharField(required=False, widget=forms.TextInput(attrs={
'class': 'form-control', 'id': 'last-name', 'type': 'text', 'name': 'last-name', 'maxlength': '50', 'placeholder': 'Last name'}))
email_address = forms.EmailField(required=False, widget=forms.EmailInput(
attrs={'class': 'form-control', 'type': 'email', 'id': 'email', 'name': 'email', 'placeholder': 'Email address'}))
feedback_or_further_details = forms.CharField(
required=True, widget=forms.Textarea(attrs={'class': 'form-control', 'rows': '5', 'name': 'additional-details', 'placeholder': 'Please enter additional details or your feedback here.'}))
affiliation = forms.ChoiceField(
choices=AFFILIATION_CHOICES, widget=forms.CheckboxSelectMultiple(), required=True)
Related
I'm building a website and I'm trying to make the user able to change his credentials. I've made a form for this:
newUsername = forms.CharField(
label="Enter your new username here*",
required=True,
widget=forms.TextInput(attrs={
'class': 'userChangeCredentials',
'value': "{{ user.username }}"
}))
newEmail = forms.EmailField(
label="Enter your new e-mail adress here*",
required=True,
widget=forms.EmailInput(attrs={
'class': 'userChangeCredentials',
'value': '{{ user.email }}'
}))
newPassword = forms.CharField(
label="Enter your new password here",
required=False,
widget=forms.PasswordInput(attrs={
'class': 'userChangeCredentials',
'value': ''
}))
passwordConfirmation = forms.CharField(
label="Confirm your existing password here*",
required=True,
max_length=256,
widget=forms.PasswordInput(attrs={
'class': 'userChangeCredentials',
'value': ''
}))
The problem is, that the values in the widget dictionary are passed as raw text and I want them to be variables.
This is the resulting page layout:
Do I need to change something inside of HTML?
My HTML:
<form id="UserForm" action="{% url 'user' name=user.username %}" method="POST">
{% csrf_token %}
{{ form|safe }}
<input class="userChangeCredentials" type="submit"></input>
</form>
I tried to make the text raw like this:
widget=forms.EmailInput(attrs={
'class': 'userChangeCredentials',
'value': r'{{ user.email }}'
})
But it didn't help. I searched for a week and I couldn't find any questions of this nature. I've read the official Django form page, but there is nothing about this exact thing.
In this case, I suggest you use the form for the user credentials only (email and username), then use the built-in PasswordChangeView for updating the user password without even creating a form class for it.
As for the raw values, the best way to get them is to inherit the form from the User model.
I am trying to send Gmail with attachments also in Django.
here my views.py:
def index(request):
if request.method != 'POST':
form = EmailForm()
context = {'email_form': form}
return render(request, 'app/index.html', context)
form = EmailForm(request.POST, request.FILES)
if form.is_valid():
subject = form.cleaned_data['subject']
message = form.cleaned_data['message']
email = form.cleaned_data['email']
attach = request.FILES['attach']
try:
mail = EmailMessage(subject, message, settings.EMAIL_HOST_USER, [email])
mail.attach_file(attach.name, attach.read(), attach.content_type)
mail.send()
context = {'message': 'email sended'}
print("email sended")
return render(request, 'app/email_template.html', context)
except:
context = {'message': 'Either the attachment is too big or corrupt'}
print("Either the attachment is too big or corrupt")
return render(request, 'app/index.html', context)
context = {'message': 'Unable to send email. Please try again later'}
return render(request, 'app/index.html', context)
forms.py:
class EmailForm(forms.Form):
email = forms.EmailField()
subject = forms.CharField(max_length=100)
attach = forms.Field(widget = forms.FileInput)
message = forms.CharField(widget = forms.Textarea)
template:
<div class="container-fluid">
<div class="col-xl-4">
<h1>Welcome in django's world</h1>
{{message}}
<form method="POST" action ="." enctype="multipart/form-data">
{% csrf_token %}
<br></br>
{{email_form.as_p}}
<label> </label><label> </label><label> </label>
<input type ="submit" name = "send" value = "Send"/>
</form>
</div>
</div>
Now each and every time I tried to sent mail, it shows Either the attachment is too big or corrupt, which means it goes by the except: block, instead of the try block.I just print the exception msg, it says
__init__() takes from 1 to 2 positional arguments but 5 were given
Now how can I solve this problem such that Gmail will be sent successfully?
I've been trying to code the reset password for my website. However, I keep on running into the 405 error. Google says it's probable that it is a client side error, but I think my html is fine. I'm not sure what else can be causing the error.
I've tried testing the url without the content, but that has not been working either.
routes.py
def send_reset_email(user):
token = user.get_reset_token()
msg = Message('Password Reset Request', sender='noreply#clubsapp.com', recipients=[user.email])
msg.body = f'''To reset your password, visit the following link:
{url_for('reset_token', token=token, _external=True)}
If you did not make this request then simply ignore this email and no change will be made.
'''
mail.send(msg)
#users.route('/reset_request', methods=['GET, POST'])
def reset_request():
if current_user.is_authenticated:
return redirect(url_for('main.home'))
form = RequestResetForm()
if form.validate_on_submit():
user = User.query.filter_by(email=form.email.data).first()
send_reset_email(user)
flash('An email has been sent with instructions to reset your password', 'info')
return redirect(url_for('users.login'))
return render_template('reset_request.html', title='Reset Password', form=form)
#users.route('/reset_password/<token>', methods=['GET, POST'])
def reset_token(token):
if current_user.is_authenticated:
return redirect(url_for('main.home'))
user = User.verify_reset_token(token)
if user is None:
flash('That is an invalid or expired token', 'warning')
return redirect(url_for('reset_request'))
form = ResetPasswordForm()
if form.validate_on_submit():
hashed_password = bcrypt.generate_password_hash(form.password.data).decode('utf-8')
user.password = hashed_password
db.session.commit()
flash(f'Your password has been updated, you are now able to log in!', 'success')
return redirect(url_for('users.login'))
return render_template('reset_token.html', title='Reset Password', form=form)
forms.py
class RequestResetForm(FlaskForm):
email = StringField('Email',
validators=[DataRequired(), Email()],
render_kw={"placeholder":"Enter Email"})
submit = SubmitField('Request Password Reset')
def validate_email(self, email):
user = User.query.filter_by(email=email.data).first()
if user is None:
raise ValidationError('There is no account with that email. You must register first.')
class ResetPasswordForm(FlaskForm):
password = PasswordField('Password',
validators=[DataRequired(), EqualTo('confirm_password', message='Passwords Must Match')],
render_kw={"placeholder":"Create Password"})
confirm_password = PasswordField('Confirm Password',
validators=[DataRequired(), EqualTo('password', message='Passwords Must Match')],
render_kw={"placeholder":"Confirm Password"})
submit = SubmitField('Reset Password')
models.py
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
firstname = db.Column(db.String(15), nullable=False)
lastname = db.Column(db.String(15), nullable=False)
email = db.Column(db.String(60), unique=True, nullable=False)
password = db.Column(db.String(60), nullable=False)
role = db.Column(db.Integer(), nullable=False, default=ROLES['student'])
clubs = db.relationship('Club', secondary=user_club_assoc_table)
def get_reset_token(self, expires_sec=1800):
s = Serializer(app.config['SECRET_KEY'], expires_sec)
return s.dumps({'user_id': self.id})
#staticmethod
def verify_reset_token(token):
s = Serializer(app.config['SECRET_KEY'])
try:
user_id = s.loads(token)['user_id']
except:
return None
return User.query.get(user_id)
def __repr__(self):
return f'{self.firstname} {self.lastname}'
login.html
{% extends "layout.html" %}
{% block content %}
<h1>Login Page</h1>
<div class="content-section">
<form method="POST" action="">
{{ form.hidden_tag() }}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Login</legend>
...(irrelevant content)
<div class="border-top pt-3">
<small class="text-muted">
<a class="ml-2" href="{{ url_for('users.register') }}">Don't Have An Account?</a>
</small>
<small class="text-muted ml-2">
<a class="ml-2" href="{{ url_for('users.reset_request') }}">Forgot Password?</a>
</small>
</div>
{% endblock content %}
It is a simple error. It is not methods=['GET, POST'].
Change to
methods=['GET', 'POST']
Docs
HTTP Methods
Web applications use different HTTP methods when accessing URLs. You
should familiarize yourself with the HTTP methods as you work with
Flask. By default, a route only answers to GET requests. You can use
the methods argument of the route() decorator to handle different HTTP
methods.
from flask import request
#app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
return do_the_login()
else:
return show_the_login_form()
Forms.py
class CheckPostedForm(forms.ModelForm):
posted = forms.BooleanField(required=False, initial=False)
Views.py
postform = CheckPostedForm(request.POST, instance=author)
if postform.is_valid():
postform.save()
else:
print 'Cannot save post form.'
Models.py
posted = models.CharField(max_length=2, blank=True, null=True)
class Meta:
model = TmpPlInvoice
exclude = ['net_amt', 'post_date', 'address', 'particulars', 'pos_code', 'acct', 'cust', 'voucher_id', 'voucher_date', 'post_date']
labels = {
'posted': 'Posted',
}
I want a checkbox which is initially unchecked and based on th value from DB i check/uncheck it. No matter what i do the form always comes out as checked="checked".
print postform gives this,
<tr><th><label for="id_posted">Posted:</label></th><td><input checked="checked" id="id_posted" name="posted" type="checkbox" value="n" required /></td></tr>
I have searched alot every where, the docs say that it should be initially false required=False if we want to apply conditions.
Detail
Views.py
def master_detail_posted(request):
if request.method == 'GET':
author = TmpPlInvoice.objects.get(id=1)
postform = CheckPostedForm(instance=author)
return render(request,'main.html' ,{'postform': postform})
if request.method == 'POST':
author = TmpPlInvoice.objects.get(id=1)
postform = CheckPostedForm(request.POST, instance=author)
print postform
if postform.is_valid():
logger.info('saving post form %s', postform.cleaned_data)
postform.save()
else:
logger.info('post form is not valid %s %s', postform.errors, request.POST)
return render(request,'main.html' ,{'postform': postform})
Template
<div> {{ postform }} </div>
You've hard coded the field in the template. Clearly, Django can't change HTML tags that you've written explicitly.
You need to use Django tags in your template:
<td>{{ form.posted }}</td>
Any help would be greatly appreciated, I'm fairly new to django and developing web apps in general, but up to this point i've been able to basically brute force everything or figure it out on my own; however, this has me stumped.
For some reason it appears that my code is trying to submit the entire html from my field, rather than just the data it contains, and I'm not sure why.
Error message debug shows this:
POST Variable Value
submitter u'ccroffor'
csrfmiddlewaretoken u'P8s3aL4bkyzZJWHPitQVEIFS6Lxt3s6e'
sac_id u'892064'
sr_number u'3-3016786463'
But the Query shows this:
query
'INSERT INTO `autoed_submission` (`sr_number`, `sac_id`, `submission_time`, `completed_time`, `submitter`, `submission_helpful`, `submission_link`) VALUES (\'<textarea cols=\\"40\\" id=\\"id_sr_number\\" name=\\"sr_number\\" placeholder=\\"ex... 3-3010581928\\" rows=\\"1\\">\\r\\n3-3016786463</textarea>\', \'<textarea cols=\\"40\\" id=\\"id_sac_id\\" name=\\"sac_id\\" placeholder=\\"ex... 890046, 890052, ...\\" rows=\\"1\\">\\r\\n892064</textarea>\', \'2013-04-20\', NULL, \'<textarea cols=\\"40\\" id=\\"id_submitter\\" name=\\"submitter\\" placeholder=\\"ex... ccroffor\\" rows=\\"1\\">\\r\\nccroffor</textarea>\', \'U\', \'undefined\')'
Views.py
def mySubView(request):
if request.method == 'POST': #checking request
form = AutoEdForm(request.POST)
if form.is_valid(): #validating form
newSubmission = Submission(sr_number = form['sr_number'], sac_id = form['sac_id'], submitter = form['submitter'], submission_time = datetime.now(tzz)) #formatting form data to db model
newSubmission.save() #saving data to db
return HttpResponseRedirect('/thanks/') #redirecting to thanks page
else:
form = AutoEdForm()
return render_to_response('submission.html', {'form':form,}, context_instance=RequestContext(request))
forms.py
class AutoEdForm(forms.Form):
sr_number = forms.CharField(
max_length=100,
label=u'SR Number',
widget=forms.Textarea(
attrs={
'placeholder': 'ex... 3-3010581928',
'rows': '1',
})
)
sac_id = forms.CharField(
max_length=100,
label=u'Sac ID',
widget=forms.Textarea(
attrs={
'placeholder': 'ex... 890046, 890052, ...',
'rows': '1',
})
)
submitter = forms.CharField(
max_length=100,
label=u'nai-corp Username',
widget=forms.Textarea(
attrs={
'placeholder': 'ex... ccroffor',
'rows': '1',
})
)
def clean(self):
cleaned_data = super(AutoEdForm, self).clean()
return cleaned_data
Relavent html
{% load bootstrap_toolkit %}
<div class="container well">
<form class="form-horizontal" action="" method="post">
{% csrf_token %}
{% for field in form %}
{% include "bootstrap_toolkit/field_horizontal.html" %}
{% endfor %}
<input type="submit" value="Submit" class="btn btn-primary" style="margin-left:180px">
</form>
</div> <!-- /container -->
models.py
class Submission(models.Model):
ED_VALUE = (
('A', 'Averted'),
('N', 'Not Averted'),
('U', 'Unanswered'),
)
sr_number = models.CharField(max_length=100)
sac_id = models.CharField(max_length=100)
submission_time = models.DateField(null=True)
completed_time = models.DateField(null=True)
submitter = models.CharField(max_length=100)
submission_helpful = models.CharField(max_length=100, choices=ED_VALUE, blank=False, default="U")
submission_link = models.CharField(max_length=100, blank=False,default="undefined")
save cleaned data, not form fields
if form.is_valid():
data = form.cleaned_data
newSubmission = Submission(sr_number = data['sr_number'], sac_id = data['sac_id'], submitter = data['submitter'], submission_time = datetime.now(tzz)) #formatting form data to db model