I tried to use 6 different tutorials to get this done, but all of them gave different variations so I'm really frustrated at the pace I'm making...
I think I'm nearing the last few steps but I need some help. Here is the code I have in my Django project:
# -- settings.py--
EMAIL_BACKEND = 'django.core.mail.backends.stmp.EmailBackend'
EMAIL_HOST = 'http://smtp.gmail.com/'
EMAIL_HOST_USER = 'a spare Gmail I have'
EMAIL_HOST_PASSWORD = 'the password'
EMAIL_USE_TLS = False
EMAIL_PORT = 465
..
# -- views.py --
# (assumed relevant imports are imported)
class ContactView(FormView):
template_name = 'CONTACT.html'
form_class = ContactForm
success_url = 'Success!'
context_vars = {
'example_name_f': 'Adam',
'example_name_l': 'Smith',
'example_email': 'smith.a#gmail.com',
'example_subject': 'Sales proposal',
'example_text': 'Hi Mark, I have a sales proposal for you!',
}
def get(self, request):
return render(request, 'CONTACT.html', ContactView.context_vars)
def contact(self, request):
if request.method == 'POST':
form = self.form_class(data=request.POST)
if form.is_valid():
time = request.POST.get('time', '')
first_name = request.POST.get('first_name', '')
last_name = request.POST.get('last_name', '')
email_address = request.POST.get('email_address', '')
subject = request.POST.get('subject', '')
text = request.POST.get('text', '')
send_mail(subject, text, email_address,
['999#outlook.com'], fail_silently=False)
return redirect('CONTACT-done.html') # CONTACT-done is a temporary success screen
return render(request, 'CONTACT.html', ContactView.context_vars)
The relevant portion of HTML:
<div class="container-fluid" style="width: 100%; height: 100%">
<form action="" method="post">
<label for="first-name">First Name</label>
<input id="first-name" name="first-name" type="text" placeholder="{{ example_name_f }}">
<!-- Note: placeholder vs value attributes similar -->
<!-- id is for HTML, name is for views.py -->
<label for="last-name">Last Name</label>
<input id="last-name" name="last-name" type="text" placeholder="{{ example_name_l }}">
<!-- Its unnecessary to use context vars for placehoder text -->
<label for="email">Email Address</label>
<input id="email" name="email" type="email" placeholder="{{ example_email }}" required>
<label for="subject">Subject</label>
<input id="subject" name="subject" type="text" placeholder="{{ example_subject }}">
<label for="text">Message:</label>
<input id="text" name="text" type="text" placeholder="{{ example_text }}" required>
<input type="submit" value="Send">
</form>
</div>
Some tutorials recommended a {{ form.as_p }} approach in HTML but some just did the basic HTML style as I did above. Not sure what to do from here.
Clicking send on my website gives a 403 CSRF verification failed. Request aborted.
Please explain in as simple a way as possible, I'm not brand new to programming but I'm not a CS person either. Thanks.
you need the CSRF token:
<form ...>
{% csrf_token %}
...
</form>
As in this official documentation example:
Related
I'm creating a password generator app. The app is working and stores the value on db.
The problem is whenever I refresh, the form resubmits and takes the previous value and stores.
Also, I want to show the email and password on the same page.
Whenever I refresh, I want to show an empty form with empty fields.
Views.py
def home(request):
if request.method=='POST':
inputemail = request.POST.get('InputEmail')
gen = ''.join(random.choices((string.ascii_uppercase+string.ascii_lowercase+string.digits+string.punctuation), k=10))
newpass = Item(email=inputemail,encrypt=gen)
newpass.save()
return render(request,'home.html',{"gen":gen})
return render(request,'home.html',{})
Home.html
<form method = 'post' id='pass-form' >
{% csrf_token %}
<div class="mb-3">
<label for="exampleInputEmail1" class="form-label">Email address</label>
<input type="email" class="form-control" name="InputEmail" >
<div id="emailHelp" class="form-text">We'll never share your email with anyone else.</div>
</div>
<button type="submit" name = "submit" class="btn btn-primary">Generate Password</button><br><br>
</form>
<div class="mb-3">
<label for="exampleInputPassword1" class="form-label">Generated Password</label>
<input type="text" id="InputPassword" name = "genpassword" value = {{gen}} >
</div>
Urls.py
urlpatterns = [
path('',views.home,name='home'),
]
According to docs:
you should always return an HttpResponseRedirect after successfully dealing with POST data. This tip isn’t specific to Django; it’s good web development practice in general.
So you should make another page to show generated password, which will take submitted instance id of Item model created in home view so:
def home(request):
if request.method=='POST':
inputemail = request.POST.get('InputEmail')
gen = ''.join(random.choices((string.ascii_uppercase+string.ascii_lowercase+string.digits+string.punctuation), k=10))
newpass = Item(email=inputemail,encrypt=gen)
newpass.save()
return redirect('success', args=(newpass.pk))
return render(request,'home.html',{})
def success(request, pk):
item_obj = get_object_or_404(Item, pk=pk)
return render(request,'success.html', {'gen':item_obj.encrypt})
urls.py
urlpatterns=[
path('',views.home,name='home'),
path('success/<int:pk>/',views.success,name='success')
]
success.html
<body>
<h2>The form is successfully submitted.</h2>
<br>
<div class="mb-3">
<label for="exampleInputPassword1" class="form-label">Generated Password</label>
<input type="text" id="InputPassword" name="genpassword" value={{gen}} >
</div>
Again go to password generator page.
</body>
Another possible solution
You can make email field required in Html form and then hard refresh the page after submitting the form using Javascript's submit event so the template:
<form method='POST' id='pass-form'>
{% csrf_token %}
<div class="mb-3">
<label for="exampleInputEmail1" class="form-label">Email address</label>
<input type="email" class="form-control" name="InputEmail" required>
<div id="emailHelp" class="form-text">We'll never share your email with anyone else.</div>
</div>
<button type="submit" class="btn btn-primary">Generate Password</button><br><br>
</form>
<div class="mb-3">
<label for="exampleInputPassword1" class="form-label">Generated Password</label>
<input type="text" id="InputPassword" name = "genpassword" value ={{gen}} >
</div>
<script type='text/javascript'>
let form = document.getElementById('pass-form');
addEventListener('submit', (event) => {
location.reload(true); // hard refreshed
console.log('hard refreshed')
});
</script>
Note: Then also there are certain browsers like Microsoft Edge which gives pop up as Resubmit the form? in which they mention The page you're looking for used information that you entered. Returning to the page might trigger a repitition of any action you took there. Do you want to continue?
The moment you click on continue it creates duplicacy of records, so I think as docs mentions the first approach is better.
Views.py
def contact(request):
if request.method == 'POST':
message_name = request.POST['message-name']
message_email = request.POST['message-email']
message = request.POST['message']
# send an email
send_mail(
'Message from ' + message_name, # subject
message, # message
message_email, # from email
['myEmailId#gmail.com'], # to email
)
settings.py
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_HOST_USER = 'myEmailId#gmail.com'
EMAIL_HOST_PASSWORD = '<myaccount app password>'
EMAIL_USE_TLS = True
contact.html
<form action="{% url 'contact' %}" method="POST" class="bg-light p-5 contact-form">
{% csrf_token %}
<div class="form-group">
<input type="text" name="message-name" class="form-control" placeholder="Your Name">
</div>
<div class="form-group">
<input type="email" name="message-email" class="form-control" placeholder="Your Email">
</div>
<div class="form-group">
<textarea name="message" id="" cols="30" rows="7" class="form-control" placeholder="Message">
</textarea>
</div>
<div class="form-group">
<input type="submit" value="Send Message" class="btn btn-primary py-3 px-5">
</div>
</form>
I have created this code for the contact-me page. Now when user Submits the Contact Form which has the fields message-name, message-email and message, I receive the email where FROM and TO are both my email-id.
It is not retrieving the users email. But rest of the fields are working fine.
Even Tested with DebuggingServer and that works as expected. Seems like I am missing something in the setting.py because that is the one file I have changed.
I don't understand where I am going wrong. Any help appreciated.
You should not be using user's email address in from field. It should be the address that is in your control. By using user's email in from field, it implies that the email was sent by the user which is not the case, and should never happen.
Moreover, gmail would not allow you to send email from anyone else's email address from your account.
I would suggest you to use your own email address and have user's email address in the message.
I have created a Django application in which i have a signup page which asks a user to upload their profile picture.
When I'm uploading the profile picture through the Django admin panel, the images are being uploaded to the correct path and are being displayed in the website. However, the error comes when I directly select the image to upload when signing up and then When I click on the uploaded image in Django admin it shows page not found and the path to the image is being showed as C:\Users\hp\Workspace\findem\media\image.jpg
Settings.py
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'findem/static')
]
# media folder settings
MEDIA_ROOT = os.path.join(BASE_DIR , 'media').replace('\\', '/')
MEDIA_URL = '/media/'
User Model
class UserProfile(AbstractBaseUser, PermissionsMixin):
"""Represents a user profile inside our system"""
email = models.EmailField(max_length=255, unique=True)
name = models.CharField(max_length=255, default=profile_pic)
profile_picture = models.ImageField(upload_to='photos/profile_pictures/', default='photos/User.jpg')
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
highest_degree_earned = models.CharField(max_length=255, blank=False)
college_name = models.CharField(max_length=255, blank=False)
graduation_year = models.IntegerField(default=2020, blank=False)
Template :
<form class="needs-validation" novalidate autocomplete="off"
action="{% url 'signup' %}", method="POST" >
{% csrf_token %}
<div id="Personal_Information">
<h5 class="loginSignup">Personal Information</h5>
<div class="form-group row">
<label for="inputprofile" class="col-sm-2 col-form-label">Profile Picture</label>
<div class="col-sm-5">
<div class="input-group">
<div class="custom-file">
<input type="file" accept="image/png, image/jpeg, image/gif" class="custom-file-input" id="inputprofile" name="inputprofile">
<label class="custom-file-label" for="inputprofile" aria-describedby="inputprofile">Choose file</label>
</div>
</div>
</div>
</div>
<div class="form-group required row">
<label for="inputname" class="col-sm-2 col-form-label">Full Name <span id="required-field">*
</span>
</label>
<div class="col-sm-5">
<input type="text" class="form-control" name="inputname" id="inputname" placeholder="Enter Your Full Name" required>
<div class="valid-feedback">Looks good!</div>
<div class="invalid-feedback">Please enter your full name.</div>
</div>
</div>
<div class="form-group row">
<label for="inputemal" class="col-sm-2 col-form-label">Email <span id="required-field">*</span></label>
<div class="col-sm-5">
<input type="email" class="form-control" id="inputEmail" name="inputEmail" placeholder="Enter a Valid Email Address" required>
<div class="valid-feedback">Looks good!</div>
<div class="invalid-feedback">Please provide a valid email.</div>
</div>
</div>
<div class="form-group row">
<label for="inputPassword" class="col-sm-2 col-form-label">Password <span id="required-field">*</span></label>
<div class="col-sm-5">
<input type="password" class="form-control" id="inputPassword" name="inputPassword" placeholder="Choose a Password" required>
<div class="valid-feedback">Looks good!</div>
<div class="invalid-feedback">Please chose a valid password.</div>
</div>
</div>
<button type="submit" class="btn btn-success mt-3" id="loginButton">Sign Up</button>
</form>
view :
def signup(request):
"""View for Signing-up into the system"""
if request.method == 'POST':
# Get form value
profile_picture = request.POST.get('inputprofile')
name = request.POST.get('inputname')
email = request.POST['inputEmail']
password = request.POST['inputPassword']
highest_degree_earned = request.POST['inputDegree']
college_name = request.POST['CollegeName']
graduation_year = request.POST['inputGradYear']
skill_1 = request.POST['upload_skill1']
skill_2 = request.POST.get('upload_skill2', '')
skill_3 = request.POST.get('upload_skill3', '')
skill_4 = request.POST.get('upload_skill4', '')
skill_5 = request.POST.get('upload_skill5', '')
skill_6 = request.POST.get('upload_skill6', '')
join_date = datetime.now()
# Check Username
if UserProfile.objects.filter(name=name).exists():
messages.error(request, "That Name already taken")
return redirect('signup')
# Check email
else:
if UserProfile.objects.filter(email=email).exists():
messages.error(request, "That email is being used")
return redirect('signup')
else:
# Looks Good
user = UserProfile.objects.create_user(profile_picture=profile_picture, name=name, email=email,
password=password, highest_degree_earned=highest_degree_earned, college_name=college_name,
graduation_year=graduation_year, skill_1=skill_1, skill_2=skill_2, skill_3=skill_3, skill_4=skill_4,
skill_5=skill_5, skill_6=skill_6, join_date=join_date)
# #Login after register
# auth.login(request, user)
user.save()
messages.success(request, "You are now registered and can log in")
return redirect('login')
else:
return render(request, 'pages/signup.html')
Change your form tag to be be like this :
<form class="needs-validation" novalidate autocomplete="off"
action="{% url 'signup' %}", method="POST" enctype="multipart/form-data">
add request.FILES to profile_picture like that :
profile_picture = request.FILES.get('inputprofile') or None
Than in your create request you do that :
else:
if UserProfile.objects.filter(email=email).exists():
messages.error(request, "That email is being used")
return redirect('signup')
else:
# Looks Good
if profile_picture != None
user = UserProfile.objects.create_user(profile_picture=profile_picture, name=name, email=email,
password=password, highest_degree_earned=highest_degree_earned, college_name=college_name,
graduation_year=graduation_year, skill_1=skill_1, skill_2=skill_2, skill_3=skill_3, skill_4=skill_4,
skill_5=skill_5, skill_6=skill_6, join_date=join_date)
else:
user = UserProfile.objects.create_user(name=name, email=email,
password=password, highest_degree_earned=highest_degree_earned, college_name=college_name,
graduation_year=graduation_year, skill_1=skill_1, skill_2=skill_2, skill_3=skill_3, skill_4=skill_4,
skill_5=skill_5, skill_6=skill_6, join_date=join_date)
For the default picture try to change it to this :
profile_picture = models.ImageField(upload_to='photos/profile_pictures/', default='/media/photos/User.jpg')
In the HTML form, you need to use.
enctype="multipart/form-data"
Without that, the file is not sent to the server.
Add this tag to your form
<form method="post" enctype="multipart/form-data">
....
</form>
and to get the files at django part use request.FILES.get('filename') in your view
profile_picture = request.FILES.get('inputprofile')
So I'm trying to make a form with some data and an upload field. Django docs doesn't provide any good tutorial of doing this without forms.py. I don't want to use that.
I tried to adapt their tutorial with forms.py (https://docs.djangoproject.com/en/2.2/topics/http/file-uploads/) with my project but I'm getting an error.
"InMemoryUploadedFile' object is not callable"
I've tried searching it on google but I didn't find this error.
I obviously miss something, because when I used to do file uploads with Node I had to do more things, like setting file storage ect.
I just don't know how to handle this in django. So what am I missing and why do I get this error?
views.py
def incarcarecv(req):
context = {
'title': "title"
}
if req.method == 'POST':
nume = req.POST['nume']
prenume = req.POST['prenume']
telefon = req.POST['telefon']
email = req.POST['email']
CV = req.FILES['CV']
cvUpload = CV(solicitant = req.user, nume=nume, prenume=prenume, telefon=telefon, emailContact=email, CV=CV)
return render(req, "../templates/pagini/incarcare-cv.html", context)
models.py
class CV(models.Model):
solicitant = models.ForeignKey(User, on_delete=models.CASCADE)
dataUploadCV = models.DateField(auto_now_add=True)
nume = models.CharField(max_length=12)
prenume = models.CharField(max_length=12)
telefon = models.CharField(max_length=12)
emailContact = models.EmailField(max_length=40)
CV = models.FileField(upload_to='documents/%d/%m/%Y')
rezolvata = models.BooleanField(default=False)
def __str__(self):
return self.solicitant
html
{% extends 'base.html' %}
{% load static %}
{% block content %}
<div class="container container-centru">
<h1 class="heading-contact">Incarca CV</h1>
{% include 'partials/_alerts.html' %}
<form action="{% url 'incarcarecv' %}" method="POST" class="form-contact" enctype="multipart/form-data">
{% csrf_token %}
<div class="form-group">
<label for="inputnume" class="email-contact">Nume</label>
<input type="text" name="nume" class="form-control" id="inputnume" aria-describedby="emailHelp" placeholder="Introdu nume">
</div>
<div class="form-group">
<label for="inputprenume" class="email-contact">Prenume</label>
<input type="text" name="prenume" class="form-control" id="inputprenume" aria-describedby="emailHelp" placeholder="Introdu prenume">
</div>
<div class="form-group">
<label for="inputtelefon" class="email-contact">Telefon</label>
<input type="text" name="telefon" class="form-control" id="inputtelefon" aria-describedby="emailHelp" placeholder="Introdu telefon">
</div>
<div class="form-group">
<label for="inputemail" class="email-contact">Email</label>
<input type="email" name="email" class="form-control" id="inputemail" aria-describedby="emailHelp" placeholder="Introdu email">
</div>
<div class="form-group">
<label for="inputcv" class="email-contact">CV</label>
<input type="file" name="CV" class="form-control" id="inputemail" aria-describedby="emailHelp">
</div>
<div class="form-group form-group-custom">
<input type="submit" value="Trimite" class="btn btn-secondary btn-block btn-login-custom">
<input type="submit" value="Resetează câmpurile" class="btn btn-secondary btn-block btn-reset-custom">
</div>
</form>
</div>
{% endblock %}
Let me translate: name = last name, prenume = first name, telefon = phone.
So how can I handle files in this situation and without using forms.py? As I said, django doesn't provide any tutorial on this.
Thanks!
In your view, you shadow the CV model, by defining a local variable named CV. Indeed, you write:
CV = req.FILES['CV']
So in this view, CV does not refer to the model CV, but to the file, later you then call the constructor of the model CV(..), but you thus call the file handler instead.
def incarcarecv(req):
context = {
'title': 'title'
}
if req.method == 'POST':
nume = req.POST['nume']
prenume = req.POST['prenume']
telefon = req.POST['telefon']
email = req.POST['email']
cv = req.FILES['CV']
cv_upload = CV(
solicitant=req.user,
nume=nume,
prenume=prenume,
telefon=telefon,
emailContact=email,
)
cv_upload.cv.save(cv.name, cv)
cv_upload.save()
return render(req, '../templates/pagini/incarcare-cv.html', context)
You will need to cv_upload.save(), since otherwise you construct a CV object, but you did not store in in the database.
That being said, I strongly advise you to use a Form, here it looks like a simple ModelForm will be sufficient. A form also can validate the input, and produce errors that you can send back to the user about what is missing.
By using the PEP-8 naming conventions, it is also less likely that such name clashes will occur.
You also should, in case of a successful POST request, redirect to a page. This is the Post/Redirect/Get web development pattern. Otherwise in case the submission was successful, if you render a page, and the user refreshes the page in the browser, the browser will make the same POST request.
I Want to process my form data and view and update my mongo DB if name not present else if name present update the DB.
Before that, I want to make sure if the entire subject is proper.. using some regex.
But when I add name and subject in below form code nothing is happening.
How do I get the form data in view and do the proper check?
And where should I do the input validation in views or form.html ??
if entered data is not proper format throw error? how can I do this?
form_template.html
<div class="container">
<div class="col-md-5">
<div class="form-area">
<form id="add-form" method="POST" action="{% url 'myapp:add_data' %}" role="form">
<br style="clear:both">
<h4 style="margin-bottom: 25px; text-align: center;"> New Data</h3>
<div class="form-group">
<input type="text" class="form-control" id="name" name="name" placeholder="Name" required>
</div>
<div class="form-group">
<input type="text" class="form-control" id="sub_list" name="sub_list" placeholder="Sub List comma separated" required>
</div>
<button type="button" id="submit" name="submit" class="btn btn-primary pull-right">Submit Form</button>
</form>
</div>
</div>
</div>
</div>
myapp/url.py
url(r'^new_data$', views.add_data, name='add_data'),
And below is my view function
def add_data(request):
print "Herfe"
if request.POST:
print "coming here"
I want validate user entered input is proper
messages.success(request, 'Form submission successful')
return render(request, '/index.html')
you can use request.POST.get(<name>) to get the data from the template and then preprocess it.
So in your case it simply becomes
def add_data(request):
print "Herfe"
if request.POST:
print "coming here"
data = request.POST.get('name')
# now validate to your heart's content
messages.success(request, 'Form submission successful')
return render(request, '/index.html')
On a side note I think you are missing out the benefits of forms in django. If you use the forms API properly you can easily pass values and validate them with inbuilt methods. In that case it would become
form = YourForm(request.POST)
if form.is_valid():
form.save()
your_variable = form.cleaned_data['name'] # validates for malicious data automatically
# Now you can do further validations accordingly.