Question

I have two different models that I would like to filter similarly by a common field name at different times, so i've written a single context function that handles both models by taking a string as an argument to use as the model name. Right now I'm using eval(), but something in my gut tells me that's a grave error. Is there a more pythonic way to do what I'm describing?

Here's a shortened version of what my code looks like at the moment:

def reference_context(model, value):
    menu = main_menu()
    info = company_info()
    pages = get_list_or_404(eval(model), category = value)

Secondly, is there a way to pass a keyword in a similar fashion, so I could have something along the lines of:

def reference_context(model, category, value):
    menu = main_menu()
    info = company_info()
    pages = get_list_or_404(eval(model), eval(category) = value)

And commentary on any other issue is welcome and greatly encouraged.

Était-ce utile?

La solution

If they are come from the same module (models.py), you can use getattr to retrieve the model class, and kwargs (a dict with double asterisk) this way:

from myapp import models

def reference_context(model, value):
    menu = main_menu()
    info = company_info()
    pages = get_list_or_404(getattr(models, model), **{category: value})

Autres conseils

You can use the get_model utility function, which takes the app name and model name.

from django.db.models import get_model
User = get_model("auth", "User") # returns django.contrib.auth.models.User

I don't really see why you need to pass the model as a string - just pass the model reference. E.g.

class ModelA(models.Model):
    ...

class ModelB(models.Model):
    ...

def reference_context(model, **kw):
    menu = main_menu()
    info = company_info()
    pages = get_list_or_404(model, **kw)
    # ...

In this setup you can pass any model and any query you want, e.g.

reference_context(ModelA, category="Hello")

or

reference_context(ModelB, item__ordered__lte=now)

As explained in my comment, if you really need to map strings to models, use an explicit registry/mapping. This prevents people from manipulating form data which might allow them to create a User in stead of, for example, a "Book":

model_map = dict(book=ModelA, magazine=ModelB)
reference_context(model_map[model_as_string], ...)
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top