Dynamic consuming of web API in Django based on user's choice - python

The program I am trying to write requires that whenever the user changes a value in a form on Django website, that value will be written to the variable and then inserted into the API's url as parameter inside requests.get() function in views.py file.
So basically my Django website is to consume web API.
API returns different data sets ​​depending on the explicit endpoint. It can change dynamically depending on what the user chooses in a form, and then, if submit button is clicked, show the content on a django website immediately.
Here is the Web API which I use to get data sets:
http://api.nbp.pl/en.html
forms.py:
from django import forms
class DateInput(forms.DateInput):
input_type = 'date'
class ExampleForm(forms.Form):
my_date_field = forms.DateField(widget = DateInput)
views.py:
from django.shortcuts import render
import requests
from .forms import ExampleForm
def home(request):
submitbutton = request.POST.get("submit") # I check if submit button is clicked
form = ExampleForm()
date2 = ''
if form.is_valid():
date2 = form.cleaned_data.get("my_date_field") # write date choosen by user to variable
# And now I have a problem. I want to use the value of this variable to specify an endpoint:
response = requests.get(f"http://api.nbp.pl/api/exchangerates/tables/a/2012-01-01/{date2}/")
Api = response.json()
context= {'form': form, 'submitbutton': submitbutton, "Api": Api}
return render(request, 'home.html', context)
The user selects a date in the form and based on that date, the data set is returned.
I have no problem with the HTML template file. I know how to insert form and submit button on a website, and how to view the data set using API, but my goal is to make it flexible - dependent on form value.
Current code returns error: JSONDecodeError. The help would be greatly appreciated.

Yes, URL constructed using the f-string returns data.
I found that if I don't use the function is_valid(), form is invalid but code returns correct reponse (Response [200]) and as a result the data is correctly displayed without error, but this only happens if the value of date2 is constant - this is not what interests me, I want it to be taken from the form!
Please have someone look at my code and say if I am doing something wrong, I am tired of this problem...
from django.shortcuts import render
import requests
from .forms import ExampleForm
def home(request):
submitbutton = request.POST.get("submit")
date2 = '2020-01-17'
if request.method == 'POST':
form = ExampleForm(request.POST)
if form.is_valid():
print("Is Valid")
date2 = form.cleaned_data.get("my_date_field")
date_string = str(date2)
argument = f"http://api.nbp.pl/api/exchangerates/tables/a/2012-01-01/{date_string}/"
response = requests.get(argument)
Api = response.json() # This causes an error, because response is incorrect, I don't know why
return render(request, 'home.html', {'form': form, 'submitbutton': submitbutton, "Api": Api} )
else:
print("Is no valid")
form = ExampleForm()
date2 = '2012-01-10'
response = requests.get(f"http://api.nbp.pl/api/exchangerates/tables/a/2012-01-01/{date2}/")
Api = response.json() # This doesn't cause an error, response is correct - but that way value of variable is not taken from the form...
context= {'form': form, 'submitbutton': submitbutton, "Api": Api}
return render(request, 'home.html', context)

Related

How to save multiple objects at once to Django database?

I'm trying to get form data using a POST request and save the form data to my database which was created using a django model, which is InfoModel. I'm getting the data from the POST request, but I don't know how to save all of it at once so that it all saves to the same row in the db. The way I'm doing it now, each object from the form saves to a different row of the database which is obviously not useful at all. I expect the answer is simple, but I haven't seen this in the docs.
views.py:
def home(request):
if request.method == 'POST':
# if POST request, validate the data
form = InfoForm(request.POST)
if form.is_valid():
# if the form is valid, collect the data, submit to db, and thank the user
valid = True
form_data = request.POST
f = InfoModel(fname=form_data['fname'])
f.save()
l = InfoModel(lname=form_data['lname'])
l.save()
e = InfoModel(email=form_data['email'])
e.save()
p = InfoModel(phone=form_data['phone'])
p.save()
return render(request, 'form_db/home.html', {'form': form, 'valid': valid})
else:
# if the form is invalid, populate the form with the entered data and show error message
valid = False
form = InfoForm(request.POST)
return render(request, 'form_db/home.html', {'form': form, 'valid': valid})
else:
# if GET request, return blank form as normal
form = InfoForm()
return render(request, 'form_db/home.html', {'form': form})
You can simply, give all fields' names of your InfoModel at once in the following way:
if form.is_valid():
valid=True
fName=form.cleaned_data['fname']
lname=form.cleaned_data['lname']
email=form.cleaned_data['email']
phone=form.cleaned_data['phone']
instance=InfoModel(fname=fName,lname=lname,email=email,phone=phone)
instance.save()
return render(request,"form_db/home.html",{'form': form,'valid':valid})
Note: Models in django doesn't require model to be the suffix, so it will be better if you only give model name Info rather than InfoModel.
Every time you call f = InfoModel() you are instantiating a new instance, and then saving it using f.save(), which is why you are getting so many rows. All this is unnecessary since a form has it's own save() method, which will save all the fields at once into ONE row.
The best way to handle forms is to use the classic Post/Redirect/Get method where if the form data comes in as Post, then you process it and redirect, usually back to the same view, but it can be another view as well. If it is a Get, then you render the blank form.
def home(request):
if request.method == 'POST':
form = InfoForm(request.POST or None)
if form.is_valid():
form.save()
return redirect('home')
return render(request, 'form_db/home.html', {'form':form})
Note the form = InfoForm(request.POST or None), which is handy since it will create a blank form with the None if it is not a Post request, but if it is will fill the form with the data request.POST if it's a Post request.

How to reload the current page when form was sent?

Hey,
after the form was sent the page needs to be automatically reloaded / refreshed. Either just the current page is going to be reloaded or the variable slug_title (which would be part of the current page url) needs to be passed into the (' ') from HttpResponseRedirect.
Do you have any suggestions? I would really appreciate it. :)
views.py
def posts(request, slug_titel):
post = get_object_or_404(Thread, slug_titel=slug_titel)
form = ThreadForm()
if request.method == "POST":
form = PostForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(' ') # <- here I need to put in slug_title from above
You can redirect to a view with variables that way:
from django.shortcuts import redirect
return redirect('some-view-name', slug=slug_titel)
Well if the form is valid, you have access to cleaned_data, from there you can fetch the slug value entered by user:
if form.is_valid:
slug = form.cleaned_data.get(“slug_titel”)
return redirect(“your-view”, slug = slug)

Why we write this, form = StudentForm(request.POST) in django?

This is my views function,
def studentcreate(request):
reg = StudentForm()
string = "Give Information"
if request.method == "POST":
reg = StudentForm(request.POST)
string = "Not Currect Information"
if reg.is_valid():
reg.save()
return render('http://localhost:8000/accounts/login/')
context = {
'form':reg,
'string': string,
}
return render(request, 'student.html', context)
Here first we store form in reg variable then also we write reg = StudentForm(request.POST) why?
acutally why we write this?
I can't tell you why you are writing this. Maybe only you know. It does not make much sense. I would recommend reading the Django documentation on this at https://docs.djangoproject.com/en/4.0/topics/forms/#the-view
from django.http import HttpResponseRedirect
from django.shortcuts import render
from .forms import NameForm
def get_name(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 = NameForm(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:
return HttpResponseRedirect('/thanks/')
# if a GET (or any other method) we'll create a blank form
else:
form = NameForm()
return render(request, 'name.html', {'form': form})
You read from data if the request is a POST. Otherwise, return an empty form.
You could think of the "request.POST" as a parameter passed onto the form in the view. This tells the view that the form mentioned has POST data from the form in name.html. Otherwise it is just an empty form.

The view urlshort.views.page_redirect didn't return an HttpResponse object. It returned None instead

I'm making a url shortener with django. I have a form that has a long_url attribute. I'm trying to get the long_url and add it to a redirect view with a HttpResponseRedirect.
# Form
from .models import ShortURL
from django import forms
class CreateNewShortURL(forms.ModelForm):
class Meta:
model=ShortURL
fields = {'long_url'}
widgets = {
'long_url': forms.URLInput(attrs={'class': 'form-control'})
}
# View
def page_redirect(request, url):
if request.method == 'GET':
form = CreateNewShortURL(request.GET)
if form.is_valid():
original_website = form.cleaned_data['long_url']
return HttpResponseRedirect(original_website)
When I go to the link, it gives me The view urlshort.views.page_redirect didn't return an HttpResponse object. It returned None instead. Does anyone know why this is happening?
It is not returning because there is no valid form, you need to redirect to a form for the user to enter data first, you will then get that data from the form to perform your redirect. additionally because a user is returning data you will need to get the data from request.POST.
def page_redirect(request, url):
if request.method == 'GET':
form = CreateNewShortURL(request.POST)
if form.is_valid():
original_website = form.cleaned_data['long_url']
return HttpResponseRedirect(original_website)
return render(request,'template') # this is the form for the user to enter the url

Django work flow redirect from one view to another and display page with url parameter

I am trying to create a web app that users will select a file, get data processed and then redirected to a confirmation page with a url parameter(?status=1) How can I move from the processing view to the confirmation view and then display the confirmation page?
I have put my code below which is not working in my views and urls py files
# views.py
def marketdata_processing(request):
if request.method == 'POST':
uploadform = forms.MyUploadForm(request.POST, request.FILES)
if uploadform.is_valid():
newdoc = models.UploadDocument(docfile=request.FILES['uploadfile'])
filename = request.FILES['uploadfile'].name
newdoc.save()
selecteddate = newdoc.getselecteddate() # Model method calculated
fileid = newdoc.pk
request.session['fileid'] = fileid
request.session['selecteddate'] = selecteddate
return redirect(reverse('views.confirm_input_details'))
else:
uploadform = forms.MyUploadForm()
# Render list page with the documents and the form
return render_to_response(
'mytemplate.html',
{'uploadform': uploadform},
context_instance=RequestContext(request)
)
def confirm_input_details(request):
fileid = request.session['fileid']
selecteddate = request.session['selecteddate']
msg = 'Proceed to import data for %s? \nFileID Being Imported is %s ' % (
selecteddate, fileid,)
url = reverse('views.confirm_input_details', kwargs={'status': 1})
return HttpResponseRedirect(url)
# urls.py
urlpatterns = [
url(r'', views.marketdata_processing, name='myapp/mytemplate.html'),
url(r'^\?status=(?P<status>[0-9]+)$',
views.confirm_input_details, name='myapp/myconfirmpage.html'),
]
There are a couple of issues I feel exist in your code:
Indentation is a very important thing in python code. Please make sure the indentation of your if-else statements in the 'marketdata_processing' view are in correct order. Beware, in your code:
return render_to_response('mytemplate.html',
{'uploadform': uploadform},
context_instance=RequestContext(request))
will always get executed as it is outside the else statement. You might want to indent it under the else (if it makes sense)- like so:
else:
uploadform = forms.MyUploadForm()
return render_to_response('mytemplate.html',
{'uploadform': uploadform},
context_instance=RequestContext(request))
Instead of 'redirect(reverse())' try 'HttpResponseRedirect()' in the processing view to call the confirm-page view, like so:
from django.http import HttpResponseRedirect
return HttpResponseRedirect('/?status=1') --> relative URL shown
place the relative/absolute url (both would work) above.
Finally, render your confirm-page template in the 'confirm_input_details' view with the context parameters, like so:
def confirm_input_details(request):
fileid = request.session['fileid']
selecteddate = request.session['selecteddate']
msg = 'Proceed to import data for %s? \nFileID Being Imported is %s ' % (selecteddate, fileid)
return render_to_response('confirmpage_template.html'),
{'fileid': fileid,
'selecteddate': selecteddate,
'msg': msg}, context_instance=RequestContext(request))
** P.S: Stick to neat basics and it will work. You happened to call your confirm_input_details view from within the same view itself. As far as I think, that would probably take you into an infinite loop. Simple concept of any view is:
take input:request, parameters
--> process logic with parameters
--> render a specific template or call another url where a template is being rendered.
You can't expect a page to show up without the rendering a template.

Categories