【问题标题】:Django model instance fields with ManyToMany relationship to Dict与字典具有多对多关系的 Django 模型实例字段
【发布时间】:2016-05-23 11:56:59
【问题描述】:

我正在尝试创建一个简单的操作,从数据库中获取一条记录(具有多对多关系),然后显示 JSON 序列化实例,这是我现在的做法:

服务模式:

class SystemService(models.Model):
    name = models.CharField(max_length=35, unique=True, null=False, blank=False)
    verion = models.CharField(max_length=35, unique=True, null=False, blank=False)

    def __str__(self):
        return self.name

服务器模型:

class Server(models.Model):
    name = models.CharField(max_length=35, unique=True, null=False, blank=False)
    ip_address = models.GenericIPAddressField(protocol='both', unpack_ipv4=True,
                                              null=False, blank=False, unique=True)
    operating_system = models.ForeignKey(OperatingSystem, null=False, blank=False)
    monitored_services = models.ManyToManyField(SystemService)
    info = models.CharField(max_length=250, null=True, blank=True)
    pause_monitoring = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.name

这是现在使用 muj-gabriel 答案的方式:

def get_server(request, server_id):
    try:
        server_object = Server.objects.get(id=server_id)
        data = {
            'name': server_object.name,
            'ip_address': server_object.ip_address,
            'os': server_object.operating_system.name,
            'info': server_object.info,
            'monitoring_paused': server_object.pause_monitoring,
            'created_at': server_object.created_at,
            'update_at': server_object.updated_at,
            'services': {service['id']: service['name'] for service
                     in server_object.monitored_services.values('id', 'name')}
        }
        return JsonResponse(data)
    except Server.DoesNotExist:
        return JsonResponse({'error': 'Selected object does not exits!'})

我认为我所做的还不够好,因为每次我需要将一个实例作为 JSON 获取时,我都必须重复同样的事情,所以我想知道是否有一种 Pythonic 和动态的方法来做是吗?

【问题讨论】:

    标签: python json django django-models


    【解决方案1】:

    如果您只需要值 'id' 和 'name' 我建议使用这个:

    'services': {service['id']: service['name'] 
                 for service in server_object.monitored_services.values('id', 'name')}
    

    django docs

    您还可以将代码移动到 Model 类的属性中,以便在其他地方重用。

    class Server(models.Model):
        .......
    
        @property
        def data(self):
            return {
                'name': self.name,
                'ip_address': self.ip_address,
                'os': self.operating_system.name,
                'info': self.info,
                'monitoring_paused': self.pause_monitoring,
                'created_at': self.created_at,
                'update_at': self.updated_at,
                'services': {service['id']: service['name'] for service in self.monitored_services.values('id', 'name')}
            }
    

    您的视图函数将是:

    def get_server(request, server_id):
        try:
            server_object = Server.objects.get(id=server_id)
            return JsonResponse(server_object.data)
        except Server.DoesNotExist:
            return JsonResponse({'error': 'Selected object does not exits!'})
    

    【讨论】:

    • 感谢您的回答我用它来改进我的代码,但当我说我不想每次都重复同样的事情时,我的意思是其他模型,所以我正在寻找为任何模型的实例执行此操作的独特方式。
    • 正如我在回答中所说,在 Model 类中创建一个 @property 并将代码移到那里
    • 我的意思是另一个模型(不仅仅是服务器)实例,抱歉我没有很好地解释自己。
    • 但是你每次重复的内容是什么?您是否有具有相同字段的类模型?
    • 做同样的操作,比如说我想为一个用户实例做同样的事情,我将不得不再次手动创建一个字典字段,这就是重复。
    【解决方案2】:

    在 Django 文档中查看了一下后,我发现了 model_to_dict 函数,它基本上可以满足我的需要(模型实例到 Dict),但是对于 ManyToMany 关系它只返回一个 PK 列表,所以我编写了自己的基于函数的函数就可以了:

    def db_instance2dict(instance):
        from django.db.models.fields.related import ManyToManyField
        metas = instance._meta
        data = {}
        for f in chain(metas.concrete_fields, metas.many_to_many):
            if isinstance(f, ManyToManyField):
                data[str(f.name)] = {tmp_object.pk: db_instance2dict(tmp_object)
                                     for tmp_object in f.value_from_object(instance)}
            else:
                data[str(f.name)] = str(getattr(instance, f.name, False))
        return data
    

    希望对其他人有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-17
      • 2020-09-04
      • 2014-05-16
      • 2020-07-01
      • 2012-03-25
      • 2011-05-25
      相关资源
      最近更新 更多