On Apr 27, 9:17 am, Ejah <ej.huijb...@gmail.com> wrote: > You might want to take a look at godjango.com for some nice short > intro videos on generic class based views, and the source code.
As it happens, the godjango videos didn't cover the templates, but they did provide some clues - enough to get me going. So I'm posting the kind of thing I ended up with here, in case it'll help someone else struggling with the class-based generic views. models.py: This is a scheduling app, so people are assigned to scheduled items. This model is used as the "through" model for that relation. You can ignore the content of the model - it's not relevant to the use of generic views, with the exception that I made sure to define verbose_name and verbose_name_plural in everything. That's because I'm using the same template to render things like lists of objects of different models, and I want to have predictable names coming out. class ItemPerson(models.Model): item = models.ForeignKey(Item) person = models.ForeignKey(Person) role = models.ForeignKey(PersonRole, default=PersonRole.objects.find_default) status = models.ForeignKey(PersonStatus, default=PersonStatus.objects.find_default) visible = models.CharField(max_length=4, choices=YesNo, default='Yes') distEmail = models.CharField(max_length=4, choices=YesNo, default='No') recordingOkay = models.CharField(max_length=4, choices=YesNo, default='No') class Meta: verbose_name = 'itemperson' verbose_name_plural = 'itemspeople' def __unicode__(self): return u"%s: %s [%s]" % (self.item, self.person, self.role) def get_absolute_url(self): return mk_url(self) forms.py: I have a form for editing ItemPerson objects. This is used both when creating and when editing the objects. The fromPerson field is some plumbing I no longer need. class ItemPersonForm(ModelForm): fromPerson = forms.BooleanField(required=False, widget=forms.HiddenInput) class Meta: model = ItemPerson urls.py: I have URLs to: - list all the ItemPerson objects - display the details of a given ItemPerson - delete an ItemPerson - edit an existing ItemPerson - create a new ItemPerson These all use subclassed generic views. url(r'^progdb/itemspeople/$', VisibleView.as_view(model=ItemPerson)), url(r'^progdb/itemperson/(?P<pk>\d+)/$', show_itemperson_detail.as_view()), url(r'^progdb/delete_itemperson/(?P<pk>\d+)/$', permission_required('progdb2.delete_itemperson') (AfterDeleteView.as_view( model=ItemPerson))), url(r'^progdb/edit_itemperson/(?P<pk>\d+)/$', permission_required('progdb2.change_itemperson')(EditView.as_view( model = ItemPerson, form_class=ItemPersonForm))), url(r'^progdb/new_itemperson/$', permission_required('progdb2.add_itemperson')(NewView.as_view( template_name = 'progdb2/edit_itemperson.html', model = ItemPerson, form_class=ItemPersonForm))), ListView ======= I have two levels of subclass of ListView. The first level, AllView, is because I'm using the same template to render lists of lots of different models (not just this one), so I'm setting up both the common template name and populating the context with names and labels relating to the model. class AllView(ListView): template_name = 'progdb2/object_list.html' def get_context_data(self, **kwargs): context = super(AllView, self).get_context_data(**kwargs) context['request'] = self.request context['verbose_name'] = self.model._meta.verbose_name context['verbose_name_plural'] = self.model._meta.verbose_name_plural context['new_url'] = r'/progdb/new_%s/' % ( self.model.__name__.lower() ) return context The second level, VisibleView, is because I'm filtering the queryset based on whether the user is logged in (I don't do this for all models, hence two levels). class VisibleView(AllView): def get_queryset(self): if self.request.user.is_authenticated(): return self.model.objects.all() else: return self.model.objects.filter(visible = True) object_list.html: I'm rendering the list with a common template that iterates over the list, and has a link for creating a new object in the model. linky is a filter that gives me a link to a particular object. {% extends "progdb2/base.html" %} {% load progdb_filters %} {% block title %}{{ verbose_name_plural }} {% endblock %} {% block body_content %} <table border> {% for o in object_list %} <tr><td> {{ o|linky|safe }} </td></tr> {% empty %} <tr><td>None yet</td></tr> {% endfor %} </table> {% if user.is_authenticated %} <p><a href="{{ new_url }}">Add new {{ verbose_name }}</a>.</p> {% endif %} {% endblock %} DetailView ======== I'm subclassing DetailView, in order to set a few attributes, and for some of the models, I'm doing more. For ItemPerson, I could just be setting all of these via keyword arguments to DetailView in urls.py. class show_itemperson_detail(DetailView): context_object_name = 'itemperson' model = ItemPerson template_name = 'progdb2/show_itemperson.html' show_itemperson.html: The template for the detail view shows the information for the ItemPerson, and also gives a link to editing the object. {% extends "progdb2/base.html" %} {% load progdb_filters %} {% block title %}{{ itemperson }} {% endblock %} <p> {% block body_content %} <table border="1"> <tr> <td>{{ object.person|linky|safe }}</td> <td>{{ object.item|linky|safe }}</td> <td>{{ object.role }}</td> <td>{{ object.status }}</td> </tr> </table> </p> <p><a href="/progdb/edit_itemperson/{{ itemperson.id }}/">Edit itemperson</a>.</p> {% endblock %} UpdateView ========== UpdateView is subclassed because I'm using the same template everywhere. This could just be a parameter to UpdateView in urls.py. Other things like the model and the form class to use are passed as parameters because they're different for each of my models. class EditView(UpdateView): template_name = 'progdb2/editform.html' editform.html: {% extends "progdb2/base.html" %} {% load progdb_filters % {% block title %}{{ form_title }} {% endblock %} {% block body_content %} {% if form_intro %} <p>{{ form_intro }}</p> {% endif %} <form action="" method="post"> {% csrf_token %} <table border> {{ form.as_table }} <tr><td colspan="2"><input type="submit" value="submit" /></td></tr> </table> </form> {% endblock %} DeleteView ========= When I delete an ItemPerson, it'll most likely be because I was following a deletion link from an Item or from a Person, so I want to return back to that object after deletion. I use a form with two submissions, and pass along the URLs for the items and the person in question (because the object will be gone by the time I want them). class AfterDeleteView(DeleteView): def get_success_url(self): if self.request.POST.has_key('after'): return self.request.POST.get('after') else: return '/progdb/main/' itemperson_confirm_delete.html: {% extends "progdb2/base.html" %} {% load progdb_filters %} {% block title %}{{ form_title }} {% endblock %} <p> {% block body_content %} <table border="1"> <tr> <td>{{ object.person }}</td> <td>{{ object.item }}</td> <td>{{ object.role }}</td> <td>{{ object.status }}</td> </tr> </table> </p> <form action="" method="post"> {% csrf_token %} <input type="hidden" name="after" value="{{ object.item.get_absolute_url }}" /> <input type="submit" value="Remove and return to {{ object.item }}" name="DeleteAndShowItem" /> </form> <form action="" method="post"> {% csrf_token %} <input type="hidden" name="after" value="{{ object.person.get_absolute_url }}" /> <input type="submit" value="Remove and return to {{ object.person }}" name="DeleteAndShowPerson" /> </form> {% endblock %} CreateView ========= Creating a new ItemPerson is similar, but more messy. I'll probably be following a link from an Item (in which case I'd like to return to the Item, and I don't know what Person will be added), or I'll be following a link from a Person (and want to return to it), and won't know what Item will be added. (this, btw, is where fromPerson came from in ItemPersonForm; I should get rid of that now). My solution was to have two submission buttons (again), but specify the names of the model I want to return to, rather than the URL of the object. Then I can determine the success URL from one side of the relation or the other, after the new ItemPerson is created. (If there are better ways of doing this, I'd like to know. :-> ) class NewView(CreateView): template_name = 'progdb2/editform.html' def get_initial(self): models = { 'item': Item, 'person': Person } initial = super(NewView, self).get_initial() for k in self.request.GET: if k in models: id = int(self.request.GET[k]) m = models[k] initial[k] = m.objects.get(id = id) return initial def get_success_url(self): df = super(NewView, self).get_success_url() subs = [ ('submit0', 'after0'), ('submit1', 'after1') ] for (s, a) in subs: if self.request.POST.has_key(s) and self.request.POST.has_key(a): attr = self.request.POST.get(a, 'self') return getattr(self.object, attr).get_absolute_url() return df edit_itemperson.html: {% extends "progdb2/base.html" %} {% load progdb_filters % {% block title %}{{ form_title }} {% endblock %} {% block body_content %} {% if form_intro %} <p>{{ form_intro }}</p> {% endif %} <form action="" method="post"> {% csrf_token %} <table border> {{ form.as_table }} <tr><td colspan="2"> <input type="submit" name="submit0" value="Save and show person" /> <input type="hidden" name="after0" value="person" /> </td></tr> <tr><td colspan="2"> <input type="submit" name="submit1" value="Save and show item" /> <input type="hidden" name="after1" value="item" /> </td></tr> </table> </form> {% endblock %} steve -- 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+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/django-users?hl=en.