Duplicate entry in database on refreshing the submitted form in django - django

After i submit my form using GET method and then refresh the page the data get resubmitted
i am using javascript for form validation
my views are:
def show(request,post_id):
try:
p = post.objects.get(pk=post_id)
c = comment.objects.filter(blog_id=p)
if 'cbox' in request.GET:
c = comment(text=request.GET['cbox'],name=request.GET['cname'],blog=p)
c.save()
c_list = comment.objects.filter(blog_id=p)
except post.DoesNotExist:
raise Http404
return render_to_response('show.html',{'post':p,'c_list':c_list})
my form is:
<form name="comment" action="" method="get" onsubmit="return validateForm()">
<input id="carea" type="text" placeholder="leave a comment" name="cbox" >
<input id="cb" type="submit" value="Post" />
<input id="cn" type="text" placeholder="Name" name="cname">
</form>
i want that when i refresh my page my data should not get resubmited
thanks

If you really insist on using GET to submit which practically is not a good method. You should do a request redirect using HttpResponseRedirect from the server side which will remove the query string from the url . This way it wouldn't resumit the form.
def show(request,post_id):
try:
p = post.objects.get(pk=post_id)
c = comment.objects.filter(blog_id=p)
if 'cbox' in request.GET:
c = comment(text=request.GET['cbox'],name=request.GET['cname'],blog=p)
c.save()
#Do a redirect here
return HttpResponseRedirect("URL of the page you would like to redirect")
c_list = comment.objects.filter(blog_id=p)
except post.DoesNotExist:
raise Http404
return render_to_response('show.html',{'post':p,'c_list':c_list})

Related

Variable 'html' referenced before assigned: UnboundLocalError

This code previously worked and outputed what I wanted on the website, but then this error happened
from django.shortcuts import render
import json
def get_html_content(fplid):
import requests
API_KEY = "eb9f22abb3158b83c5b1b7f03c325c65"
url = 'https://fantasy.premierleague.com/api/entry/{fplid}/event/30/picks/'
payload = {'api_key': API_KEY, 'url': url}
for _ in range(3):
try:
response = requests.get('http://api.scraperapi.com/', params= payload)
if response.status_code in [200, 404]:
break
except requests.exceptions.ConnectionError:
response = ''
#userdata = json.loads(response.text)
return response.text
def home(request):
if 'fplid' in request.GET:
fplid = request.GET.get('fplid')
html = get_html_content(fplid)
return render(request, 'scrape/home.html', {'fpldata': html})
here is my views.py file. I think I assigned html before, but I'm not sure, how is it referenced before it renders. I added scraperapi for many ip addresses, as I thought maybe I was banned from the api. I am unsure what is going on.
<body>
<h1>Enter Your FPL id </h1>
<form method="GET">
<label for="fplid"> </label>
<input type="text", name="fplid", id="fplid"> <br>
<input type="submit" value="Submit" />
</form>
<h3> {{fpldata}}</h3>
</body>
This is a part of the home.html file if it is relevant
When you initially load the page there probably wont'be an initialized ?fplid=xx. When this isn't present the variable is not assigned a value.
You could initialize the variable with html = None or this:
def home(request):
if 'fplid' in request.GET: # <- when this isnt true
fplid = request.GET.get('fplid')
html = get_html_content(fplid)
return render(request, 'scrape/home.html', {'fpldata': html})
return render(request, 'scrape/home.html')

Django : downloading a file (pdf version or odt version) through radio buttons

I trying to propose to the users of my site to download a document in either pdf or odt version through radio buttons. How can I get and use the value of the radio button chosen by the user to serve the appropriate file. So far, I can only serve one at a time.
My current work:
models.py
class File(models.Model):
name = models.CharField(max_length=200)
pdf_version = models.FileField()
odt_version = models.FileField()
def __str__(self):
'''String name represents class File'''
return self.name
urls.py
path('files_page/', views.files_page, name='files_page'),
path('download_file/<int:file_id>/', views.download_file, name='download_file'),
views.py
def files_page(request):
files = File.objects.all()
context = {'files':files}
return render (request, 'walk/files_page.html', context)
def download_file(request, file_id):
#No post request; do nothing
if request.method != 'POST':
pass
else:
#fetch the file to download
#file = File.objects.get(id=file_id)
response = FileResponse(open('/home/me/Desktop/super/media_cdn/tog.pdf', 'rb'))
response['Content-Disposition'] = 'attachment; filename="tog.pdf"'
return response
template
{%block content%}
{%for file in files %}
<p>{{file.name}}</p>
<p>{{file.pdf_version}}</p>
<p>{{file.csv_version}}</p>
<form action="{%url 'walk:download_file' file.id%}" method="POST">
{%csrf_token%}
<input type="radio" name="format" value="pdf" checked> pdf
<input type="radio" name="format" value="csv"> csv
<button name="submit">download</button>
</form>
{%endfor%}
{%endblock content%}
Let's start with using forms. Yes, you use django forms in django instead re-implementing everything yourself.
Create forms.py:
from django import forms
FILE_FORMAT_CHOICES = [("csv", "Download PDF"), ("csv", "Download CSV")]
class FileFormatForm(forms.Form):
file_format = forms.ChoiceField(choices=FILE_FORMAT_CHOICES, widget=forms.RadioSelect())
Inside of the template used by files_page (just let django render the fields, don't do it yourself):
<form action="{%url 'walk:download_file' file.id%}" method="POST">
{% csrf_token %}
{{ form }}
<input type="submit" value="Download">
</form>
And finally adjust the views.py:
def files_page(request):
...
context = {
'files': files,
'form': FileFormatForm() # empty / without POST
}
...
def download_file(request, file_id):
assert request.method == 'POST', "users should only come here with POST now"
form = FileFormatForm(request.POST) # populate from POST
if form.data['file_format'] == 'pdf':
return "return PDF file response here"
else:
return "return CSV file response here"
Note: you don't use tab in Python. Use 4x whitespaces instead.
Another Note: Class Based Views to further reduce the amount of boilerplate.

Should I use request.GET['...'] or form.cleaned_data.get('...')

I have created a function for a search form form my database, method works fine, but I, don't know whether I should use queryBooks = request.GET['queryBooks'] or form.cleaned_data.get('queryBooks')
Here is my code.
# views.py
def SearchBook(request):
error = False
message = ''
books = Books.objects.all()
if 'queryBooks' in request.GET:
queryBooks = request.GET['queryBooks']
if not queryBooks:
error = True
message = u'enter book or author title'
else:
books = Books.objects.filter\
(
Q(book__icontains=queryBooks) | Q(Author__name__icontains=queryBooks)
)
contexto = {'Books': books, 'Error': error, 'Message': message}
return render(request, 'list_of_book.html', contexto)
# list_of_book.html
<form action="" method="get">
<input type="text" name="queryBooks">
<input type="submit" value="search">
</form>
# urls.py
url(r'^books/search/$', SearchBook, name='searchBook'),
There is no form in your view, so
form.cleaned_data.get('queryBooks')
Would give you an error.
In general, I recommend that you learn about Django forms, as they take care of rendering the html, and validating the input from the user. For your specific example, fetching the query string from request.GET is probably ok.

Django: keep data visible in multiple individual forms

I have three forms in three tabs respectively in a template.
I fill in the first tab, submit, fill in the second form, submit, fill in the third form, submit.
Is there a way to keep the data in each form after saving? I need to show them all together.
No, when I save the second form I lose my data on the first form.
input.html: template
<form class="tab-pane fade in active" id="demographics" method="post" >
<input type="hidden" name="form_id" value="demographics">
{%crispy frm%}
</form>
<form class="tab-pane fade" id="diagnosis" method="post">
<input type="hidden" name="form_id" value="diagnosis">
{%crispy frm_d%}
</form>
<form class="tab-pane fade" id="a_b_sickle" method="post">
<input type="hidden" name="form_id" value="a_b_sickle">
{%crispy frm_a_b_s%}
</form>
views.py
def input(request):
context = RequestContext(request)
if request.method == 'POST':
submitted = request.POST.get('form_id', '')
print submitted
if submitted == 'demographics':
# Get the Form1 instance
my_demographics = DemographicForm(request.POST)
#my_diagnosis = DiagnosisForm()
if my_demographics.is_valid():
my_demographics_object= my_demographics.save()
my_diagnosis=DiagnosisForm({'patient': my_demographics_object.patient_id, 'diagnosis_option': 'b-thalassaemia syndromes'})
my_a_b_sickle=A_b_sickle_thalForm({'patient': my_demographics_object.patient_id})
else:
my_diagnosis=DiagnosisForm()
my_a_b_sickle = A_b_sickle_thalForm()
elif submitted == 'diagnosis':
my_diagnosis = DiagnosisForm(request.POST)
my_demographics = DemographicForm()
my_a_b_sickle = A_b_sickle_thalForm()
if my_diagnosis.is_valid():
my_diagnosis_object=my_diagnosis.save()
my_a_b_sickle =A_b_sickle_thalForm({'patient': my_diagnosis_object.patient})
else:
my_demographics = DemographicForm()
my_a_b_sickle = A_b_sickle_thalForm()
elif submitted == 'a_b_sickle':
my_a_b_sickle = A_b_sickle_thalForm(request.POST)
my_demographics = DemographicForm()
my_diagnosis = DiagnosisForm()
if my_a_b_sickle.is_valid():
my_a_b_sickle.save()
else:
raise ValueError('No form specified !')
else:
my_demographics = DemographicForm()
my_diagnosis = DiagnosisForm()
my_a_b_sickle= A_b_sickle_thalForm()
return render(request,'input.html', {'frm':my_demographics, 'frm_d': my_diagnosis, 'frm_a_b_s': my_a_b_sickle})
Any ideas please?
You can either submit them using ajax or send them back filled in your context. If you can get the saved objects between request by any association they have you can try:
For the second way you can try something like this:
my_demographics = DemographicForm(my_demographic_object)
my_diagnosis = DiagnosisForm(my_diagnosis_object)
my_a_b_sickle= A_b_sickle_thalForm(my_a_b_sickle)
return render(request,'input.html', {'frm':my_demographics, 'frm_d': my_diagnosis, 'frm_a_b_s': my_a_b_sickle})
In fact, with that you can even make that work as an update form with a little extra using the 'instance' attribute of ModelForm.

Add form returns None as record id, causing URL to error

I'm using the code found here (SO.com) to use the same template to both add and edit a record, but when I add a new record and click Submit, I get a 404 on the URL http://192.168.1.3:5678/app/student/edit/None/, and I'm not exactly sure why.
Here is the relevant portion of my urls.py:
url(r'^app/lesson/new/$', 'edit_lesson', {}, 'lesson_new'),
url(r'^app/lesson/edit/(?P<id>\d+)/$', 'edit_lesson', {}, 'lesson_edit'),
Here is the relevant portion of my views.py:
def edit_lesson(request, id=None, template_name='lesson_edit_template.html'):
if id:
t = "Edit"
lesson = get_object_or_404(Lesson, pk=id)
stu = get_object_or_404(Student, pk=sid)
if stu.teacher != request.user:
raise HttpResponseForbidden()
else:
t = "Add"
lesson = Lesson()
if request.POST:
form = LessonForm(request.POST, instance=lesson)
if form.is_valid():
form.save()
# If the save was successful, redirect to another page
return view_lessons(request)
else:
form = LessonForm(instance=lesson)
return render_to_response(template_name, {
'form': form,
't': t,
'lesson': lesson,
}, context_instance=RequestContext(request))
And finally, here is my template:
<h1>{{ t }} Lesson</h1>
<form action="/app/lesson/edit/{{ lesson.id }}/" method="post"> {% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
I'm certain that I'm missing something really easy, but I can't seem to put my finger on it. I'm using Django 1.3.1 if that makes any difference.
Thanks,
MC
There's no need to specify any URL in the form's action attribute. Just do
<form action="" method="post">
and it will POST back to the URL that you originally used to access it, which is what you want.
In add case {{ lesson.id }} is None, because lesson is unsaved Lesson() instance, without pk, so your form is being fired to nonexistent URL.
I recommend separating create and edit views and processing them in different ways (or even inherit generic views - with new class-based generic views it's easy and pleasant).
Also, use {% url %} template tag everywhere instead of hard-coded urls.