Archive for the ‘Django’ Category



22
Mar

Request dummies

If you ever need to create a Django request for testing purposes you can use this:

 
import urllib
from urlparse import urlparse, urlunparse, urlsplit
from django.test.client import FakePayload
from django.conf import settings
from django.conf.urls.defaults import *
from django.http import HttpRequest, HttpResponse
from django.utils.http import urlencode
from django.core.handlers.wsgi import WSGIRequest
from django.http import SimpleCookie
 
def create_request(path, data={}, method="GET"):
    parsed = urlparse(path)
    environ = {
        'HTTP_COOKIE':       SimpleCookie().output(header='', sep='; '),
        'REMOTE_ADDR':       '127.0.0.1',
        'SCRIPT_NAME':       '',
        'SERVER_NAME':       'testserver',
        'SERVER_PORT':       '80',
        'SERVER_PROTOCOL':   'HTTP/1.1',
        'wsgi.version':      (1,0),
        'wsgi.url_scheme':   'http',
        'wsgi.errors':       None,
        'wsgi.multiprocess': True,
        'wsgi.multithread':  False,
        'wsgi.run_once':     False,
        'CONTENT_TYPE':    'text/html; charset=utf-8',
        'PATH_INFO':       urllib.unquote(parsed[2]),
        'QUERY_STRING':    urlencode(data, doseq=True) or parsed[4],
        'REQUEST_METHOD':  method,
        'wsgi.input':      FakePayload('')
     }
    return WSGIRequest(environ)
 

It is pretty much a copy&paste from different parts of Django source code. Once you get this dummy request you can invoke actions directly (functions from your views.py)

9
Mar

Setting the selected tab from the template

How to select the main template tabs status from a child template using Django:

base.html:

{% block tabs%}
<ul class="menu">

<li class="{{ SEARCH_TAB_STATUS }}"><a href="/">
<span>{% trans "search_professional" %}</span></a></li>
<li class="{{ REGISTER_TAB_STATUS }}"><a href="/register">

<span>{% trans "want_work" %}</span></a></li>
</ul>
{% endblock %}

register.html:

{% extends "base.html" %}

{% block tabs%}
{% with "inactive" as SEARCH_TAB_STATUS %}
{% with "active" as REGISTER_TAB_STATUS %}
{{ block.super }}
{% endwith %}
{% endwith %}
{% endblock %}

Nice one!!!

19
May

Dynamic and Testable wizard with FormWizard and polymorphism

Very important update: DO NOT USE THE FORMWIZARD for dynamic steps as described below. Django stores the FormWizard as a Singleton so concurrent sessions produce crazy behavior on the wizard. Thanks to my friends at Galotecnia.com because they found the problem. Use the FormWizard just as described in Django documentation and always stateless.

---------------------------
Django FormWizard is really useful. But when it comes to variable steps (I mean, depending on the choosen answer the user gets different forms) you can't just initialize the FormWizard with a bunch of Forms as you don't know which ones. Using polymorphism makes it possible to save lots of code lines by letting each form decide which one is next.

Instead of define your form extending Form, use this base class:

 
class WizardStepForm(forms.Form):
    step_order = 0
    confirmQuestion = "Proceed?"
 
    def process_dynamic_step(self, form_list):
        raise NotImplementedError("Please implement this")
 
    def get_field_name(self):
        raise NotImplementedError("Please implement this")
 
    def get_field_name_for_summary(self):
        fieldname = self.get_field_name()
        firstUpper = fieldname.upper()[0] + fieldname[1:]
        return firstUpper + ":"
 
    def append_end(self, form_list):
        return "", form_list
 

Now we assume our FormWizard will work with WizardStepForms instead of regular Forms:

 
class MyWizard(FormWizard):
    def get_summary(self, form_list):
        """
         To show the user the summary at the last step
        """
        summary = ""
        for i in form_list:
            if hasattr(i, "cleaned_data"):
               if isinstance(i, WizardStepForm):
                  model = i.cleaned_data[i.cleaned_data.keys()[0]]
                  append_text = i.get_field_name_for_summary()
                  append_text = append_text + " " + str(model)
                  summary = summary + append_text + "<br>"
        return summary
 
    def get_hidden_summary(self, form_list):
        """
         Collect the information from all the steps which is in the input hidden field
        """
        summary = ""
        for i in form_list:
            if hasattr(i, "cleaned_data"):
               model = i.cleaned_data[i.cleaned_data.keys()[0]]
               if hasattr(model, "id"):
                   summary  = summary + str(model.id) + ":"
               else:
                   summary = summary + str(model) + ":"
        summary = summary[:-1]
        return summary
 
    def done(self, request, form_list):
        summary = self.get_summary(form_list)
        hidden_summary = self.get_hidden_summary(form_list)
        return render_to_response('confirm.html',
            {
            'summary': summary,
            'hidden_summary': hidden_summary,
            'form': ConfirmationForm(), # a regular Form
            },
            RequestContext(request))
 
    def get_template(self, step):
        return 'wizard.html'
 
    def process_step(self, request, form, step):
        self.extra_context = {'info': ''}
        if hasattr(form, "cleaned_data"):
            info, self.form_list = form.process_dynamic_step(self.form_list)
            self.extra_context = {'info': info}
 

Now two forms for the wizard (two steps):

 
class SearchWhateverForm(WizardStepForm):
    step_order = 1
 
    someChoice = forms.ChoiceField(choices=WHATEVER_CHOICES)
 
    @classmethod
    def get_field_name(self):
        return "whatever"
 
    def process_dynamic_step(self, form_list):
        form_list = form_list[:self.step_order]
        form_list.append(WhatToGenerateForm)
        return "How many items do you need to generate?", form_list
 
class WhatToGenerateForm(WizardStepForm):
    step_order = 2
    generate = forms.ChoiceField(choices=GENERATION_CHOICES)
 
    @classmethod
    def get_field_name(self):
        return "generate"
 
    def process_dynamic_step(self, form_list):
        form_list = form_list[:self.step_order]
        generate = self.cleaned_data['generate']
        if generate == GENERATE_EXACT or generate == GENERATE_EXACT_90:
           form_list.append(HowManyToGenerateForm)
           return "Please set number", form_list
        else:
           return self.append_end(form_list)
 

File urls.py would be like this:

 
  url(r'^wizard/$', MyWizard([SearchWhateverForm])
 

Only one template is needed for all the steps:

 
<form action="." method="post">
<table>
			{{ form }}
		</table>
<input type="hidden" name="{{ step_field }}" value="{{ step0 }}" />
		{{ previous_fields|safe }}
<input class="button" type="submit" value="{% trans "Next Step" %}" />
</form>
 

So, How could you test drive the wizard?

As you don't need views or templates to run the sequence, it is easy:

 
def test_StepsAreOk(self):
        form_list = []
        form_list.append(SearchWhateverForm)
        # define somedata
        form_list[-1].cleaned_data = {SearchWhateverForm.get_field_name(): somedata}
        info, form_list = form_list[-1]().process_dynamic_step(form_list)
        self.assertEqual(form_list[-1].get_field_name(), WhatToGenerateForm.get_field_name())
 

How can I populate the choices of one form dynamically?

The forms_list of the wizard is not populated with instances but data types so you've got to dynamically create a form type once you know which choices will it have available. One solution is to extend from one of your forms:

 
class SomeWizardStepForm(WizardStepForm):
    step_order = 1
 
    #field is not defined
 
    @classmethod
    def get_field_name(self):
        return "whatever"
 
    def process_dynamic_step(self, form_list):
        form_list = form_list[:self.step_order]
        form_list.append(TheNextForm)
        return "whatever", form_list
 
def createDynamicForm(self, someInput):
        class SomeDynamicForm(SomeWizardStepForm):
             field = forms.ModelChoiceField(queryset=someInput.get_whatever())
        return SomeDynamicForm  # returning a datatype not an instance.
 

Method createDynamicForm can be inserted in MyWizard class or in any WizardStepForm, in its process_dynamic_step method, so once the datatype is returned the form_list can hold the new form.

What if I need to populate the first step form with an incoming variable?

Initialize the FormWizard with an empty list:

 
url(r'^wizard/(?P<someInput>\d+)/$', MyWizard([]),
 

Add logic to MyWizard to populate and place the first form:

 
class MyWizard(FormWizard):
 
    someInput = None   # this is a model in my actual code
 
    def _initialize(self, id):
        self.someInput = SomeModel.objects.get(id=id)
        self.extra_context = {'someInput': self.someInput}
        self.form_list = []
        self.form_list.append(self.createDynamicForm(self.someInput))
 
    def parse_params(self, request, *args, **kwargs):
        """
        Get the parameters sent through the URL
        """
        if self.someInput is None:  # first time
           self._initialize(kwargs['someInput'])
 
    ....
 

It the code snippets are not clear enough let me know.

Celadon theme by the Themes Boutique
teeth bleaching
baldness treatment