Tuesday, February 7, 2012

Upload Files to a Django form

Decided to add a little feature to the Remixerator the other day - the ability to supply your own base kickstart file. Django has a Filefield widget for its forms that make this work like magic. The form looks a bit like this.


class KickstartForm(forms.Form):
    select_language = forms.ChoiceField(choices=languages(), initial='en_US')
    select_timezone = forms.ChoiceField(choices=timezones())
    name_of_the_spin = forms.CharField()
   
    ks_choices = ((None, 'Use your own!'),) + ls_ks()
    based_on = forms.ChoiceField(choices=ks_choices)
   
    uploaded_kickstart = forms.FileField()
    # ... Set the widget css...



I then tossed in a little jquery to hide the form until the "Use your own!" option is selected...


// Show the "upload file" portion if the user decides to use their own kickstart file
$("#id_based_on").change(
  function() {
    if( $('#id_based_on option:selected').text() == 'Use your own!' ) {
      $("label[for='id_uploaded_kickstart']").show('fast');
      $('#id_uploaded_kickstart').show('fast');
    } else {
      $("label[for='id_uploaded_kickstart']").hide('fast');
      $('#id_uploaded_kickstart').hide('fast');
    }
  });


Next comes the handler for actually dealing with the file, which gets sent along with a POST


def handle_uploaded_ks(uploaded_ks):
    # MEDIA_ROOT defined with django settings, mine is set to a temp cache
    ks_path = os.path.join(settings.MEDIA_ROOT, uploaded_ks._name)
    print ks_path
    destination = open(ks_path, 'wb+')
    for chunk in uploaded_ks.chunks():
        destination.write(chunk)
    destination.close()


Then I needed to go to the view that handles the POST and make it execute the handler.

# The package view (page after the form)

def packages(request):
    """
    Select packages and groups
    """
    # if the user is uploading their own kickstart file, toss it in the cache directory
    if request.FILES:
        handle_uploaded_ks(request.FILES['uploaded_kickstart'])


And finally, we had to allow the form to handle all of this. This is simply done through the form tag's enctype in the html...
<form method="POST" action="/packages/" enctype="multipart/form-data">
    {{ form.as_p }}
    <input type="submit" value="Next" id="nextButton"/>
</form>




Tuesday, January 10, 2012

Python on Android with Kivy


So, it took some tinkering, but I managed to get python working on android using the python-for-android project that allows python kivy applications to run on an android device. I did stumble upon a few issues, though, so I'll describe my steps below.

Original Instructions can be found at the project's github page, and Mathieu Virbel's blog.

The general steps are making sure that you have all the SDK and NDK tools ready, recompiling python against Android (ARM processor), create a python distribution, and using that distribution to build an APK from your Kivy Application. Kivy is necessary to actually render an interface on the screen for user feedback, and overall it's a pretty promising multi platform UI framework. Other toolkits based on something other than OpenGL ES 2.0 can potentially work, should other java bootstraps get created in the future. As of right now, the android-for-python project is providing only a single java bootstrap to handle touch input and audio output, with support for more of android's features on the way.

Note: I used Ubuntu 11.10 to mimic the creator's environment.

Step 0: Get the SDK and NDK here:
http://developer.android.com/sdk/index.html
http://developer.android.com/sdk/ndk/index.html


Step 1:
After downloading this, run SDK program in android-sdk-linux/tools/android
Download the appropriate version of the API. For me, this was version 10 (running on 2.3)


Step 2:
Export necessary variables that are used in the configuration script
Make sure that the NDKVER and API numbers match those that you downloaded and installed.
export ANDROIDSDK="Location/android-sdk-linux"
export ANDROIDNDK="Location/android-ndk-r#"
export ANDROIDNDKVER=r#
export ANDROIDAPI=##


Step 3: get the minimal environment for building python
sudo apt-get install build-essential patch git-core cache


Step 4: clone the python-for-android project
git clone https://github.com/kivy/python-for-android.git


Step 5: Create the python distribution. This is where I first ran into problems.
ideally, you this will work by simply using the distribute.sh script
./distribute.sh -m "kivy package1 package2…"

(available packages are jpeg pil png sdl sqlite3 pygame kivy android libxml2 libxslt lxml ffmpeg openssl with more being created as the project moves forward, see the github repository's readme to contribute to this growing list)

However, here are some issues I ran across when trying to create a python distribution.
  - outdated awk tool. You may get an error message saying that AWK_HOME is referencing an old version of awk. Install a new version of awk, go into your android-ndk-r#/prebuilt/linux-x86-orx64/ directory and rename awk to awk_ so that the build script uses the global awk tool. If that doesn't work, have the AWK_HOME variable point to gawk instead.
  - missing NDK tools. The distribute script refers to the android-ndk-r#/platforms/android-##/ directory that refers to your selected version of the API denoted by the ANDROIDSDK export. However, your NDK might not contain contents for your selected version. For example, r7 of the NDK does not contain contents for version 10 of the API. This might be because its tools refer to the tools included in the existing android-9 directory. Either way, if your version of the API doesn't have a corresponding directory, create one, and copy the contents of the previous version into it.


Step 6: Create an APK using the build.py script in /python-for-android/dist/default (unless you specified a different location for the python distribution)

Package your APK using the following command:
python build.py --dir location_of_your_kivy_application --package your.package.name --name "My Application" --version # debug

If you are unfamiliar with kivy applications, you should check this out.
There are also android requirements for kivy applications:


Step 7: Deploy to android by executing the following command as root.
sudo location_of_sdk/platform-tools/adb install -r location_of_distribution/bin/app_name-version-debug.apk

Note that if it says you do not have correct permissions, you will need to restart adb and re-start it as root by doing the following commands:
adb kill-server
sudo adb start-server

Learn more about the adb tool here:
http://developer.android.com/guide/developing/tools/adb.html


So, with this success, I just need to think of something to create.