views:

100

answers:

1

Reader's Digest version: How do I get data (either single row if specified or full table) from a model by taking a URL argument of the model's name without hardcoding the URLconfs to match each model? For more details, read on:

I'm making an app that has three models, and I want to make a simple view that takes a name of a model, and spit out the model's default manager's Model.manager.all(), and if there's a slug, a single object matching that slug. I don't know how to do this, so I'm running into problems with having to make views/URLconfs for EACH model individually.

Here's what the URLconfs are looking like:

(r'^model1/$', 'model1_index_view', 'model1_index'),
(r'^model1/(?P<slug>[-\w]+)/$', 'model1_detail_view', 'model1_detail'),
(r'^model2/$', 'model2_index_view', 'model2_index'),

It goes on a little bit longer, but I think you get the picture. I'm ending up hardcoding a relatively large amount of URLconfs to do something that I'm thinking I can do with perhaps one View that takes a Model name as an argument and optionally a slug. My concern is, what happens if someone specifies a Model name of say... User? Is there a snippet of code to get a list of models from an app and make sure it matches one of 'em and not a model from contrib.auth or another app?

+6  A: 

Use get_model:

from django.db.models import get_model

def my_view(request, model_name, item_slug):
    try:
        model = get_model('app_name', model_name)
    except:
        ## throw an error
        pass
    objects = model.objects.get(slug=item_slug)

Then in urls:

 (r'^(?P<model_name>[-\w]+/(?P<slug>[-\w]+)/$', 'model_detail_view', 'model_detail'),
f4nt
Thanks so much, really appreciate it!
Zack
You'll probably want to wrap the "model.objects.get" with a "try...except model.DoesNotExist: raise Http404" to avoid 500 errors. And you may want to validate that model_name is one of a limited list (you could do this with "(model1|model2|model3)" right in the URLconf), to avoid the potential issues you mentioned of somebody naming a model you didn't intend on having accessible.
Carl Meyer
That's a good idea, I'm not sure if I'd need to add the regexp to the URLconf in this case, since everything inside the app is open for browsing. I'll keep that in mind, though, it will certainly come in handy in the future (I'm terrible with regexps); the main thing I was looking to avoid was this app somehow "leaking" into other app's models, like auth. Thanks again for the comment!
Zack
One other question, though. I've got certain "live" rows in each of these models, and I want only those rows to be retrieved when someone accesses the model. I've already written a manager for the two models that have that issue, Model.live_objects; is there a way to detect the first manager defined in a model (in the two models that have the other manager, it's defined and then objects is redefined after, I believe that how you make it "default," not 100% sure, though.) and use that instead of Model.objects?
Zack
You're probably going to have to use ifs to get that. something like: if hasattr(model, "live_objects"): ## do somethingSorry if formatting gets hosed.
f4nt
Just checked around on Google a bit, apparently there's a variable I can use to get the default manager (the one that's defined first in the model, which mine is (objects is redefined after this new manager is defined)). It's, not surprisingly, called Model._default_manager. So I'd just say model._default_manager.all(). Also: I noticed there's not a closing ) on the first regexp group, is that to make the 2nd group "optional?" I was looking for one view that will expect there to not be a slug defined and return all(), and if there is to use get()
Zack