Valentin Golev
2010-11-05 14:29:43 UTC
Hello,
I'm still playing with brand new class-based views. I think I'm not
wrong about writing my experiences, questions and ideas so you
developers could polish the API more (if I'm being useless here,
sorry).
My first question is, that is "the right way" to handle creation of
objects with parameters which can't be set in the creation form?
Let's say we have a model:
class Item(models.Model):
owner = models.ForeignKey(User)
title = models.CharField(max_length=120)
and we have a form
class ItemForm(forms.ModelForm):
class Meta:
exclude = ('owner',) # because one can only add items which
belongs to him
so if we just write
class ItemCreateView(CreateView):
model = Item
the form won't be saved! And I have to do something like this:
class ItemCreateView(CreateView):
model = Item
def form_valid(self, form):
obj = form.save(commit=False)
obj.owner = self.request.user
obj.save()
self.object = obj
return HttpResponseRedirect(self.get_success_url())
I used to create an unsaved "instance" for that with function-based
view. I guess there should be used get_object() in CreateView, like in
the other SingleObjectMixin descendants, instead of just writing
"self.object = None" (or add a get_instance() function). (If I'm
right, maybe I could write a patch? But how do you handle the bleeding-
edge fast-changing features development? My experience with ticket/
patch system on code.djangoproject.com is dissappointing).
Another question, or I'd rather say remark, is what Mixins are awesome
and seem better than decorators. My views.py file looks like this now:
class AuthenticatedOnlyMixin(object):
def dispatch(self, request, *args, **kwargs):
assert request.user.is_authenticated(), "You must be
authenticated!" # todo: a better handling, maybe redirect
return super(AuthenticatedOnlyMixin, self).dispatch(request,
*args, **kwargs)
class ItemMixin(object):
model = Item
form_class = ItemForm
class UserItemMixin(ItemMixin, AuthenticatedOnlyMixin):
def get_queryset(self):
return super(UserItemMixin,
self).get_queryset().filter(owner=self.request.user)
class ItemView(ItemMixin, DetailView):
pass
class ItemCreateView(ItemMixin, AuthenticatedOnlyMixin, CreateView):
def form_valid(self, form):
obj = form.save(commit=False)
obj.owner = self.request.user
obj.save()
self.object = obj
return HttpResponseRedirect(self.get_success_url())
class ItemListView(ItemMixin, ListView):
context_object_name = 'item_list'
IndexView = ItemListView
class ItemEditView(UserItemMixin, UpdateView):
pass
class ItemDeleteView(UserItemMixin, DeleteView):
success_url = '/'
and I like this "style" more than dancing with old-school decorators
in one way or another. We've already had this conversation, but I
can't still can't see neither why this style is bad nor how should I
write it instead? (By "bad" and "should write" I mean "not supported
and not encouraged by Django" and "supported and encouraged by
Django").
I hope my thoughts can help you (and every django-lover) a little bit.
- Valya
I'm still playing with brand new class-based views. I think I'm not
wrong about writing my experiences, questions and ideas so you
developers could polish the API more (if I'm being useless here,
sorry).
My first question is, that is "the right way" to handle creation of
objects with parameters which can't be set in the creation form?
Let's say we have a model:
class Item(models.Model):
owner = models.ForeignKey(User)
title = models.CharField(max_length=120)
and we have a form
class ItemForm(forms.ModelForm):
class Meta:
exclude = ('owner',) # because one can only add items which
belongs to him
so if we just write
class ItemCreateView(CreateView):
model = Item
the form won't be saved! And I have to do something like this:
class ItemCreateView(CreateView):
model = Item
def form_valid(self, form):
obj = form.save(commit=False)
obj.owner = self.request.user
obj.save()
self.object = obj
return HttpResponseRedirect(self.get_success_url())
I used to create an unsaved "instance" for that with function-based
view. I guess there should be used get_object() in CreateView, like in
the other SingleObjectMixin descendants, instead of just writing
"self.object = None" (or add a get_instance() function). (If I'm
right, maybe I could write a patch? But how do you handle the bleeding-
edge fast-changing features development? My experience with ticket/
patch system on code.djangoproject.com is dissappointing).
Another question, or I'd rather say remark, is what Mixins are awesome
and seem better than decorators. My views.py file looks like this now:
class AuthenticatedOnlyMixin(object):
def dispatch(self, request, *args, **kwargs):
assert request.user.is_authenticated(), "You must be
authenticated!" # todo: a better handling, maybe redirect
return super(AuthenticatedOnlyMixin, self).dispatch(request,
*args, **kwargs)
class ItemMixin(object):
model = Item
form_class = ItemForm
class UserItemMixin(ItemMixin, AuthenticatedOnlyMixin):
def get_queryset(self):
return super(UserItemMixin,
self).get_queryset().filter(owner=self.request.user)
class ItemView(ItemMixin, DetailView):
pass
class ItemCreateView(ItemMixin, AuthenticatedOnlyMixin, CreateView):
def form_valid(self, form):
obj = form.save(commit=False)
obj.owner = self.request.user
obj.save()
self.object = obj
return HttpResponseRedirect(self.get_success_url())
class ItemListView(ItemMixin, ListView):
context_object_name = 'item_list'
IndexView = ItemListView
class ItemEditView(UserItemMixin, UpdateView):
pass
class ItemDeleteView(UserItemMixin, DeleteView):
success_url = '/'
and I like this "style" more than dancing with old-school decorators
in one way or another. We've already had this conversation, but I
can't still can't see neither why this style is bad nor how should I
write it instead? (By "bad" and "should write" I mean "not supported
and not encouraged by Django" and "supported and encouraged by
Django").
I hope my thoughts can help you (and every django-lover) a little bit.
- Valya
--
You received this message because you are subscribed to the Google Groups "Django developers" group.
To post to this group, send email to django-developers-/JYPxA39Uh5TLH3MbocFF+G/***@public.gmane.org
To unsubscribe from this group, send email to django-developers+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/***@public.gmane.org
For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.
You received this message because you are subscribed to the Google Groups "Django developers" group.
To post to this group, send email to django-developers-/JYPxA39Uh5TLH3MbocFF+G/***@public.gmane.org
To unsubscribe from this group, send email to django-developers+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/***@public.gmane.org
For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.