i think the title is pretty clear. I want to know when the user clicks the button to run a piece of code in a function in my views.py. lets say i have this html:
<div>
<input type="button" name="_mail" value="Enviar Mail">
</div>
and i want to run this code if the user clicks on it:
send_templated_mail(template_name='receipt',
from_email='robot#server.com',
recipient_list=[request.user.email],
context=extra_context)
that´s all i want to do.
EDIT: this is the view that i have:
def verFactura(request, id_factura):
fact = Factura.objects.get(pk = id_factura)
cliente = Cliente.objects.get(factura = fact)
template = 'verfacturas.html'
iva = fact.importe_sin_iva * 0.21
total = fact.importe_sin_iva + iva
extra_context = dict()
extra_context['fact'] = fact
extra_context['cliente'] = cliente
extra_context['iva'] = iva
extra_context['total'] = total
if (here i want to catch the click event):
send_templated_mail(template_name='receipt',
from_email='imiguel#exisoft.com.ar',
recipient_list =['ignacio.miguel.a#gmail.com'],
context=extra_context)
return HttpResponseRedirect('../facturas')
return render(request,template, extra_context)
You should create this function in your views.py, map it to the url in your urls.py and add event handler using JavaScript (pure JS or using jQuery as shown below):
JS (using jQuery):
$('#buttonId').click(function() {
$.ajax({
url: your_url,
method: 'POST', // or another (GET), whatever you need
data: {
name: value, // data you need to pass to your function
click: true
}
success: function (data) {
// success callback
// you can process data returned by function from views.py
}
});
});
HTML:
<div>
<input type="button" id="buttonId" name="_mail" value="Enviar Mail">
</div>
Python:
def verFactura(request, id_factura):
...
if request.POST.get('click', False): # check if called by click
# send mail etc.
...
Note that if you're going to use POST method you should care about csrf (cross-site request forgery) protection as described HERE
Related
I have a textview in my html template that allows the user to enter text
<textarea name="texteditor" id="texteditor" style="width:100%; height:100vh; resize:none; font-size:20px; font-family:sans-serif; border:none;" placeholder="Start Writing!"></textarea>
I want to get that text on a button click into my view
def write_view(request, *args, **kwargs):
texteditor = request.POST.get('texteditor')
print(texteditor)
return render(request, "write.html", {'texteditor': texteditor})
Is there a solution for this?
You have to use ajax for this.
Add this script in your html file. I have assumed that the url for write_view (in your views.py) is 'url_to_post'. Change it below to suit your requirements.
<script>
$("#texteditor").keyup(function(event){
TextEntered = $("#texteditor").val();
// You can remove the below line, after debugging!
console.log("You have typed the following ",TextEntered);
// You can remove the above line, after debugging!
data = {
'TextEntered':TextEntered, 'csrfmiddlewaretoken':$('input[name=csrfmiddlewaretoken]').val()
};
$.ajax({
type:'POST',
url:url_to_post,
datatype: 'JSON',
data: data,
success: Successfully_Received
})
})
function Successfully_Received(data, textStatus, jqXHR){
console.log("Successfully received by View and acknowledged");
}
</script>
Then I will change your views.py function like below.
def write_view(request, *args, **kwargs):
if request.is_ajax() and request.method == "POST":
texteditor = request.POST['TextEntered']
print(texteditor)
## Don't forget to do validation and cleanup on texteditor to avoid security hassles
## Do your logic here
SuccessAcknowledgment = {"Acknowledged":"Acknowledged"}
return HttpResponse(json.dumps(SuccessAcknowledgment))
else:
return render(request, "write.html")
This is my guesstimate solution, without seeing your code in entirety. Please let me know, if it worked out or not. Thank you.
Basically code works as I expected, but my ListView is not refreshing. Everything works fine, but template does not load itself, I must push reload button (all data are loaded correctly then).
I done simple form/input for testing and there is no problem with views. My project requires calendar widget for picking months, and simplest way to do this I found on the internet was Ajax approach.
Ajax function:
$(document).ready(function () {
$(function () {
$("#datetimepicker1").datetimepicker({
viewMode: 'months',
format: 'MM/YYYY',
}).on('dp.change', function (e) {
var url = "/booking/update_months/{{hotel_id}}";
$.ajax({
type: 'GET',
url: url,
dataType: 'json',
data: {
month: e.date.month(),
},
success: function (data) {
},
error: function (data) {
}
});
})
});
});
Url "/booking/update_months/{{hotel_id}}" refers to first View function I'm using for this functionality:
#csrf_exempt
def update_months(request, hotel_id):
if request.GET.get('month'):
month = request.GET.get('month')
request.session['month'] = int(month) + 1
return HttpResponseRedirect(reverse('booking:hotel_statistics', args=(hotel_id,)))
else:
return render_to_response(request, 'booking/hotel_statistics.html')
Then in HotelStatistics ListView I'm doing some stuff in get_context_data function, nothing special here. Just by some "prints" I've tested that the code is being executed until the end of the class.
class HotelStatistics(ListView):
model = Reservation
context_object_name = 'reservations'
template_name = 'booking/hotel_statistics.html'
def get_context_data(self, **kwargs):
.
.
.
return context
I'm pretty sure that I'm missing something with Ajax functionality, It's my first approach to this language. Thanks in advance for your help.
Why are you using AJAX here? Unless I am missing something, you should just have the date picker inside an HTTP GET form that is submitted.
template.html
<!-- The action attribute hardcoded URL value should be replaced with a Django url templatetag. This will allow the url to be resolved based on the router configuration. i.e. {% url "booking:update_months" hotel_id %} -->
<form action="/booking/update_months/{{ hotel_id }}" method="GET">
<input id="date" name="date">
<button type="submit">Update</button>
</form>
<script>
$(document).ready(function() {
$("#date").datetimepicker({
viewMode: 'months',
format: 'yyyy-mm-dd',
});
});
</script>
view.py
#csrf_exempt
def update_months(request, hotel_id):
date = request.GET.get("date")
if date:
request.session["month"] = datetime.strptime(date, "%Y-%m-%d").month
return redirect("booking:hotel_statistics", False, hotel_id)
return render(request, "booking/hotel_statistics.html")
The code above submits an HTTP GET form, resulting in a server side 301 and therefore a "refresh" of your statistics page with the update session data.
Notice, we are sending up the full date information. I am not sure if you are doing this separately, but if you are allowing users to update each date part independent, you could now bring that together into a single update_date function.
like same problem but not solve--> Send Dynamic AJAX URL in Django
i want to data extraction by using dynamically url.
urls.py
url(r'^(?P<idx>\d+)/rapor/$',ReportView.as_view(),name='rapor'),
url(r'^(?P<idx>\d+)/rapor/hamveri/$',ChartData.as_view(),name='hamveri'),
report.html
var endpoint ='/analiz/{{ data.id }}/rapor/hamveri/';
var defaultData = [];
var labels = [];
$.ajax({
method: "GET",
url: endpoint,
success: function(data){
labels = data.labels;
defaultData = data.default;
setChart()
},
error: function(error_data){
console.log("error");
console.log(error_data)
}});
well-done data send to web address but i can't data extraction from this url
http://127.0.0.1:8000/analiz/33/rapor/
how can i fixed this problem?
if i edit report.html
report.html
var endpoint ='/analiz/33/rapor/hamveri/';
perfect-run web site, it can data extraction from 'analiz/33/rapor/hamveri/'
and so;
http://127.0.0.1:8000/analiz/33/rapor/
but not dynamically url :(
Thanks in advance for your help.
What you can try is:
Write this HTML just before the JavaScript starts.
Then change the variable:
var endpoint ='/analiz/{{ data.id }}/rapor/hamveri/'; as described below,
Somewhat like this:
<div id="endpoint-url-div" url="{% url 'hamveri' data.id %}" style="display: none;"></div>
<script type="text/javascript">
var endpoint = document.getElementById('endpoint-url-div').getAttribute('url');
//Now endpoint should have a URL like **/analiz/33/rapor/hamveri/**
//Add the rest of your JavaScript as it is.
var defaultData = [];
var labels = [];
$.ajax({
method: "GET",
url: endpoint,
success: function(data){
labels = data.labels;
defaultData = data.default;
setChart()
},
error: function(error_data){
console.log("error");
console.log(error_data)
},
});
</script>
Make sure that variable is sent correctly from your views. Make sure you have a variable inside your context dictionary inside the views.
views.py must have something like:
context = dict()
context['data'] = #Some data model object
EDIT:
As I can see in your analiz/views.py, you are not sending any idx or model data object to your repor.html.
Not sending idx or model data object to repor.html will not give you a url like: /analiz/33/rapor/hamveri/ inside the variable endpoint.
In your views, you have to send a model object
class ReportView(View):
def get(self, request, *args, **kwargs):
data = UploadFile.objects.get(...) #Get the model object here. Put something like: user = request.user
context = {'data' : data}
return render(request, 'analiz/rapor.html', context)
Now in your HTML:
<div id="endpoint-url-div" url="{% url 'hamveri' data.id %}" style="display: none;"></div>
<script type="text/javascript">
var endpoint = document.getElementById('endpoint-url-div').getAttribute('url');
...
...
... #Rest of the Javascript# ...
...
</script>
Yes, well-done
i make mistake in a critical point.
#shivamsharma said that you are not sending any idx or model data object to your repor.html.
So this function:
class ReportView(View):
def get(self, request,idx,*args, **kwargs):
return render(request, 'analiz/rapor.html', {'dataninidx':idx}) # added new key
Then i change variable in report.html
var endpoint='/analiz/{{ dataninidx }}/rapor/hamveri/';
Yes, the program only works with two changes.
Thanks for your help, #shivam-sharma
I'm trying to implement a search bar to query my database and show only the matches. When I hit submit it just gives me back 'SEARCH', which is what I set as the default instead of printing an error.
ajax.py
...
def chunkSearcher(request):
test = request.GET.get('search_box', "SEARCH")
print(test)
....
Searcher.html
<form type="get" action="." style="margin: 0">
<input id="search_box" type="text" name="search_box" value="Search..." >
<button id="search_submit" type="submit" >Submit</button>
urls.py
url(r'^ajax/chunk/Searcher/$',
ajax.chunkSearcher, name='chunkSearcher')
views.py (It actually works here for some reason but it won't recognize the same two lines of code in my ajax code
def searcher(request):
# test = request.GET.get('search_box', "SEARCH")
# print(test)
this_main = Searcher(
request = request,
num_elements = Candidate.objects.all().count(),
size = 'col-xs-12',
title = 'Search',
modelname = 'Searcher',
listing_fields = [
{'readable_name': 'Name', 'model_attribute': 'full_name()', 'subtext_model': 'email', 'color': 'False'},
{'readable_name': 'Status', 'model_attribute': 'get_status_display()', 'color': 'True'},
{'readable_name': 'Automated Status', 'model_attribute': 'get_auto_status()', 'color': 'True'},
{'readable_name': 'Submitter', 'model_attribute': 'submitter', 'color': 'True'},
],
listing_actions = [
{'tooltip': 'Search', 'color': 'success', 'icon': 'plus', 'permission': 'prog_port.add_candidate', 'modal': 'candidateform', 'controller': 'addCandidate'},
],
)
context = {
'nav' : Nav(request),
'main' : this_main,
'fb' : TestFeedback()
}
return render(request, 'prog_port/base.html', context)
widgets.py
class Searcher:
def __init__(self, request,
num_elements,
size = 'col-xs-12',
modelname = None,
title = None,
listing_fields = None,
listing_actions = None):#!!
self.template = 'prog_port/widgets/Searcher.html'
self.size = size
self.modelname = modelname
self.num_elements = num_elements
self.num_pages = int(math.ceil( num_elements / 25.0))
self.title = title
self.listing_fields = [x['readable_name'] for x in listing_fields]
self.listing_actions = listing_actions
for action in self.listing_actions:
action['restricted'] = False
if 'permission' in action:
if not request.user.has_perm(action['permission']):
action['restricted'] = True
Getting this working without Ajax would be a bit quicker to start. When the action attribute of your form is pointed towards the URL of the current page (rather than towards the URL of your ajax view), the GET request is sent to the view that corresponds to that page's URL - your searcher view in your case. That's why you were able to get the expected values to print when you had those two lines in that view.
Importantly, since the searcher view is the one rendering your page, having access to your search_box value in that view lets you filter or otherwise manipulate the queryset being passed into the view's context and ultimately display only the restricted/filtered items you want shown.
A separate Ajax view doesn't have access to all of that stuff right off of the bat. To dynamically update your search results with a separate Ajax view, that view will need to respond to your request with all of the information necessary to re-render the page appropriately. Practically speaking, that usually means one of two things:
Your search results are displayed within a div or other defined content area, and your Ajax view returns the HTML necessary to populate that content area with the appropriate stuff, or
Your initial view renders its template based on some serialized JSON, and your Ajax view provides updated information in that format which is then used to re-render the template.
This is a good starting point for getting the hang of ajax with django. Notice in the example code given how the view responds to the ajax call with some data (a HTTPResponse or a rendered template), and how that data is then used in the success/failure functions.
If your ajax view returned the HTML necessary to render search results, you could use your success function to update the search results div (or table or whatever) on your page with that new HTML. For example:
views.py
def index(request):
return render(request, "index.html")
def ajax_update(request):
return HttpResponse("<h1>Updated Header</h1>")
index.html
...
<div id="update_this_header">
<h1>Old header</h1>
</div>
<button id='updater'>
...
<script>
$("#updater").click(function() {
$.ajax({
url: #url to ajax_update view
success : function(data) {
$("#update_this_header").html(data)
},
failure : function(data) {
...
}
});
});
</script>
Now clicking the updater button should update the contents of the update_this_header div with the HTML returned in the HttpResponse from our ajax_update view (I admit I didn't test this, forgive me if there's a typo). Updating your search results works the same way; you just need to do more processing in your ajax view to respond with the correct HTML.
I hope this helps make things somewhat clearer; please let me know if I can (try to) explain anything more fully. The important takeaway here is that an ajax view will provide you with Some Data. It's up to you to make sure your template can take that data and properly display it.
I have a Django app that uses React to create a Newsfeed component. When the React Newsfeed component mounts, it makes an ajax call to the Django API to get the current user, and sets the author of a new post to the current user. Below is the code for the new post form React component:
var NewPost = React.createClass({
getInitialState: function() {
return {
author: 'Default Author'
}
},
getUser: function() {
$.ajax({
url: this.props.url + "user/",
dataType: 'json',
method: 'GET',
success: function(data){
this.setState({author: data.fields.first_name});
}.bind(this),
error: function(xhr, status, err) {
console.error("Error with API", status, err.toString());
}.bind(this)
})
},
componentDidMount: function(){
this.getUser();
},
handleSubmit: function(event) {
event.preventDefault();
var author = this.state.author;
var content = React.findDOMNode(this.refs.content).value.trim();
if (!content) {
return;
}
this.props.onPostSubmit({author: author, content: content});
React.findDOMNode(this.refs.content).value = '';
return;
},
render: function() {
return (
<div className="panel panel-default">
<div className="panel-body">
<form onSubmit={this.handleSubmit}>
<div className="form-group">
<textarea className="form-control" ref="content" placeholder="Whats Up" rows="3" id="newpost-input" />
<br/>
<input type="submit" className="btn btn-primary" id='newpost-submit' value="Submit" />
</div>
</form>
</div>
</div>
)
}
});
When I test this code manually everything works the way it should. I login, make a post, and my name is displayed as the author of the post. But when I test this using Selenium, the author is 'Default Author'; it is not getting changed. In my Selenium test I login to my app with my login credentials, and everything works as it should, except that the author of the post is not being changed from 'Default Author' to my name.
At first I thought that Selenium was doing its work before the ajax call had time to finish. So I added some wait times to my Selenium tests but the author name never gets changed. Any ideas why the ajax call seems to not be working?
UPDATE
Here is the relevant Selenium code:
class FunctionalTest(LiveServerTestCase):
def login(self):
self.browser.find_element_by_id('username').send_keys(LOGIN['USERNAME'])
self.browser.find_element_by_id('password').send_keys(LOGIN['PASSWORD'] + '\n')
def create_post(self, content=""):
self.browser.find_element_by_id('newpost-input').send_keys(content)
self.browser.find_element_by_id('newpost-submit').click()
def test_correct_author_name_is_displayed(self):
self.login()
self.create_post('A Post')
self.assertIn("Jonathan", self.browser.find_element_by_id('newsfeed').text)
I know the login with my credentials is successful because I added {{user}} to my django template, and added a print statement to the selenium test to print the text of the body and {{user}} is correctly displayed as my username.
Another test I did was to see if the react function componentDidMount was being called. In the componentDidMount function I did this:
componentDidMount: function() {
console.log("component mounting");
this.getUser();
console.log("component mounted");
},
In addition to that I also added console.logs to the success and error functions of the getUser ajax call. The console.logs from the componentDidMount function work, but the console.logs inside the ajax call do not.