views:

2254

answers:

8

Is there a good way in Django to convert an entire model to a dictionary? I mean, like this:

class DictModel(models.Model):
    key = models.CharField(20)
    value = models.CharField(200)


DictModel.objects.all().to_dict()

... with the result being a dictionary with the key/value pairs made up of records in the Model? Has anyone else seen this as being useful for them?

Thanks.

Update
I just wanted to add is that my ultimate goal is to be able to do a simple variable lookup inside a Template. Something like:

{{ DictModel.exampleKey }}

With a result of DictModel.objects.get(key__exact=exampleKey).value

Overall, though, you guys have really surprised me with how helpful allof your responses are, and how different the ways to approach it can be. Thanks a lot.

+5  A: 

You are looking for the Values member of QuerySet which allows you to get a list of dictionaries from your query

Returns a ValuesQuerySet -- a QuerySet that evaluates to a list of dictionaries instead of model-instance objects. Each of those dictionaries represents an object, with the keys corresponding to the attribute names of model objects.

>>> Blog.objects.values()
[{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}],
>>> Blog.objects.values('id', 'name')
[{'id': 1, 'name': 'Beatles Blog'}]
Tom Leys
I don't think he wants a list of dict, he wants a single dict where key is model key
Anurag Uniyal
+4  A: 

use

dict(((m.key, m.value) for m in DictModel.objects.all())

As suggested by Tom Leys, we do not need to get whole object, we can get only those values we need e.g.

dict(((m['key'], m['value']) for m in DictModel.objects.values('key', 'value')))

and if you need all values, it is better to keep whole object in dict e.g.

dict(((m.key, m) for m in DictModel.objects.all())
Anurag Uniyal
We should combine solutions - dict(((m['key'], m['value']) for m in DictModel.objects.all().values()) - this way the hidden id field isn't returned from the DB.
Tom Leys
ok I will update my solution, you may do yours :)
Anurag Uniyal
+2  A: 

Does this need to create an actual dict? could you get by with only something that looked like a dict?

class DictModelAdaptor():
    def __init__(self, model):
        self.model = model

    def __getitem__(self, key):
        return self.model.objects.get(key=key)

    def __setitem__(self, key, item):
        pair = self.model()
        pair.key = key
        pair.value = item
        pair.save()

    def __contains__(self, key):
        ...

You could then wrap a model in this way:

modelDict = DictModelAdaptor(DictModel)
modelDict["name"] = "Bob Jones"

etc...

TokenMacGuy
If this works in Template variable lookups, this may actually be what I want. Have you tried this? It'll be a few hours before I can.
LarrikJ
Yes, I have used container adapters in many situations, although I have certainly not wanted to use a whole model in this way. Also please note that this example is somewhat abbreviated. You will want to add some additional handlers and proper error handling.
TokenMacGuy
I picked this answer because it fits my specific situation the best (which is slightly more complicated a situation than I described). The other responses were great, and worked fine as well.My favorite part was that lookups are done one at a time, instead of loading the whole table at once. I didn't even realize I wanted that until I saw it.
LarrikJ
+2  A: 

You can use the python serializer:

from django.core import serializers
data = serializers.serialize('python', DictModel.objects.all())
Luper Rouch
I haven't tried Django's serializers yet, so I'm having trouble figuring out how this would work. I think I'll need to try this idea in an interactive session. It seems like it could be a solution, though. Thanks.
LarrikJ
+7  A: 

You want the in_bulk queryset method which, according to the docs:

Takes a list of primary-key values and returns a dictionary mapping each primary-key value to an instance of the object with the given ID.

It takes a list of IDs, so you'll need to get that first via the values_list method:

ids = MyModel.objects.values_list('id', flat=True)
model_dict = MyModel.objects.in_bulk(ids)
Daniel Roseman
While this doesn't help me in this instance, that's pretty neat and I didn't know that. Thanks
LarrikJ
Django allows you to have primary keys that are not integers. If your model is set up properly in this way, this might still be a good solution.
TokenMacGuy
+23  A: 

You can also rely on django code already written ;).

from django.forms.models import model_to_dict
model_to_dict(intance, fields=[], exclude=[])

Regards Arthur

Arthur Debert
It is very nice solution but I've noticed that there is a catch. Since this method was written for usage in forms it doesn't dump fields that have editable=False flag.
Łukasz Korzybski
A: 

Or were you trying to do something like:

def someview(req):
    models = MyModel.objects.all()
    toTuple = lambda field: (getattr(field, 'someatt'), getattr(field, 'someotheratt'))  
    data = dict(map(toTuple,models))
    return render_to_response(template, data)
Shea Kauffman
+1  A: 

dict((x.name, getattr(o, x.name)) for x in o._meta.fields)

One of differences between this and Luper's solution with serialize('python', ...) is that here foreign key fields will be represented as actual related objects. Using serialize you will get only id value of related object, not the object itself.
Łukasz Korzybski