Django - Class Function not returning page - python

I am trying to create code for my Django site which will take the user's input, perform a calculation, and then send the data back to the user in the form of a new page, however everytime I run the code, it does not create the new page nor does it post the results.
Below is the function itself.
def SparkCalc(request):
new_item = sparkCalculator()
new_item.tix = request.POST['tix']
new_item.tenrolls = request.POST['tenrolls']
new_item.crystals = request.POST['crystals']
new_item.save()
total = new_item.getTotal()
return render(request, 'SparkResults.html', {"title": "Spark Results"}, {"total": total})
and below is the Django page I am calling it from:
<form action="/SparkCalc/" method="POST">{% csrf_token %}
<label for ="tix">Please enter your single roll tickets</label>
<input type="text" id="tix" name="tix"/>
<label for ="tenrolls">Please enter your ten-roll tickets</label>
<input type="text" id="tenrolls" name="tenrolls"/>
<label for ="tix">Please enter your total crystal amount</label>
<input type="text" id="crystals"name="crystals"/>
<input type="submit" value="Get Results"/>
</form>
And finally below is the class I created:
class sparkCalculator(models.Model):
tix = models.PositiveIntegerField()
tenrolls = models.PositiveIntegerField()
crystals = models.PositiveIntegerField()
def getTotal(self):
return (int(self.tix)*300) + (int(self.tenrolls)* 3000) + int(self.crystals)
The way I envision the code to work is that once the user enters their information into the form, Django then runs the SparcCalc function, collecting the information entered, performing the math and collecting a total, and then sending the total to the new page. Instead, it seems to be just refreshing the page.
Also is it possible to run this style of code without creating an entire class for it? This is not information I would want to store. Ideally I would just want it executed at runtime and to be done with it, but previous attempts at doing this have failed and I simply gave up and tried creating a class.
As far as I can tell it is correctly entered into my urlpatterns.
from catalog.views import (
SparkCalc,
sparkCalcPage,
)
urlpatterns = [
path('SparkCalc/', sparkCalcPage),
path('SparkResults/', SparkCalc),
]
Any help would be greatly appreciated and thank you in advance for your help.

The signature of render function is as follows:
def render(request, template_name, context=None, content_type=None, ...):
...
In your case, you have passed {'total':total} to the content_type keyword argument instead of context.
# also make sure 'SparkResults.html' can be found by the template loader
render(request, 'SparkResults.html', {"title": "Spark Results", "total": total})
Also, you need to submit your data to the corrent view.
<form action="/SparkResults/" method="POST">
{% csrf_token %}
...
</form>

Instead of creating a model for the task,
perform the operation in the views.py itself.
def SparkCalc(request):
tix = request.POST['tix']
tenrolls = request.POST['tenrolls']
crystals = request.POST['crystals']
total = (int(tix)*300) + (int(tenrolls)* 3000) + int(crystals)
return render(request, 'SparkResults.html', {"title": "Spark Results"}, {"total": total})

Related

Choosing Flask method based on the button clicked in html form

I have created a sort of a "Postman" app for my colleagues and me. So, basically worked great with GET method only and I thought why not making DELETE, PUT, POST methods so we can have complete tool.
What I am trying to do is to fire an API call based on a button clicked in a html form. Here is my code with three files, template one, routes and methods files:
<form method="post" action="{{ url_for('api_dashboard.get_customer', store_id=store_id, customer_id=customer_id) }}">
<label class="rc_form__label" for="customer_id">Customer ID</label>
<div class="inputContainer">
<input type="text" class="rc_form__input mb-4 mr-4" placeholder="ex. 123" name="get_customer_id" id="customer_id"/>
<button type="submit_button" id="get_customer" name="get" class="rc_button rc_button--small rc_button--primary">GET</button>
<button type="submit_button" id="delete_customer" name="delete" class="rc_button rc_button--small rc_button--primary">DELETE</button>
<button type="submit_button" id="put_customer" name="put" class="rc_button rc_button--small rc_button--primary">PUT</button>
<button type="submi_button" id="post_customer" name="post" class="rc_button rc_button--small rc_button--primary">POST</button>
</div>
</form>
This is my routes code:
#api_dashboard.route("/<store_id>/customers", methods=["GET", "POST"])
def get_customer_by_id(store_id):
customer_id = request.form.get("customer_id")
if request.method == "POST":
if request.form["submit_button"] == "get_customer":
get_customer = Customer(store_id).get_customer(customer_id)
return render_template(
"/api_dashboard/index.html",
result=json.dumps(get_customer, indent=4, default=str),
store_id=store_id,
customer_id=customer_id,
)
elif request.form['submit_button'] == 'delete':
pass # this will be logic for deleting one
else:
pass # I will continue with other methods
elif request.method == "GET":
return render_template("/internal/api_dashboard/index.html", store_id=store_id)
And this is methods file:
class Customer(ApiService):
def get_customer(self, customer_id):
customer = self.api.get(endpoint=f"/customers/{customer_id}")
return customer.json()
def delete_customer(self, customer_id):
delete_response = self.api.delete(endpoint=f"/customers/{customer_id}")
return jsonify({"Customer deleted"}), 204
The error I am getting is this one:
{
"error": "The browser (or proxy) sent a request that this server could not understand."
}
I have found an article on StackOverFlow but really could not understand what would be the solution in this case. When making condition by the button, not sure what I should look for - and id, name or value of the button field.
My first official dev project in Flask, hope you understand if this is stupid question. Thanks in advance!

Python: Sending to a certain URL based on form submission

I'm trying to create a search bar where it will send users to certain URLs based on the query they typed on the "result" page, e.g. "/results?<form_search>". I've successfully made the version where the result page URL is /results but this isn't really what I want.
Here's the HTML script:
<!--index.html-->
<form action="{{ url_for('search') }}" method="post">
<input type="text" id="search" name="form_search" placeholder="Type here">
</form>
Here's the Python script where I direct the result to /results URL:
#app.py
#app.route("/")
def index():
return render_template("index.html")
...
# I want to direct this to "/results?<form_search>"
# I think I need to put the line below somewhere but I'm not sure where
# form_search = request.form.get("form_search")
#app.route("/results", methods=["POST"]) # Want to change it to "/results?<form_search>"
def search(form_search):
...
return render_template("results.html", form_search=form_search, results=results)
Anyone can help?
I barely worked with flask but if you want to have the dynamic URL you need to add it in your #app.route decorator, e.g.: If I want a username to be posted in the URL this is what it would look like:
#app.route("/<username>") # str,int,uuid,float,path also works
def user_name(username=None, post_id=None):
return render_template("index.html", name=username)
When it comes to getting the data from the form I can show you a similar example as I did in django (I didnt work with flask a while so you might need to experiment a bit yourself) - This is a method as it is created in a class:
def get_queryset(self):
query = self.request.GET.get(
"searchrecipe") # searchrecipe is the name of our input form, means: the value we enter in the form -> This might also work for FLASK, get the data with request.get and FORM NAME
object_list = Recipe.objects.filter(name__icontains=query) #This filters the data in my database (aftger name) so not relevant for you
return object_list

Flask + SqlAlchemy delete database entries

I have to delete database entries conditionally and I couldn't figure out as the form is asking for correct parameters posted in uri. I can delete entries in shell with same code but not in view. Following is the view and form:
#app.route('/cancelannualsub/<int:student_id>', methods=['DELETE'])
def cancel_yearly_rec(student_id):
if not user_authorized():
return redirect('/')
user = get_profile_data(session['auth_token'])
profile_data = user['StudentProfile']
pkg = Package.query.filter_by(student_id=profile_data.id).first_or_404()
if request.method=='POST':
try:
pkg = Package()
dbase.session.delete(pkg)
flash('Package deleted successfully.')
dbase.session.commit()
except:
pass
return redirect('plans')
return render_template('profile/cancel/cancel.html')
Form:
<form action="{{ url_for('cancel_yearly_rec', student_id=***can't render value here***) }}" method='post'>
<input type='hidden' name='_method' value='DELETE'
<input class='btn' type="submit" value="Cancel" />
</form>
I am trying different things from stackoverflow examples. Please assist if I am doing something wrong or if there is a better way to do it.
I wasn't using proper formatting to render model objects inside try block.
It supposed to be something like:
mymodel = Model.query.filter_by(variable=some_field_data).first_or_404()
dbase.session.delete(mymodel)
dbase.session.commit()
For readers don't get confused with "dbase" because I made this import like:
from app import db as dbase
You can import it simply by:
from app import db
or add "as anything".
Then you reference anything in rest of your file where you've made import.

How can Ajax work with a dynamic Django dropdown list?

I'm making this little web app that takes 2 addresses, calculates the distance using google maps, and calculates the gas cost based on the vehicles mpg rating. Everything is complete except for this last part that I believe would work best with AJAX.
I have 3 lists (year, make, model), and I need the list of car models to be restricted based on the year and make of the car. After selecting, I have a button that once clicked, will verify if it is a valid vehicle in the database and pull the vehicle's mpg rating to do some basic math on it.
The problem is I don't really know how to approach this problem. I've searched some inquiries the past few hours and I'm getting a lot of things related to model forms and Django choice fields which I don't want to get into if I don't have to. My idea is to just change the innerText/value, and check it against my django database.
I also came across this answer from SO:
How do I integrate Ajax with Django applications?
and am a bit confused by it. If I understand correctly, the AJAX GET request will extract data in javascript objects the same as if I visited that url as a user. Does this mean I could just create another html template and post every vehicle in the database onto that page from which I can extract info and create my dynamic lists from?
Looking for the most straightforward way to dynamically generate my lists with ajax and verify the year, make, and model with my database which will then return the car's mpg.
models.py:
class Car(models.Model):
year = models.IntegerField(default=0)
make = models.CharField(max_length=60)
model = models.CharField(max_length=60)
mpg = models.IntegerField(default=0)
def __str__(self):
return ("{0} {1} {2}".format(self.year, self.make, self.model))
views.py: (right now, it just lists every vehicle and has no way to verify the vehicle on the spot)
def index(request):
context_dic = {}
car_list = Car.objects.order_by('make')
car_list_model = Car.objects.order_by('model')
context_dic['car_list'] = car_list
context_dic['years'] = []
context_dic['makes'] = []
context_dic['models'] = []
for year in range(1995, 2016):
context_dic['years'].append(year)
for make in car_list:
if make.make not in context_dic['makes']:
context_dic['makes'].append(make.make)
else:
continue
for model in car_list_model:
if model.model not in context_dic['models']:
context_dic['models'].append(model.model)
else:
continue
return render(request, 'ConverterApp/index.html', context_dic)
html: (x3 for the make and model)
<div id="specifics">
<div class="dropdown" id="year-dropdown">
<button class="btn btn-default dropdown-toggle" type="button"
id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
Year
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
{% for year in years %}
<li>{{ year }}</li>
{% endfor %}
</ul>
</div>
javascript: (just shows the value right now, but can't verify with the database)
$('#calculate').on('click', function ()
{
$(this).siblings()[0].textContent = (
document.getElementById("dropdownMenu1").textContent
+ " " + document.getElementById("dropdownMenu2").textContent
+ " " + document.getElementById("dropdownMenu3").textContent
+ " " + document.getElementById("specifics-gas").value
)
});
});
//this part changes the year, make, model to what the user selects //from the list
$('li').on('click', function () {
$(this).parent().siblings()[0].innerHTML = this.innerHTML
//console.log(this.textContent)
});
Suppose you have to populate a static list of all the brand names in a drop-down and the second dropdown is supposed to be populated based on the selection in first.
Assuming two simple Django models defining Brands and Showrooms.
Views.py
class YourView(TemplateView):
template_name = 'template.html'
def get_context_data(self, **kwargs):
brands = Brands.objects.all()
context = super(YourView, self).get_context_data(**kwargs)
context.update({'brands': brands})
return context
def get_showrooms(request, **kwargs):
brand = Brands.objects.get(id=kwargs['brand_id'])
showroom_list = list(brand.showrooms.values('id', 'name'))
return HttpResponse(simplejson.dumps(showroom_list), content_type="application/json"
HTML
<label>Select Brand</label>
<select id="brands" name="brands" class="form-control">
<option value="">Select Brand</option>
{% for brand in brands %}
<option id="{{ brand.id }}" value="{{ brand.id }}">
{{ brand.name }}
</option>
{% endfor %}
</select>
<label>Select Showrroom</label>
<div id="showroom_list">
<select name="showrooms" class="form-control">
</select>
</div
Ajax
$('select[name=brands]').change(function(){
brand_id = $(this).val();
request_url = '/sales/get_showrooms/' + brand_id + '/';
$.ajax({
url: request_url,
success: function(data){
$.each(data, function(index, text){
$('select[name=showrooms]').append(
$('<option></option>').val(index).html(text)
);
};
});
You can make the RESTful calls in request_url.
You can further populate the third dropdown based on the selection in second and so on. Also, you can access the selected option and perform the further stuff.
The chosen plugin can help you in optimizing your dropdowns.
I would go for a REST service, like Django Rest Framework, and then use jquery to autopopulate the dropdowns.
If installing a REST service is a hassle, you could write a couple of views to get the data in json format...
For instance, if you have a REST service in /myapp/api, you could populate the Cars like this:
$.ajax({
url: "/myapp/api/cars?format=json",
dataType: "json",
success: function( data ) {
var makes=[];
for (var i in data) {
car = data[i];
if (makes.indexOf(car.make) < 0){ // avoid duplicate brands
makes.push(car.make);
$('#makeselect').append($('<option>', {
value: car.id,
text: car.make
}));
}
}
}
});
Then, attach a handler when the "make" selector has changed, and populate the model and year accordingly using another REST call, like /myapp/api/cars?make=Ford
I'm not sure what you're confused about. Why would you put every car into a page? When you build a normal non-Ajax page, you pass some data - eg the slug or ID of a database object - via the URL, you query the database for that specific object, and return its data via an HTML template.
The exact same logic applies for Ajax, except that you probably don't want an HTML template; you can just return JSON, which is easy for JS to understand.

How to initialise data on a non model form?

I have a little question regarding Forms / Views which don't use a Model object. I seem to have it set up almost the way it should, but I can't seem to figure out how to pass data around to initialise the fields in my edit form.
What I have to do is get data from a REST server which was developed using Delphi. So this django thingie won't be using the normal django ORM model thing. Currently I have it working so my app displays a list of departmets which it got using a REST call to the server. Each department has it's ID as a hyperlink.
My next step / thing I would like to do is display a form in which the user can edit some values for the selected department. Logically everything seems to be hooked up together the way it should (as far as I can see). Sadly ... for whatever reason ... I can't seem to pass along information about the clicked ID or even the selected object in my list to the detail view.
Would anyone be able to help me out ? This is what I have so far :
The urls.py :
# DelphiClient/urls.py
from django.conf.urls import patterns
from django.conf.urls import url
from . import views
urlpatterns = patterns("",
url(
regex=r"^Departments$",
view=views.DelphiDepartmentsListView.as_view(),
name="Departments"
),
url(
regex=r'^Department/(?P<pk>\d+)/$',
view=views.DepartmentFormView.as_view(),
name='department_update'
),
)
The views.py :
# DelphiClient/views.py
...
from .client import DelphiClient
from .forms import DepartmentForm
class DelphiDepartmentsListView(TemplateView):
template_name = 'DelphiDepartmentList.html'
def get_context_data(self, **kwargs):
client = DelphiClient()
departments = client.get_department()
context = super(DelphiDepartmentsListView, self).get_context_data(**kwargs)
context['departments'] = departments
#client.update_department(1, 'Update From Django')
return context
class DepartmentFormView(FormView):
template_name = 'DepartmentUpdate.html'
form_class = DepartmentForm
success_url = '/DelphiClient/Departments'
def get_initial(self, **kwargs):
"""
Returns the initial data to use for forms on this view.
"""
initial = super(DepartmentFormView, self).get_initial(**kwargs)
# How can I get the ID passed along from the list view
# so I can get the correct object from my REST server and
# pass it along in the Initial ???
return initial
def form_valid(self, form):
# This method is called when valid form data has been POSTed.
# It should return an HttpResponse.
print "form.data {0}".format(form.data)
client = DelphiClient()
client.update_department(form.data["flddepartmentId"],form.data["flddepartmenet"])
return super(DepartmentFormView, self).form_valid(form)
The forms.py :
# DelphiClient/forms.py
from django import forms
from .client import DelphiClient
class DepartmentForm(forms.Form):
# How can I fill in the values for these fields using an object passed in
# thhrough Initial or the context?
flddepartmentId = forms.IntegerField(label="Department ID") #, value=1)
flddepartmenet = forms.CharField(label="New Description", max_length=100)
def update_department(self, *args, **kwargs):
#print "update_department"
#print self.data
#print self.data["flddepartmenet"]
client = DelphiClient()
client.update_department(self.data["flddepartmentId"],self.data["flddepartmenet"])
And the template for the form :
<h1>Update Department</h1>
<p>Update Department? {{ department.flddepartmentid }}</p>
<p>Something : {{ something }}</p>
<form action="" method="post">
{% csrf_token %}
{{ form.as_p }}
<p><label for="id_flddepartmentId">Department ID:</label> <input id="id_flddepartmentId" name="flddepartmentId" type="number" value="1"></p>
<p><label for="id_flddepartmenet">New Description:</label> <input id="id_flddepartmenet" maxlength="100" name="flddepartmenet" type="text"></p>
<input type="submit" value="OK">
</form>
As you can see ... I'm close ... but no cigar yet :-) Since I'm completely new to Python / Django and have been learning on the go, I have no idea what I'm doing wrong or where I should look.
If anyone would be able to help or point me in the right direction it would be really appreciated.
The positional and name-based arguments are stored in self.args and self.kwargs respectively (see the docs on name based filtering). Therefore you can access the pk with self.kwargs['pk'].
I'm not sure that you should include flddepartmentId as an editable field in the form. It means that users could go to /Department/1/, but then enter flddepartmentId=2 when they submit the form. It might be better to remove the field from the form, then use the value from the URL when calling update_department.
client.update_department(self.kwargs['pk'],self.data["flddepartmenet"])
If you are sure that you want to include flddepartmentId in your form, then your get_initial method should look as follows:
def get_initial(self, **kwargs):
"""
Returns the initial data to use for forms on this view.
"""
initial = super(DepartmentFormView, self).get_initial(**kwargs)
initial['flddepartmentId'] = self.kwargs['pk']
return initial

Categories

Resources