In the normal development process, it is inevitable to encounter the need to convert the model into a dictionary, especially now the popular front and back end separation architecture, Json format has almost become the standard for data exchange between the front and back end, this model to dict demand is more, this paper introduces several daily use methods for reference. All examples are based on the Django 2.0 environment demo

background

The model contents are as follows:

class Group(models.Model):
    name = models.CharField(max_length=255, unique=True, verbose_name='Group name')

    def __str__(self):
        return self.name

class User(models.Model):
    create_time = models.DateTimeField(auto_now_add=True, verbose_name='Creation time')
    update_time = models.DateTimeField(auto_now=True, verbose_name='Update Time')
    username = models.EmailField(max_length=255, unique=True, verbose_name='Username')
    fullname = models.CharField(max_length=64, null=True, verbose_name='Chinese name')
    is_active = models.BooleanField(default=True, verbose_name='Active state')
    leader = models.ForeignKey('self', null=True, on_delete=models.CASCADE, verbose_name='superior')
    group = models.ManyToManyField(Group, null=True, verbose_name='Owning Group')

    def __str__(self):
        return self.username
Copy the code

The requirement is simply to return the data in the Group and User tables in dictionary format, respectively

Method one: Build the dictionary directly

Sample code:

>>> _t = Group.objects.get(id=1)
>>> 
>>> dict = {
...   'id': _t.id,
...   'name': _t.name ... } > > > > > >print(dict)
{'name': 'GroupA'.'id': 1}
Copy the code

The advantage of this method is that it is convenient to control the format of the dictionary value returned in the end. For example, for the User table, I want to return the final data is ID, creation time, Chinese name, parent Chinese name, the group name list can be implemented with the following code

>>> _t = User.objects.get(id=2)
>>> 
>>> dict = {
...   'id': _t.id,
...   'create_time': _t.create_time.strftime('%Y-%m-%d %H:%M:%S'),...'fullname': _t.fullname if _t.fullname else None,
...   'leader': _t.leader.fullname if _t.leader else None,
...   'group': [ i.name for i in_t.group.all() ], ... } > > > > > >print(dict)
{'fullname': Operation coffee Bar.'group': ['GroupA'.'GroupC'.'GroupE'].'create_time': 'the 2018-10-12 21:20:19'.'id': 2.'leader': 'Public Account'} > > >Copy the code

The disadvantages are obvious: if a model field has many fields and does not need to convert the value format, it needs to write a lot of redundant code. Take a look at the method below

Method 2:dict

Sample code:

>>> Group.objects.get(id=1).__dict__
{'id': 1, 'name': 'GroupA'.'_state': <django.db.models.base.ModelState object at 0x7f68612daef0>}
>>> 
>>> User.objects.get(id=1).__dict__
{'is_active': True, '_state': <django.db.models.base.ModelState object at 0x7f68612fa0b8>, 'id': 1, 'username': '[email protected]'.'leader_id': None, 'fullname': 'Public Account'.'update_time': datetime.datetime(2018, 10, 12, 17, 49, 35, 504141), 'create_time': datetime.datetime(2018, 10, 12, 16, 9, 7, 813660)}
Copy the code

The advantage of this method is that it is simple to write, easy to understand, and less code

However, I will find that there is an extra useless _state field, and the Foreignkey field name has more _id, and there is no data of ManyToManyField field, and the output cannot be displayed as required. When I only need a few of these fields, there will be a lot of redundant data

Method 3: model_to_dict

Sample code:

>>> model_to_dict(Group.objects.get(id=1))
{'name': 'GroupA'.'id': 1}
>>> 
>>> model_to_dict(User.objects.get(id=2))
{'leader': 1, 'is_active': True, 'username': '[email protected]'.'fullname': Operation coffee Bar.'group': [<Group: GroupA>, <Group: GroupC>, <Group: GroupE>], 'id'2} :Copy the code

This method can meet most of the requirements, and the output is reasonable. In addition, two parameters, fields and exclude, are used to configure the output fields. For example:

>>> model_to_dict(User.objects.get(id=2), fields=['fullname'.'is_active'])
{'is_active': True, 'fullname': Operation coffee Bar}
>>> 
>>> model_to_dict(User.objects.get(id=2), exclude=['group'.'leader'.'id'])
{'fullname': Operation coffee Bar.'is_active': True, 'username': '[email protected]'}
Copy the code

Datetime fields with auto_now_add=True and auto_now=True will be added with the editable=False hidden attribute by default. Create_time and update_time are not dict values.

for f in chain(opts.concrete_fields, opts.private_fields, opts.many_to_many):
    if not getattr(f, 'editable', False):
        continue
Copy the code

Method 4: Customize to_dict

Sample code:

from django.db.models.fields import DateTimeField
from django.db.models.fields.related import ManyToManyField

class User(models.Model):
    ...

    def to_dict(self, fields=None, exclude=None):
        data = {}
        for f in self._meta.concrete_fields + self._meta.many_to_many:
            value = f.value_from_object(self)

            if fields and f.name not in fields:
                continue

            if exclude and f.name in exclude:
                continue

            if isinstance(f, ManyToManyField):
                value = [ i.id for i in value ] if self.pk else None

            if isinstance(f, DateTimeField):
                value = value.strftime('%Y-%m-%d %H:%M:%S') if value else None

            data[f.name] = value

        return data
Copy the code

Execution Result:

>>> User.objects.get(id=2).to_dict()
{'is_active': True, 'update_time': 'the 2018-10-12 21:21:39'.'username': '[email protected]'.'id': 2.'leader': 1, 'group': [1, 3, 5].'create_time': 'the 2018-10-12 21:20:19'.'fullname': Operation coffee Bar}
>>> 
>>> User.objects.get(id=2).to_dict(fields=['fullname'.'is_active'.'create_time'])
{'is_active': True, 'fullname': Operation coffee Bar.'create_time': 'the 2018-10-12 21:20:19'}
>>> 
>>> User.objects.get(id=2).to_dict(exclude=['group'.'leader'.'id'.'create_time'])
{'is_active': True, 'update_time': 'the 2018-10-12 21:21:39'.'username': '[email protected]'.'fullname': Operation coffee Bar}
Copy the code

With the convenience of model_to_dict, it also solves the problem that time fields (Editable =False) cannot be output, and can output values according to their own format. Of course, with the convenience, to_dict code needs to be implemented by themselves, which increases the complexity


Related articles are recommended reading

  • Django Model Select
  • Introduction to the various uses of Django Model Update
  • Django configures tasks with asynchronous tasks and timed tasks
  • Django Model to a dictionary
  • Django uses Signals to send notifications that detect changes in the Model field
  • Django+Echarts drawing example
  • Djangos password management table
  • Django+JWT implements Token authentication
  • Djangos integrated Markdown editor
  • Djangos default permissions mechanism introduction and practice
  • Djangos built-in permission extension example
  • Django integrates OpenLDAP authentication
  • Django uses Channels to implement WebSocket
  • Django implements WebSocket using Channels — part 2
  • Write a freehand static page generator using Django
  • Django+zTree builds the organizational structure tree