Wednesday, May 30, 2012

Django ModelForm user best practices

Say there's a model:

class Notification(models.Model):
    user = models.ForeignKey(User)    
    board = models.ForeignKey(Board)
    post = models.ForeignKey(Post)    
    name = models.CharField()
    
    class Meta:
        unique_together = ('user', 'name', 'post', 'board')
        #i know this is funny.. just for purpose of this post

In every post there's a form that you can fill with "name" value.
This way the logged in user gets notification on every post update.

What is the best way to save the "user", "board", "post" data ?

1. Saving in the views directly (CBV):

class NotificationModelForm(forms.ModelForm):
    class Meta:
        model = Notification
        fields = ["name"]

class CreateNotificationView(CreateView):
    model = Notification
    form_class = NotificationForm
    def form_valid(self, form):
        data = form.save(commit=False)
        data.user = self.request.user
        data.board = ...
        data.post = ...
        data.save()

* if you have model validators (unique_together for user... this won't no longer work when submitting the form)

2. Displaying all the fields in the form, with some fields hidden

class NotificationModelForm(forms.ModelForm):
    class Meta:
        fields = ["user", "board", "post", "name"]

    def __init__(self, *args, **kwargs):
        super(NotificationModelForm, self).__init__(*args, **kwargs)
        for field in ["user", "board", "post"]:
            forms.field['field'].widget = forms.HiddenInput()
            #I know this can be done other ways too

Now we need to prepopulate fields with initial data for these fields

class CreateNotificationView(CreateView):
    model = Notification
    form_class = NotificationModelForm

    def get_initial(self):
        initial = super(CreateNotificationView, self).get_initial()
        initial['user'] = self.request.user
        initial['board'] = ...
        initial['post'] = ....
        return initial
  
If the same field pattern (user, board, post) is used in more forms/views... I can also create a MixinView

class CommonUserFormMixin(object):
    
    def get_form(self, form_class):
        form = super(CommonUserFormMixin, self).get_form(form_class)
        for field in ['user', 'board', 'post']:
            form.fields[field].widget = forms.HiddenInput()

Then:

class NotifcationModelForm(forms.ModelForm):
    class Meta:
        model = Notification
        fields = ["user", "board", "post", "name"]

class CreateNotificationView(CommonUserFormMixin, CreateView):
    form_class = NotificationModelForm
    model = Notification

* in 2 above scenarios we get model validators working.
3. Sending values to the form directly and overriding the form.save() method

class CreateNotificationView(CreateView):
    model = Notification
    form_class = NotificationModelForm

    def get_form_kwargs(**kwargs):
        kwargs = super(CreateNotificationView, self).get_form_kwargs(**kwargs)
        kwargs['user'] = self.request.user
        kwargs['board'] = ...
        kwargs['post'] = ...
        return kwargs

class NotificationModelForm(forms.ModelForm):
    class Meta:
        model = Notification
        fields = ["name"]

    def __init__(self, *args, **kwargs):
        self.user = kwargs.pop('user')
        self.post = kwargs.pop('post')
        self.board = kwargs.pop('board')

        super(NotificationModelForm, self).__init__(*args, **kwargs)
        
    def save(*args, **kwargs):
        n = super(NotificationModelForm, self).save(commit=False)
        n.user = self.user
        n.post = self.post
        n.board = self.board
        n.save()
        return n


I'm sure there are more ways to achive the same result.
What are your thoughts on that ?

When should I 'hide' (by using HiddenInput() widget) ModelForm fields? when should I save them directly
in view? 

Does it all depend on needs or maybe there are some "best" standards ?
    

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To view this discussion on the web visit https://groups.google.com/d/msg/django-users/-/xn6xNGKJ2CEJ.
To post to this group, send email to django-users@googlegroups.com.
To unsubscribe from this group, send email to django-users+unsubscribe@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/django-users?hl=en.

No comments:

Post a Comment