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.

Reply via email to