Need to show result on the same page - Django - python

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.

Related

I am trying to save the form data. My Django form data is not saved, why?

I am trying to save form data from Django template to Django Model. Its not throwing any error but its not saving the data as well
Could you please let me know what could be the problem and how should I solve?
Here is my Django form template:
<form method="POST" class="review-form" autocomplete="on">
{% csrf_token %}
<div class="rating-form">
<label for="rating">Your Overall Rating Of This Product :</label>
<span class="rating-stars">
<a class="star-1" href="#">1</a>
<a class="star-2" href="#">2</a>
<a class="star-3" href="#">3</a>
</span>
<select name="rating" id="rating" required=""
style="display: none;">
<option value="">Rate…</option>
<option value="3">Average</option>
<option value="2">Not that bad</option>
<option value="1">Very poor</option>
</select>
</div>
<textarea cols="30" rows="6"
placeholder="What did you like or dislike? What did you use this product for?" class="form-control"
id="review" name="description"></textarea>
<div class="row gutter-md">
<div class="col-md-12">
<input type="text" class="form-control"
placeholder="Your Name - This is how you'll appear to other customers*" id="author" name ="name">
</div>
</div>
<button type="submit" class="btn btn-dark">Submit Review</button>
</form>
My Forms.py
class ReviewForm(forms.ModelForm):
class Meta:
model = Reviews
fields = ('rating', 'description', 'display_name')
My Views:
def reviews(request, slug):
if request.method == "POST":
if request.user.is_authenticated:
form = ReviewForm(request.POST)
if form.is_valid():
review = form.save(commit=False)
review.product = Products.objects.get(slug=slug)
review.user = request.user
review.display_name = request.name
review.description = request.description
review.rating = request.rating
print(review)
review.save()
messages.success(request, "Review saved, Thank you for the feedback.")
return redirect('products:products')
else:
messages.error(request, 'Sorry! Only customer purchased this Item are eligible for the review')
else:
pass
return redirect('ecommerce:products')
Try using generic ClassBasedViews. It's worth it to learn the concept! You will have to write less code and you will be able to edit a model instance and delete it from the front end.

How to get selected value in dropdown list, then pass it to views.py

I'm working on an upload file feature with dropdown and dropzone. But, whenever I submit the uploaded file with selected option, it always says that the selected option is None. I found it None after I printed the nama_bimbingan in views.py. Here it is my code.
url.py
....
url(r'bimbingan/add/upload', mengelola_bimbingan.upload_data_bimbingan, name='add-bimbingan-excel'),
url(r'bimbingan/download-template/', mengelola_bimbingan.bimbingan_template, name='bimbingan-template'),
....
forms.py
class UploadBimbinganForm(forms.Form):
...
...
dropdown_choices = tuple(zip(all_pembimbing, all_pembimbing))
nama_pembimbing = forms.ChoiceField(choices = dropdown_choices)
upload_bimbingan.html
<form method="POST" action="{% url 'app:add-bimbingan-excel' %}" enctype="multipart/form-data">
{% csrf_token %}
<div class="py-3">
<label for="id_nama_pembimbing"> Nama Pembimbing Akademik: </label>
<select class="form-control mb-2" id="id_nama_pembimbing" name="nama_pembimbing" required>
<option value = "" selected="selected">---------</option>
<option value = {{form.nama_pembimbing}}></option>
</select>
</div>
<div id="myDropzone" class="dropzone" drop-zone>
<h6 class="dz-message"> Drop file here or click to upload</h6>
</div>
<div class="py-3">
Download Template<br>
<div class="row justify-content-between py-3">
<div class="col-md-5 mb-1">
<a href="{% url 'app:read-all-bimbingan' %}" class="btn btn-blue-outlined">Batal</a
</div>
<div class="col-md-5">
<input type="submit" value="Simpan" class="btn btn-block btn-blue">
</div>
</div>
</div>
</form>
views.py
#login_required(redirect_field_name='index')
#user_passes_test(only_admin_access)
def upload_data_bimbingan(request):
form = UploadBimbinganForm(request.POST or None)
if request.method == "POST" and 'file' in request.FILES:
nama_pembimbing = request.POST.get('nama_pembimbing')
excel_file = request.FILES["file"]
data = get_data(excel_file, column_limit=1)
bimbingans = data["Bimbingan"]
...
...
if(len(duplicate) == 0):
space_parsed_query = nama_pembimbing.replace(' ', '%20')
cleaned_query = space_parsed_query.replace(',', '%2C')
nip_pembimbing = int(get_data_dosen_by_nama(cleaned_query)[0]["nomor"])
for bimbingan in bimbingans:
if(bimbingan[0] != "NPM"):
new_bimbingan = Bimbingan(nip_pembimbing=nip_pembimbing, npm_mahasiswa=bimbingan[0])
new_bimbingan.save()
return redirect('/app/bimbingan')
else:
...
...
return redirect('/app/bimbingan')
else:
context={
"form": form
}
return render(request, 'app/mengelola_bimbingan/upload_bimbingan.html', context)
I already tried to use nama_pembimbing = form.cleaned_data["nama_pembimbing"] in views.py, but it's still not working since the form.is_valid() always return false, so I removed it. I use django & python for this and purpusely don't use javascript to handle the uploaded file & selected option. I really hope that someone can help me to resolve this issue.
I think this part of your html code is just messed up.
<select class="form-control mb-2" id="id_nama_pembimbing" name="nama_pembimbing" required>
<option value = "" selected="selected">---------</option>
<option value = {{form.nama_pembimbing}}></option>
</select>
I recommend you not to give whitespace between html attribute and its value. So, it should be like this:
<select class="form-control mb-2" id="id_nama_pembimbing" name="nama_pembimbing" required>
<option value="" selected="selected">---------</option>
<option value="{{form.nama_pembimbing}}">{{form.nama_pembimbing}}</option>
</select>
I already got a solution for this issue. The problem is on dropzone. I tried to remove dropzone and the selected value from dropdown can be retrieved in views. So, to solve this issue, I need to add the following codes inside my dropzone script.
init: function() {
dzClosure = this;
this.on("sending", function(data, xhr, formData) {
formData.append("nama_pembimbing", jQuery("#id_nama_pembimbing").val());
});
}
That's all and it should be fuctioned well.

Trying to use file upload without forms.py - 'InMemoryUploadedFile' object is not callable

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.

Django Process Form data in views.py on submit

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.

django modelformset_factory doesn't include actual forms

I've been trying to follow tutorials and other SO questions and have a modelformset_factory that's displaying a list of what looks like forms in the html, but it turns out they're not actual forms.
html that gets displayed:
<div ='container'>
<div class='row'><tr><th><label for="id_form-0-config_key">Config key:</label></th><td><input id="id_form-0-config_key" maxlength="63" name="form-0-config_key" type="text" value="ClientMustVerify" /></td></tr>
<tr><th><label for="id_form-0-config_value">Config value:</label></th><td><input id="id_form-0-config_value" maxlength="63" name="form-0-config_value" type="text" value="TRUE" /><input id="id_form-0-id" name="form-0-id" type="hidden" value="3" /></td></tr> <input type="submit" value="Update" /></div>
<div class='row'><tr><th><label for="id_form-1-config_key">Config key:</label></th><td><input id="id_form-1-config_key" maxlength="63" name="form-1-config_key" type="text" value="Auditing" /></td></tr>
<tr><th><label for="id_form-1-config_value">Config value:</label></th><td><input id="id_form-1-config_value" maxlength="63" name="form-1-config_value" type="text" value="FALSE" /><input id="id_form-1-id" name="form-1-id" type="hidden" value="4" /></td></tr> <input type="submit" value="Update" /></div>
<div>
notice there is no form tag anywhere. working backwards, here's the excerpt from the template:
<div ='container'>
{% for form in formset %}
<div class='row'>{{form}} <input type="submit" value="Update" /></div>
{% endfor %}
<div>
yes, I added the submit button manually hoping to get these to work, but of course if there isn't a form tag, then the submit button won't do anything.
views.py:
from limbo.models import serverConfig
from django.forms import modelformset_factory
from django.forms import formset_factory
def editServer(request):
result = serverConfig.objects.values()
myConfigs = [entry for entry in result]
finalFormSet = modelformset_factory(serverConfig, exclude=('id',), extra=0)
#other lines
return render(request, 'limboHtml/ServerConfiguration.html', {'formset': finalFormSet, 'SubmitMessage': '', 'CurrentConfigs': myConfigs})
forms.py:
class serverForm(ModelForm):
class Meta:
model = serverConfig
fields = ['config_key', 'config_value']
def __init__(self, *args, **kwargs):
super(serverForm, self).__init__(*args, **kwargs)
instance = getattr(self, 'instance', None)
if instance and instance.pk:
self.fields['config_key'].widget.attrs['readonly'] = True
self.fields['config_key'].widget.attrs['disabled'] = True
and models.py:
class serverConfig(models.Model):
config_key = models.CharField(max_length=63)
config_value = models.CharField(max_length=63)
I tried using finalFormSet = formset_factory(serverForm, extra=0) at one point, but then I just got no content in the html...
As described in the formset documention you must add the form tag manually. This is not very different from what you do when displaying a single form.
It appears that you are iterating through the formset and displayig them one by one. That means you must also add the management form
<form method="post" action="">
{{ formset.management_form }}
<div ='container'>
{% for form in formset %}
<div class='row'>{{form}} <input type="submit" value="Update" /></div>
{% endfor %}
<div>
</form>
Or you will get errors about a missing or misconfigured management form.
Note that it does not include the tags, or a submit button. We’ll have to provide those ourselves in the template.
Read more: Working with Forms: Building a form in Django
The reason you are not getting the <form> tag is because from a logical point of view a form validation can be handled anywhere in your application. That's why you need to specify the form tag explicitly with the target url (good to use reverse(view_name)), method and other parameters.

Categories