Hello,

I really like the generic view feature of Django. It's been a handy
way to save a lot of work. Lately though, I've been finding myself
often wanting to display a list of objects filtered by some field. The
documentation suggests handling this by writing a small view that
filters the objects and then calling the generic view from within
that. This works fine of course, but it seems that in a lot of cases
one can end up writing a large number of small views that all simply
display a filtered list of objects. I figured it might be helpful to
abstract this behavior into a couple of additional generic
views. These will automatically filter based on a keyword captured in
the URL and a field specified in the urls.py file. I've called these
new views object_list_field and object_list_foreign_field. They are
included below:

def object_list_field(request, model, field, value, paginate_by=None,
page=None,
                      fv_dict=None, allow_empty=True,
template_name=None,
                      template_loader=loader, extra_context=None,
context_processors=None,
                      template_object_name='object', mimetype=None):
    """Extends generic view object_list to display a list of objects
filtered
    by an arbitrary field.
    Works only for fields that are not ForeignKey or ManyToMany.
    See object_list_foreign_field for ForeignKey fields"""

    if not fv_dict:
        fv_dict = {}
    fv_dict[field] = value
    obj_list = model.objects.filter(**fv_dict)

    # calculate the number of the first object on this page
    # in case the objects are paginated and want to be displayed as
    # a numbered list
    extra_context = {'start': calc_start(page, paginate_by,
obj_list.count())}

    return list_detail.object_list(request=request,
queryset=obj_list,
                                   paginate_by=paginate_by,
page=page,
                                   allow_empty=allow_empty,
template_name=template_name,
                                   template_loader=template_loader,
extra_context=extra_context,
 
context_processors=context_processors,
 
template_object_name=template_object_name,
                                   mimetype=mimetype)

def object_list_foreign_field(request, model, field, value,
foreign_model,
                              foreign_field, fv_dict=None,
                              paginate_by=None, page=None,
allow_empty=True,
                              template_name=None,
template_loader=loader,
                              extra_context=None,
context_processors=None,
                              template_object_name='object',
mimetype=None):
    """Generic view to display a list of objects filtered by an
arbitary foreign key field"""

    if not fv_dict:
        fv_dict = {}
    foreign_obj = get_object_or_404(foreign_model, **{foreign_field:
value})
    fv_dict[field] = foreign_obj.id
    obj_list = model.objects.filter(**fv_dict)

    # calculate the number of the first object on this page
    # in case the objects are paginated and want to be displayed as
    # a numbered list
    extra_context = {'start': calc_start(page, paginate_by,
obj_list.count())}

    return list_detail.object_list(request=request,
queryset=obj_list,
                                   extra_context={foreign_field:
foreign_obj},
                                   paginate_by=paginate_by,
page=page,
                                   allow_empty=allow_empty,
template_name=template_name,
                                   template_loader=template_loader,
 
context_processors=context_processors,
 
template_object_name=template_object_name,
                                   mimetype=mimetype)

Both views expect to capture a variable called "value" from the
URL. They also both accept all arguments that object_list
accepts. These can be specified within urls.py and are passed on to
object_list when it is called by object_list_field or
object_list_foreign_field.

To use the canonical book website as an example, suppose we wanted to
use these views to make a couple of different lists. For instance, we
might want to have an alpabetical listing of authors, with one page
for each letter that their last name could begin with. With
object_list_field, we wouldn't have to write a new view for this, just
add the following to urlpatterns

urlpatterns = patterns('',
                        ...other url patterns...,
                        (r'^authors/(?P<value>[A-Z]+)/$', object_list_field', 
{'model':
Author,
                                                                               
'field': 'lastname__startswith'}),
                        ...other url patterns...,
                      )

Of course, this assumes that the template_name and
template_object_name are set to the defaults expected by
list_detail.object_list. If not, these values can also be added to the
dictionary above. As another example, suppose we wanted a view that
showed all books by a particular publisher. Assuming publisher has its
own django model, we would use object_list_foreign_field to create a
view for this.


urlpatterns = patterns('',
                        ...other url patterns...,
                        (r'^authors/(?P<value>[A-Z])/$', object_list_field', 
{'model':
Author,
                                                                               
'field': 'lastname__startswith'}),
                        (r'^books/by_publisher/(?P<value>[A-Za-z]+)/$',
object_list_foreign_field', {'model': Book,
                                                                                
                     'field': 'publisher',
                                                                                
                     'foreign_model': Publisher,
                                                                                
                     'foreign_field': 'name',
                                                                                
                     'fv_dict': {'in_print': True}}),
                        ...other url patterns...,
                      )

In this example, note that additional fields can be specified in
fv_dict inside the urls.py file. In this case it is used to further
filter the list of books to only include ones that are in print.

So, that's it. I would really appreciate any feedback as to whether
this is a good way to go about abstracting a lot of common views into
a single generic view. I'd also like to know if people think this is
something worth contributing to the django project.  Please let me
know if anything needs further explanation. Thanks for your time and
input.

--~--~---------~--~----~------------~-------~--~----~
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@googlegroups.com
To unsubscribe from this group, send email to 
django-developers+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/django-developers?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to