Adrian Andreias

Jun 05, 2014

Django CreateUpdateView

Django is missing a generic class based view that handles both creating and updating a model object. As I was arguing in Ticket #22768 this is a common pattern that would save some code duplication and deserves a place in Django core. Until then here's an implementation:

class BaseCreateUpdateView(ModelFormMixin, ProcessFormView):
    """
    Base view for creating and updating an existing object.

    Using this base class requires subclassing to provide a response mixin.
    """

    object_url_kwargs = ['slug', 'pk']

    def get_object(self, queryset=None):
        if self.is_update_request():
            return super(BaseCreateUpdateView, self).get_object(queryset)
        else:
            return None

    def is_update_request(self):
        """
        Returns True if current request is an object update request, False if it's an object create request.

        Checks if the URL contains a parameter identifying an object.
        Possible URL parameter names are defined in self.object_url_kwargs
        """
        for object_kwarg in self.object_url_kwargs:
            if object_kwarg in self.kwargs:
                return True
        return False

    def get(self, request, *args, **kwargs):
        self.object = self.get_object()
        return super(BaseCreateUpdateView, self).get(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        self.object = self.get_object()
        return super(BaseCreateUpdateView, self).post(request, *args, **kwargs)

Feb 12, 2014

Sexy (bootstrap) forms with Django: comparing options

While working on a new software product I started using Bootstrap. It's a quick way for a programmer to add some looks to his web application. We might end up not using it in production, since designers will have an word on this (I had a chat with a friend that does front end and he says they're not using Bootstrap, since it's cluttered). However, it's still nice to have something else than Times New Roman in the browser while writing code. Django forms can only render as_p (HTML paragraphs), as_table and as_ul (unordered list). Hopefully we'll have a as_div in a future Django version, though if we look at the source code in BaseForm you'll notice that it wouldn't be hard at all to write an as_div method the same way the others are written:

    def as_table(self):
        "Returns this form rendered as HTML <tr>s -- excluding the <table></table>."
        return self._html_output(
            normal_row = '<tr%(html_class_attr)s><th>%(label)s</th><td>%(errors)s%(field)s%(help_text)s</td></tr>',
            error_row = '<tr><td colspan="2">%s</td></tr>',
            row_ender = '</td></tr>',
            help_text_html = '<br /><span class="helptext">%s</span>',
            errors_on_separate_row = False)

But it's best to first search for a better wheel, than to invent a new wheel every time you get some crazy idea about how things should work. So I started to look for options in the open source community.

It's important to note the difference between a software product (or shrinkwrap as Joel calls it) and a web application/site that is deployed just once and/or for a single customer (which is very close to what Joel calls "internal"). There are design decisions right from the start, for instance:

django-crispy-forms

https://github.com/maraujop/django-crispy-forms

Is probably designed for "internal" applications or to be used mostly by python programmers, because if you want your app to be easily customizable by a number of people (most of them not knowing anything about Python and some not even knowing how to program) you wouldn't want to define presentation in Python code like this:

Div('form_field_1', style="background: white;", title="Explication title", css_class="bigdivs")

or like this:

TabHolder(
    Tab('First Tab',
        'field_name_1',
        Div('field_name_2')
    ),
    Tab('Second Tab',
        Field('field_name_3', css_class="extra")
    )
)

Ionel argues that it's DRY. It's true, but I also think web designers will dry up when they need to modify layout by writing Python code  :). He also says that Python errors will be in your face, while writing Django template code will be harder to debug. This is a good point. Crispy forms also seems to have the largest community and is well documented.

Advanced form configuration are done thorough a self.helper = FormHelper() in YourForm class. I wish crispyforms would allow to do more from the Django template in order to touch the Python code as little as possible (or even at all).

django-floppyforms

https://github.com/brutasse/django-floppyforms

Similar to crispy-forms it renders HTML fields through Django templates, which obviously introduces a performance penalty, but that's something you could live with considering you're not rendering 100 forms on each HTTP request. Django templating cache would give a considerable performance boost, by the way. This project seems to have less traction that crispy-forms (if look at Github's Starts and Forks for instance). With floppyforms you derive YourForm class from floppyforms.forms, which is less than ideal. You will get HTML5 form fields out of the box with floppyforms.

formulation

https://github.com/funkybob/formulation

The #django IRC channel suggests this and it seems to be a nice and simple solution. 200 lines also means that you can easily maintain this case the project hangs, but you need to write and maintain your own bootstrap html code. It obviously has much less features out of the box when compared to crispy-forms.

django-bootstrap-form

https://github.com/tzangms/django-bootstrap-form

This is another small project that seems to do its job, just has a lot of unanswered issues and seems somehow hanging.

Conclusion

No conclusion yet; django-crispy-forms looks to be the mature project to choose, but I just don't agree with the design decision to describe presentation (in detail) from Python code and only from Python code.

Jan 22, 2013

I will not add trailing comma to lists in django json fixtures

I will not add trailing comma to lists in django json fixtures

I will not add trailing comma to lists in django json fixture

I will not add trailing comma to lists in django json fixtures

I will not add trailing comma to lists in django json fixtures

I will not add trailing comma to lists in django json fixture

I will not add trailing comma to lists in django json fixtures

I will not add trailing comma to lists in django json fixture

I will not add trailing comma to lists in django json fixtures

I will not add trailing comma to lists in django json fixtures

I will not add trailing comma to lists in django json fixture

I will not add trailing comma to lists in django json fixtures

I will not add trailing comma to lists in django json fixtures

I will not add trailing comma to lists in django json fixture

I will not add trailing comma to lists in django json fixtures

since I now know that I'll get a meaningful message:

Problem installing fixture '.....json': 
......
File "....\lib\site-packages\django\core\serializers\json.py", line 47, in Deserializer
  raise DeserializationError(e)
DeserializationError: No JSON object could be decoded

Jan 21, 2013

Django model managed=True on testing

I have a bunch of Django models that have managed=False set, but I need Django to create these database tables while running unit testing.

I eventually found an article that describes a method to do this: Simplifying the Testing of Unmanaged Database Models in Django

Place the code in myproject/testrunner.py and specify in your settings.py or test_settings.py file:

TEST_RUNNER = 'myproject.testrunner.ManagedModelTestRunner'

And that's all. Django will now create the tables for the unmanaged models when running automatic unit testing.