简体   繁体   中英

Django, JSON serialize queryset and list of models has different behavior

I have a Django model with a function (on the Python class) that modifies some of its fields.

class TimeStampedModel(models.Model):
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)


class MyModel(TimeStampedModel):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    a_number = models.FloatField()
    some_text = models.CharField(max_length=64)

    def MyFunction(self):
        self.a_number = 123.123

I can do this, and it works

from django.core.serializers.json import DjangoJSONEncoder
json.dumps(list(MyModel.objects.filter(...).values()), cls=DjangoJSONEncoder)

Now I'd like to call the function MyModel.MyFunction on all the models before JSON encoding them. I've tried this, but obviously it returns the fields as they are in the database, not modified by MyFunction:

from django.core.serializers.json import DjangoJSONEncoder

mymodels = MyModel.objects.filter(...)

for mymodel in mymodels:
    mymodel.MyFunction()
    # or mymodel.myfield = somethingelse

json.dumps(list(mymodels.values()), cls=DjangoJSONEncoder)

So I've tried this

from django.core.serializers.json import DjangoJSONEncoder

mymodels = MyModel.objects.filter(...)

_mymodels = []

for mymodel in mymodels:
    mymodel.MyFunction()
    # or mymodel.myfield = somethingelse
    _mymodels.append(mymodel)

json.dumps(_mymodels, cls=DjangoJSONEncoder)

but TypeError: Object of type MyModel is not JSON serializable .

I've read on other answers that you'd have to either install django rest framework or implement a to_json function on MyModel .

However, I'd like not to clutter my application to achieve a behavior that is already available. How can I tell django to behave the same way on an array of models that it behaves on a queryset of the same model?

django.forms.models.model_to_dict did the trick

from django.core.serializers.json import DjangoJSONEncoder
from django.forms.models import model_to_dict

mymodels = MyModel.objects.filter(...)

_mymodels = []

for mymodel in mymodels:
    mymodel.MyFunction()
    # or mymodel.myfield = somethingelse
    _mymodels.append(model_to_dict(mymodel))

json.dumps(_mymodels, cls=DjangoJSONEncoder)

Another alternative is to try using json.dumps(MyModel.objects.filter(...).values(), cls=DjangoJSONEncoder) , as this will mostly do the same thing as model_to_dict , but without the overhead of creating model instances (from something like a dict) and then converting them back to dicts.

You may need to write a custom DjangoJSONEncoder subclass if you use any custom field types, to instruct json.dumps() how to encode those.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM