Hey All,

Something I've regularly run into as a challenge is the implementation of 
Django forms work well in the simple use cases, but as the use case grows 
in complexity, Django forms become more difficult to work with.

I know that's a super general statement, but here's the simplest complex 
example I can give you. Lets say you're making an application for a home 
builder, so that their Project Managers can better coordinate the builds. 
One of the features is the ability to take notes and pictures on anything 
that's not yet done and specifically if it relates to a specific piece of 
equipment (AC, furnace, water pump, etc), they can add that too. Below is a 
moderately simplistic example:

class Note(models.Model):
    project = models.ForeignKey('project_management.Project', 
related_name="notes")
    equipment = models.ForeignKey('equipment.Equipment', null=True, 
blank=True, related_name="notes")
    picture = models.FileField(null=True, blank=True)
    is_blocker = models.BooleanField(default=True)
    comment = models.TextField()
    created_by = models.ForeignKey('users.User', verbose_name="Created By")
    created_date = models.DateTimeField(default=timezone.now, 
verbose_name="Created Date")


class NoteModalForm(forms.ModelForm):
    class Meta:
        fields = ('comment', 'is_blocker','equipment', 'picture')
        model = Note
        labels = {
            'comment': 'Note',
            'is_blocker': 'Blocking Issue',
            'picture': 'Picture',
        }
        widgets = {
            'picture': DragNDropFileButtonInput(button_text='Select file to 
Upload',
                                                    button_classes='btn 
btn-bordered uploader'),
        }



General comments first: 

   1. I would say there's no better way to accomplish what is currently on 
   that form given the current Form Meta API. (Willing to be challenged on 
   this point, btw.)
   2. The repetition of picture 3 times over (fields tuple, labels dict, 
   widgets, dict) seems to be inherently not DRY. If this gets very long, then 
   it becomes harder to manage.
   3. The API on the Model Form itself behaves not quite like you'd expect 
   initially. You'd expect redeclaring fields directly on a form for it to 
   function like a dictionary update, if the value doesn't exist in the 
   incoming dictionary, it keeps what's there. It actually behaves like 
   re-declaration. This very significant behavior is buried in a note 
   
(https://docs.djangoproject.com/en/2.0/topics/forms/modelforms/#overriding-the-default-fields).
 
   Additionally, you'll have sources like pydanny basically tell you this is 
   an anti-pattern: https://www.pydanny.com/overloading-form-fields.html
   4. The API on Meta leads you to believe initially that you can override 
   lots of things via Meta, and it's difficult to discover what is or is not 
   supported. (I usually dig into django.forms.models, and then wander around 
   until I get to ModelForm.) 
      - Here's the list: *model, fields, exclude, widgets, 
      localized_fields, labels, help_texts, error_messages, field_classes.* 
      - What's missing that's on a *default* field? *Required, 
      initial, show_hidden_initial, validators, disabled, label_suffix. *
      - Anything not on this list you basically need to override in __init__
   5. The Django Form API both does and does not care about the client side 
   implementation. I say it does care because it sets the default values in 
   the DOM if you use the form as recommended in the docs. However, there is 
   no recommended approach for anything beyond this. 

Here are some simple scenarios that are made difficult:

Scenario #1
If I'd like on this form--and this form only--to make *picture* always 
required or change the default value of *is_blocker, *we have to override 
__init__. And generally it looks like this:

    def __init__(self, *args, **kwargs):
        super(NoteModalForm, self).__init__(*args, **kwargs)
        self.fields['picture'].required = True
        self.fields['is_blocker'].initial = False


Scenario #2
If I have the feature request that notes that are blockers require pictures 
or notes that have equipment requires pictures, then you have to implement 
this pattern:

https://docs.djangoproject.com/en/2.0/ref/forms/validation/#cleaning-and-validating-fields-that-depend-on-each-other

Oh, but wait! The best in class approach to this problem would be to inform 
the user before they submit the form that this is a problem. This catches 
it only on the server side. How should we implement that? You're on your 
own to figure it out.


So in summary, I feel like this could be improved. And I'd like to take an 
whack at it!



Robert Roskam

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers  (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-developers/8fc29cb6-d059-4e49-bb76-309d0404ecd5%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to