Django Forms Choice Tutorial Sample Code

Lately I have been playing with Django!! Its a really amazing Python Web Framework that can help anybody with small experience in web frameworks and python language to create amazing web sites.


One of the biggest advantages of using Django is the really detailed documentation. Please check yourself at https://docs.djangoproject.com/en/1.10/.


In this tutorial I am going to show a quick example of creating a simple form with 3 comboboxes that will take some data from 3 tables and save the choices to a 4th table. The sample output will be as following:




Before we start:
For the above scenario we are going to have 3 simple models - tables: Category, Service, Criteria and a more complex one which will store 3 foreign keys for those 3 tables.

Implementation:
1. models.py
The trick here is to have __unicode__ function defined. This will help our comboboxes to populate a unicode string representation of our model. 
The __str__ function is used by our Django Admin site
I usually add created_at and updated_at fields for every model I create. I have found it usefull in many cases.
from django.db import models


class Service(models.Model):
    """    Service Model.     """    name = models.TextField(max_length=200, help_text='Service Name')
    short_code = models.TextField(max_length=15, help_text='Service Short Code') 
    created_at = models.DateTimeField(auto_now_add=True, editable=False)
    updated_at = models.DateTimeField(auto_now=True, editable=False)

    def __str__(self):
        return self.name + ' code: ' + self.short_code  

    def __unicode__(self):
        return self.name + ' code: ' + self.short_code  


class Category(models.Model):
    """    # Template Messages Categories (e.g. Help, Bulk, etc    """    name = models.TextField(max_length=200, help_text='Template Message Category. e.g. HELP, STOP, etc')
    description = models.TextField(max_length=1000, help_text='Template Message Category Description')
    created_at = models.DateTimeField(auto_now_add=True, editable=False)
    updated_at = models.DateTimeField(auto_now=True, editable=False)

    def __str__(self):
        return self.name

    def __unicode__(self):
        return self.name


class SubscriptionCriteria(models.Model):
    """    Criteria for Selecting Users to bulk    """    name = models.CharField(max_length=50, help_text='Name your Subscription Criteria')
    description = models.TextField(max_length=1000, help_text='Describe your Subscription Criteria')
    created_at = models.DateTimeField(auto_now_add=True, editable=False)
    updated_at = models.DateTimeField(auto_now=True, editable=False)

    @property    def __str__(self):
        return self.name

    def __unicode__(self):
        return self.name
    
    
class BulkWorker(models.Model):
    """    A Bulk Worker saves the progress of a worker .....     """    task_id = models.TextField(primary_key=True, max_length=150, help_text='Celery task Id')
    launched_at = models.DateTimeField(auto_now_add=True, editable=False)
    charged_at = models.DateTimeField(editable=True, default=None)
    state = models.TextField(max_length=1000)  # TO ADD Exceptions    percent = models.IntegerField(default=0)
    service = models.ForeignKey(Service)
    message_category = models.ForeignKey(Category, default=1)
    criteria = models.ForeignKey(SubscriptionCriteria, default=1)
    created_at = models.DateTimeField(auto_now_add=True, editable=False)
    updated_at = models.DateTimeField(auto_now=True, editable=False)

    def __str__(self):
        return "Worker started at " + str(self.launched_at) + " for service " + str(self.service)
2. views.py
Now that we have our models we can create the views.py. 
In home view we just load an empty BulkForm. BulkForm is created below in forms.py
We also add bulk Task to save form data
# coding=utf-8# Create your views here.from __future__ import print_function

from django.contrib.auth.decorators import user_passes_test
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.views.decorators.csrf import csrf_exempt

from .forms import BulkForm


@user_passes_test(lambda u: u.is_superuser)
@csrf_exemptdef home(request):
    """    Main View Page for Bulk Tasks    :param request:    :return:    """    form = BulkForm()
    return render_to_response('bulk.html', {'form': form}, context_instance=RequestContext(request))


def add_bulk_task(request):
    """    Add in db a bulk task    Send to start task    :param request: POST object should be a Request object    :return: HttpResponse    """    context = RequestContext(request)

    if request.method == 'POST':
        form = BulkForm(request.POST)

        if form.is_valid():
            form.save() # commit = True by default            json_data = 'Bulk Task saved fine'        else:
            json_data = 'Form is not valid'    else:
        json_data = 'Only POST requests are allowed'    return HttpResponse(json_data, content_type='application/json')

3. forms.py 
In our forms.py we use ModelChoiseField to load the foreign keys. As widget we use forms.Select as we only want to select one value. We query and get all objects populated for all referenced tables in queryset

from django import forms
from .models import BulkWorker, Service, SubscriptionCriteria, Category


class BulkForm(forms.ModelForm):
    """    Create Form for Sending Bulk Requests    """    service = forms.ModelChoiceField(widget=forms.Select, queryset=Service.objects.all())
    message_category = forms.ModelChoiceField(widget = forms.Select, queryset=Category.objects.all())
    criteria = forms.ModelChoiceField(widget = forms.Select, queryset=SubscriptionCriteria.objects.all())

    class Meta:
        model = BulkWorker

4. templates/bulk.html
Lastly we should add the template code so that django will replace data from view.
With Django its the easiest thing to do!
We just need 5 lines of code.
Note: csrf_token is used to prevent cross site forgery attacks
so the line that does all the work is {{form.as_p}} 
we cound have used of course the simple {{form}} with the same results, I just wanted to put the form in a paragraph (<p> element)
<div id="bulk-form">    <form id="BulkForm" action="save_bulk" method="post">        {% csrf_token %}
        {{ form.as_p }}
     <input type="submit" name="submit" value="Create BULK Task" />    </form></div>


5. urs.py
Lastly we should add our page in urls.py as simple as following
url(r'^bulk$', 'amusely.views.home', name='bulk'), 
url(r'^save_bulk$', 'amusely.views.add_bulk_task', name='save_task'),



As always comments are welcomed. I would be glad to see what you think or help you. CU next time

Σχόλια

Δημοφιλείς αναρτήσεις