Django: create a "changing button" or waiting page - javascript

I have an external python program, named c.py, which "counts" up to 20 seconds.
I call it from my Django app views.py and in the html page I have a button to start it. It's ok (= in Eclipse I can see that c.py prints 0,1,2,3,...20 when I press the button on the webpage) but I would like that the button changes from "GO" to "WAIT" during c.py process (or I would like to perform a waiting page during the counting or also a pop-up).
c.py
import time
def prova(z):
z = 0
while z < 20:
time.sleep(1)
z = z + 1
print(z)
views.py
from django.shortcuts import render_to_response
#etc.
import c
def home_user(request):
return render_to_response('homepage/home.html',{'user.username':request}, context_instance = RequestContext(request))
def conta(request):
c.prova(0)
return redirect(home_user)
where in homepage.html I have the "GO" button that I would like to change in "WAIT" if the function conta is running.
urls.py
urlpatterns =patterns('',
url(r'^homepage/home/$', views.home_user, name='home'),
#etc.
url(r'^conta', views.conta, name='conta'),
)
home.html
{% if c.alive %}
WAIT
{% else %}
GO
{% endif %}
I don't put the whole code.. I hope this is sufficient to understand my trouble.
I also see at How to create a waiting page in Django but I would start with something simpler.
Up to now when I start c.py I see that my web page is loading something (=it is "counting") but my button does not change and, after c.py execution, I return to 127.0.0.1:8000/homepage/home/ page.
Is the problem in html or in my function definition or both?
UPDATE
I try to simplify the question:
I found this script...
<button onclick="myFunction()">Try it</button>
<p id="demo"></p>
<script>
function myFunction() {
var text = "";
var i = 0;
while (i < 10) {
text += "<br>The number is " + i;
i++;
}
document.getElementById("demo").innerHTML = text;
}
</script>
I would like to "import" my conta() function in while instead of the cicle with i++
i.e. I would like to have a similar thing:
while conta() is running, appear something like Waiting.. and when it stop i return to my home page.. I don't know how "put" conta() in the script.. is this possible? Am I a dreamer? :)

You're trying to check a server-side value on the client, but the problem is that the if c.alive statement only gets evaluated when your view is rendered - not as the status of c changes.
You would need to be able to report back the status of c to the client via ajax long polling or WebSockets, or, if you don't care about the incremental status of c and just want to change the text of the link, you'll need to use JavaScript to set the value when the click event of the link fires:
// assuming jQuery for brevity...
$(document).ready(function() {
// avoid hard-coding urls...
var yourApp = {
contaUrl: "{% url 'conta' %}"
};
$('#btnGo').click(function(e) {
e.preventDefault(); // prevent the link from navigating
// set css classes and text of button
$(this)
.removeClass('btn-primary')
.addClass('btn-danger')
.text('WAIT');
$.get(yourApp.contaUrl, function(json) {
window.top = json.redirect;
});
});
});
but... your conta function will need to return a JsonResponse instead of an HttpResponse in order to do the redirect on the client-side:
from django.core.urlresolvers import reverse
from django.http import JsonResponse
def conta(request):
c.prova(0)
redirect = reverse('name_of_home_user_view')
return JsonResponse({'redirect': redirect})

I post my working solution. Thanks to #Brandon for the useful answer.
in conta.js some changes:
$(document).ready(function() {
// avoid hard-coding urls...
var yourApp = {
contaUrl: "/conta/"
};
$('#btnGo').click(function(e) {
e.preventDefault();
// set css classes and text of button
$(this)
.removeClass('btn-primary')
.addClass('btn-danger disabled') // with *disabled* I'm sure that the button is not clickable
.text('WAIT');
$.get(yourApp.contaUrl, function(json) {
alert("I have finished counting");
parent.window.location.reload(true);
});
});
});
in views.py
def conta(request):
c.prova(0)
redirect = reverse('home')
return JsonResponse({'redirect': redirect})

Related

Confirmation button on save button like delete already has

I want to modify Django admin interface.
There is delete button already has a confirmation page. But I want to add this confirmation to save or change buttons. Actually not exactly the same delete button.
I want to change default admin buttons like this JS or I want to add JS to admin buttons.
<input type="submit" onclick="linkSubmit('http://www.google.com')" value="Submit">
<p id="demo"></p>
<script>
function linkSubmit(link) {
let text = "Press a button!\nEither OK or Cancel.";
if (confirm(text) == true) {
window.location.href = link;
} else {
}
document.getElementById("demo").innerHTML = text;
}
</script>
We found the solution in the files of the delete command. We took copies of the files confirm to the delete function and connected them to the confirm button.
We still can't give it as a alert. Gives confirmation on a another page.
Assuming there is already some type of event listener for the button I would add my own custom function as an additional listener for the on click event. Then I would put in my if(confirm) logic and call event.stopImmediatePropagation() as needed to prevent the original functionality from occuring.
Create templates/admin/change_form.html in your project:
{% extends "admin/change_form.html" %}
{% block admin_change_form_document_ready %}{{ block.super }}
<script id="django-admin-form-change-constants"
data-model-name="{{ opts.model_name }}">
let modelName = document.getElementById('django-admin-form-change-constants').dataset.modelName;
let form = document.getElementById(modelName + '_form');
form.addEventListener('submit', (event) => {
let text = "Press a button!\nEither OK or Cancel.";
if (!confirm(text)) {
event.preventDefault();
}
});
</script>
{% endblock %}
Set DIRS in myproject/settings.py to point to your project's templates directory:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'templates'],
'APP_DIRS': True,
...
}
]
References:
https://docs.djangoproject.com/en/4.1/ref/contrib/admin/#overriding-admin-templates
https://docs.djangoproject.com/en/4.1/howto/overriding-templates/#overriding-from-the-project-s-templates-directory
https://github.com/django/django/blob/4.1/django/contrib/admin/templates/admin/change_form.html#L66-L74
https://github.com/django/django/blob/4.1/django/contrib/admin/static/admin/js/change_form.js#L5

Why does return jsonify() in flask goes to the API page instead of changing the page?

I am trying to make an upvote/downvote system on my Flask website, and I am trying to implement it using AJAX so the page won't reload every time there is an upvote or a downvote.
My flask application for project is:
#main.route('/project', methods=['GET', 'POST'])
def project():
...
return render_template('project.html', projects = all_projects, popular = liked_projects, recent = recent_projects,
users = all_users, comments = all_comments, followed = followed_projects, joined = joined_projects, my = my_projects, projectMember = projectMember)
My flask application for the upvote button is:
#main.route('/projects/upvote/<int:id>')
def projectupvote(id):
post = projectPosts.query.get_or_404(id)
post.likes += 1
db.session.commit()
return jsonify({"likes":post.likes})
My HTML is:
Up vote
Down vote
<h1 style="margin-bottom:5%; display: inline-block;" id = 'likes'> {{project.likes}}</h1>
And my JS application is:
$(document).ready(function() {
$('a').on('click', function(event) {
$.ajax({
data : {
likes : $('#likes').val(),
},
type : 'GET',
url : '/project'
})
.done(function(data) {
$('#likes').text(data.likes).show();
});
event.preventDefault();
});
});
When running the code, instead of updating the likes while staying on the page, it leads me to this:
It gives the correct data, but moves to another page displaying the raw JSON data of the likes.
Why does it happen and how to go about the situation? I have been researching for hours but couldn't get to the bottom of it.

Django 3. Having trouble passing dropdown menu selection from .html to forms

I'm still new to Django (2 weeks or so). I've been struggling the past few days with passing a string from an html file to forms. My project lets the user choose a state from a dropdown menu (Michigan and Ohio for now, I'll add the rest later). When the state is selected, it will take that string and pull a list of counties of that state from a spreadsheet. This is where the problem lies. I've searched far and wide and I just can't seem to find a solution. The major holdback to many of these solutions is I don't want to "submit" with a button. I want the user to "select" a state, then select a county without a page refresh. I've also included a screenshot of the webpage. So far the dependent dropdowns work perfectly thanks to a youtube tutorial. The "submit" button in the picture is cosmetic for now.
Thanks in advance for helping out. Let me know if you have any questions regarding models or anything else regarding the code.
views.py
def StateForm_Page(request):
context = {}
stateChoice = 'Michigan' //hardcode a state so if the post fails, the function can still find an excel sheet
if request.method == 'POST':
State_Form = StateForm(request.POST)
stateChoice = State_Form.cleaned_data['stateChoice'] //I think this is where my code is failing
else:
State_Form = StateForm()
context['State_Form'] = State_Form
dataArray = pd.read_excel(r'C:\filename.xls', sheet_name= stateChoice)
county_strings = dataArray['County '].values.tolist()
json_county_strings = json.dumps(county_strings)
context['json_county_strings'] = json_county_strings
return render(request, 'StateForm_page.html', context)
StateForm_page.html
<body>
<form action="" method="POST" name="stateChoice">
{% csrf_token %}
{{ State_Form.as_p }}
</form>
<script>
var state;
var county;
$(document).ready(function(){
$('#id_county').empty(); //empties county before state is chosen
$("#id_state").on('change', function(){ //when #id_state is changed...
state = $("#id_state").val(); //assign state with the selection
var countyStrings = JSON.parse('{{ json_county_strings | escapejs }}'); //grabs counties from respective state
var length = countyStrings.length;
var i;
for(i=0; i < length; i++){
county = countyStrings[i]; //update county options with spreadsheet values
$('#id_county').append(
`
<option value ="${county}">
${county}
</option>
`
);
}
});
})
}
</script>
</body>
What the webpage looks like so far:
Next day changes
Hey, after putting a few more hours into it, I'm still not having every luck. Per your suggestions, below is what I've added
views.py
def retrieveState(request):
statePick = request.GET.get('state')
return JsonResponse(statePick, safe = False)
def StateForm_Page(request):
context = {}
stateChoice = []
if request.method == 'POST':
#stateChoice = State_Form.cleaned_data['stateChoice']
State_Form = StateForm(request.POST)
stateChoice = retrieveState(request)
else:
stateChoice = 'Michigan'
State_Form = StateForm()
StateForm_Page.html
$.ajax({
type: 'POST',
url: 'ajax/retrieveState/',
data: state,
dataType: 'json',
});
Good news is something is being triggered on the ajax url I added, but I don't think the function in views is retrieving the ajax data. Any suggestions? Thanks for your help!

python function with Django

Hey guys I have a problem,
I have next function in my views.py:
#userRegistered
def getSyncGit(request, section):
print 'POTATOE' #(<-debug print)
cmd = '. script.sh 1'
p = sp.Popen(['/bin/bash', '-c', cmd], stdout=sp.PIPE, stderr=sp.PIPE)
result = p.wait()
return HttpResponseRedirect(getURL(request.LANGUAGE_CODE, '/assistant/configuration/project/list/'))
At the urls.py:
from .views import getSyncGit
url(r'^/project/sync/$', getSyncGit, {'section':'configuracion'}, name='pgetSyncGit'),
And in my template:
<script type="text/javascript">
function sendSyncProject()
{
$.ajax({url: "{% url 'pgetSyncGit' %}", success: function(result){
alert('cool');
}});
}
</script>
<td>
<input id="butSendSyncProject" type="button" name="butSendSyncProject" style="margin-left:1px;" value="{% trans 'Sinc' %}" onclick="sendSyncProject()" />
</td>
<td>
asdasdasdasdasddas
</td>
When I call to action with button, I can see thealert message, but the getSyncGit function is not executed.
When I call to action with url href, it redirects me to the url "/project/sync/", but the function neither executes....
Try to change your script to a script that writes a line into a file like "echo 'test' > tmp.txt" and tell us if tmp.txt is being created or not
Thank you for your answer #Oliver
I've tried what you've said and it doesn't work.
I've tried the following:
At the urls.py:
from .views import editDeProject
url(r'^/project/edit/0', editDeProject, {'section':'configuracion'}, name='pgetSyncGit'),
And now i have next function in my views.py:
def editDeProject(request, id, section):
"""Page Edit of DB de_project"""
errorTable = ''
form = None
if id == 0:
getSyncGit(request,id,section)
else:
try:
table = DeProject.objects.get(codProject=id)
if request.method == 'POST':
Using this method it works, it prints POTATOE and it generates file.txt, however I'm forcing url.py to take id 0 as an input.
therefore I believe the problem is when the (r'^/project/sync/(?P.*)/' gets generated

use jquery variable in # block razor

I'm strugling with a jquery script inside a cshtml page. For short my question is how to use a var inside a # statement in a cshtml page?
below an example of what I'm trying:
<select id="DefaultText">
<option value="-1">-- select --</option>
#foreach( var d in Model.DefaultTexts )
{
<option value="#d.Id" >#d.Name</option>
}
</select>
<script type="text/javascript">
$('#DefaultText').change(function () {
var id = parseInt($('#DefaultText :selected').val());
var text = #Model.DefaultTexts.First( t => t.Id == id );
$('#CustomProductText').val(text);
});
</script>
I can't reach the var id. It's out of scope. I've also tryed it with a for loop and a if statement. But in the if statement I get the same error: out of scope.
The full story is this:
On my page I've a dropdown list. The items to select are short names for default text parts. Based on the id or name, I want to show the default text part in a textbox.
#CustomProductText is my textbox where the content should be placed (code not posted).
I've also tryed it with #: and statement but that did not work.
What am I doing wrong or maybe its not even possible what I'm trying to do.
As an alternative I've added a action to my controller to get the text form there. Below the code:
<script type="text/javascript">
$('#DefaultText').change(function () {
var id = parseInt($('#DefaultText :selected').val());
$.post("Categories/GetDefaultText", { Id: id }, function (data) {
alert(data);
});
//$('#CustomProductText').val(text);
});
</script>
controller code:
[HttpPost]
public ActionResult GetDefaultText(int id)
{
using( var context = new MyContext() )
{
var text = context.DefaultText.First( d => d.Id == id ).Text;
return this.Content( text );
}
}
This doesn't work. The action doesn't get hit in debug mode.
regards,
Daniel
The $.post that is not working for you, you should prefix the url with / sign and it will be hit as expected:
$.post("/Categories/GetDefaultText", { Id: id }, function (data) {
alert(data);
});
As for the razor solution, you can't use javascript variables in the razor code as it's not a scripting language. What razor does is simply rendering the strings (be it html or javascript or anything) into the page.
To do what you want you either need to request the server to pass the text to your page or render all the texts you have in the page and then access this rendered content in your javascript.

Categories