Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django execute cmd application

Tags:

python

django

from django.db import models
import os
from django.db.models.signals import post_save
import sys

class Form(models.Model):
    site = models.CharField(max_length=50)
    num = models.CharField(max_length=10)
    octet = models.CharField(max_length=30)

    def __unicode__(self):
        return self.site
        return self.num
        return self.octet

def create_conf(sender, **kwargs):
    os.system("/usr/local/build " + self.site + ' ' + self.num + ' ' + self.octet)

post_save.connect(create_conf, sender=Form)

Trying to get my django web app to execute python command line application with arguments. Not sure if this is the best way to go around it? If its not any advice would be great. Trying to take input from user via web form and use it as the arguments to execute cmd application.

Help would be fantastic

Thanks William

like image 504
LinuxBill Avatar asked Sep 13 '13 15:09

LinuxBill


3 Answers

This seems to be a good way if you want to execute the command at each save() of your objects.

However, you should sanitize your inputs: if users set some special characters (,, ; or & for example) it could break your command and it could be risky for your system (for example a && rm -rf /* in octet could be fun here :p). You should look at this answer which uses Popen to secure parameters:

from subprocess import Popen  

def create_conf(sender, instance, **kwargs):
     p1 = Popen(["/usr/local/build", instance.site, instance.num, instance.octet])

I also fix the function declaration to get the instance, according to the documentation.

Another thing: your __unicode__ function is incorrect, you can't return 3 values like this.

class Form(models.Model):
    site = models.CharField(max_length=50)
    num = models.CharField(max_length=10)
    octet = models.CharField(max_length=30)

    def __unicode__(self):
        return "%s %s %s" % (self.site, self.num, self.octet)
like image 123
Maxime Lorant Avatar answered Sep 20 '22 09:09

Maxime Lorant


Why this code doesn't work is explained in another answer, I'm just answering his questions for the next time something like this happens.

Would like advice on how to debug why this is not working.

def create_conf(sender, **kwargs):
    import pdb
    pdb.set_trace()
    os.system("/usr/local/build " + self.site + ' ' + self.num + ' ' + self.octet)

This will give you the built-in Python debugger, in the console runserver is running. With it, you can go trough your code step by step, and execute regular Python commands (like print).

Read up on the commands for inside the debugger here Some IDEs come with Python debugging support, and present it with a nice GUI.

When using it a lot: use the oneliner:

import pdb; pdb.set_trace;  # yes, Python supports semicolons 
                            # (although its not recommended)

And to make sure that the strings are being passed through from django web page to arguments on cmd application.

You can either:

cast them to strings to make sure

os.system("/usr/local/build " + str(self.site) + ' ' + str(self.num) + ' ' + str(self.octet))

or use the string formatter (which is better than using the + sign and makes sure input gets cast to strings)

os.system("usr/local/build {0} {1} {2}".format(self.site, self.num, self.octet))

Read up on the string .format method here

like image 40
Maikel Wever Avatar answered Sep 19 '22 09:09

Maikel Wever


  1. Would like advice on how to debug why this is not working.

You can use the python / django logging mechanism and throw logging information wherever needed. In short:

import logging
logger = logging.getLogger(__name__) # Get an instance of a logger
my_custom_command = "/usr/local/build " + self.site + ' ' + self.num + ' ' + self.octet
logger.warning(my_custom_command)

prints a warning message to console. If you use the django debug toolbar (highly recommended!), you can easily log using the .debug-level (not .warning) and see the results on the web page.

You can include those logging messeges on every intended step of your work flow and check whether everything is as it should be.

I'm doing something like this (compiling c-code which is prvided by the user) using the following code snipplet:

    try:
        cfile = os.path.join(MEDIA_ROOT, 'temp/src/cfile.c')
        ofile = os.path.join(MEDIA_ROOT, 'temp/src/cfile.o')
        efile = os.path.join(MEDIA_ROOT, 'temp/src/cfile.exe')
        command_string = 'gcc -O0 -g3 -Wall -c -fmessage-length=0 ' + cfile + ' -o ' + ofile
        compile_result = subprocess.check_output(command_string,stderr=subprocess.STDOUT,shell=True)
        if compile_result != "": #Compile error
            self.ausgabe = "Compile:\n"
            self.ausgabe += str(compile_result)
    except:
        self.ausgabe = u"Compilierfehler:\n"
        self.ausgabe += str(compile_result)

(please ignore the German words, they are not important for understanding the logic)

One additional thing which might be important is to use correct encoding for all strings.

like image 43
OBu Avatar answered Sep 22 '22 09:09

OBu