Wednesday, May 30, 2012

Re: Django ModelForm user best practices

I tend to put as much functionality in my forms as possible. I've
asked a similar question before (many months ago) and I believe that
was the consensus. One advantage is you can re-use your forms (and its
save functionality) for your Create and Update views.

On Wed, May 30, 2012 at 3:45 PM, RM <rmirecki@gmail.com> wrote:
> 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.

--
You received this message because you are subscribed to the Google Groups "Django users" group.
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