How to call external python script in django from a dropdown button on click event in the html

Viewed 1896

I need to run a Jenkins job from a frontend button using Django+Python. I have made a header with html which has dropdown button. From reading many posts I learned that I can trigger my Jenkins job using AJAX. Can someone please tell me how to do that with an example snippets of view.py, and how to redirect it to a new HTML page when firing the on click event.

home.html

<div class="row">
    <div class="col-sm-2">
        <br><br>
        <div class="well bs-sidebar" id="sidebar" style="background-color:#fff">
            <ul class="nav nav-pills nav-stacked">
                <h4>Application B <span class="badge badge-secondary"></span></h4>
            </ul>
        </div>
    </div>

    <div class="col-sm-10">
        <h3>ACTIONS ALLOWED</h3>
        <br>
        <div class="dropdown">
            <button class="btn btn-success btn-md"  type="button" onclick="" data-toggle="dropdown">
                List of scripts available
                <span class="caret"></span>
            </button>
            <ul class="dropdown-menu">
                <li><a href="#">Healthcheck</a></li>
                <li><a href="#">Regresseion Testing</a></li>
                <li><a href="#">Functional Testin</a></li>
                <li><a href="#">Unit Testing</a></li>
                <li class="divider"></li>
            </ul>
            <button class="btn btn-warning btn-md">
                Cick to see the results
            </button><br>
        </div>
    </div>
</div>

<script>
    $(document).ready(function() {
        $('.btn-success').tooltip({title: "Execute", animation: true}); 
        $('.btn-warning').tooltip({title: "Results!@", animation: false}); 
    });
</script> 

urls.py

from django.conf.urls import url
from . import views
urlpatterns=[
   url(r'^$', views.index, name='index'),
   url(r'^hello', views.hello, name='hello'),
]
3 Answers

You are tackling a somewhat advanced Django topic as a newbie, but it should be doable. Note this is a non-Ajax python-only solution, not sure it's exactly what you're looking for, but it would be a common pattern for a Django project.

Create a view (connected to a URL) that will fire off an external python script and display a message. The view could be as simple as:

def fire_job(request):
    exec(open('/path/to/external/script.py').read())
    return render(request, 'some_template.html', {})

The template can say e.g. "Job has started. Please watch your email for updates." Create a URL for the view and link to it from your nav.

That will basically work, but with one big problem: Python is synchronous by default so the user will not see the page until the job has completed.

Aside: During development, try calling a dummy script that will execute quickly but maybe includes something like:

import time
time.sleep(10) # 10 second artificial delay

Later, when everything is working, replace the path to your dummy script with the real thing.

Now you need a queueing system that will let you fire off a process in the background but return the page immediately, and that will send an email when the job is complete. A common solution for this is to use Celery, but I prefer Django_Q because it's simpler to implement, with fewer moving parts.

Here is probably the easiest way to get it done with Django_Q (and while running ./manage.py qcluster in a separate terminal):

def myview(request):
    from django_q.tasks import async, result
        task_id = async(
            'appname.tasks.fire_job',  # dotted path to function
            hook='appname.tasks.report'  # Runs when task completes
        )
        return render(request, 'some_template.html', {})

You now need to create those two functions: appname.tasks.fire_job and appname.tasks.report, changing the paths to match your project. The first one will be a simple function that calls your external script:

# appname/tasks.py
def fire_job():
    exec(open('/path/to/external/script.py').read())

And another that gets fired when that job completes (e.g to send email):

   # appname/tasks.py
   def report():
        # See Django docs on how to send email

That's a bit simplified, but should get you going. Good luck!

template

$(document).ready(function(){
    $('.btn-success').on('click',function(){
       $.get( "{% url 'execute' 'your_param' %}", function( data ) {
           alert( "Done." );
       });
    }); 
});

url

urlpatterns += [
   url(r'^execute/(?P<command>[a-z]+)',views.execute, name='execute'),
]

view

def execute(request,command):
    if command == 'command1':
       # do job 1
    elif command == 'command2':
       # do job 2

    return Response("What you want to get on client as response")

This should look like this: import jenkins

def hello(request):
    if request.method == 'POST' and request.is_ajax():
        server = jenkins.Jenkins('http://localhost:8080', username='myuser', password='mypassword')
        server.build_job('api-test', {'param1': 'test value 1', 'param2': 'test value 2'})
        last_build_number = server.get_job_info('api-test')['lastCompletedBuild']['number']
        build_info = server.get_build_info('api-test', last_build_number)
        return JsonResponse('info': build_info)
Related