简体   繁体   English

具有与Toct的ManyToMany关系的Django模型实例字段

[英]Django model instance fields with ManyToMany relationship to Dict

I'm trying to create a simple action that gets one record (with ManyToMany relationship) from the database then display the JSON serialized instance, here is how I did it for now: 我正在尝试创建一个简单的操作,该操作从数据库中获取一条记录(具有ManyToMany关系),然后显示JSON序列化实例,这是我目前的操作方式:

the service model: 服务模式:

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

the server model: 服务器型号:

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

Here is how it is now using muj-gabriel answer: 这就是现在使用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!'})

I don't think that what I did is good enough since I have to repeat the same thing each time I need to get one instance as JSON, so I would like to know if is there a pythonic and dynamic way to do it? 我认为我所做的工作不够好,因为每次我需要获取一个实例作为JSON时都必须重复相同的事情,所以我想知道是否存在一种pythonic和动态的方式来做到这一点?

If you just need the values 'id' and 'name' I suggest using this: 如果您只需要值'id'和'name',我建议使用以下方法:

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

See django docs 参见Django文档

Also you can move the code into a property to the Model class to reuse it elsewhere. 您也可以将代码移到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')}
        }

Your view function will be: 您的查看功能将是:

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!'})

After looking a bit in the Django doc I found the model_to_dict function, which basically do what I need (Model instance to Dict), but for the ManyToMany relationship it only returns a list of PKs, so I wrote my own function based on it: 在Django文档中查看了一下之后,我发现了model_to_dict函数,该函数基本上可以完成我需要的任务(将Model实例转换为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

Hope it helps someone else. 希望它可以帮助别人。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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