抽象类的外键(泛型关系) [英] ForeignKey to abstract class (generic relations)

查看:21
本文介绍了抽象类的外键(泛型关系)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在用 Django 构建一个个人项目,以训练自己(因为我喜欢 Django,但我想念技能).我有基本要求,我懂Python,我仔细读了两遍Django书.

I'm building a personal project with Django, to train myself (because I love Django, but I miss skills). I have the basic requirements, I know Python, I carefully read the Django book twice if not thrice.

我的目标是创建一个简单的监控服务,使用基于 Django 的 Web 界面让我可以检查节点"(服务器)的状态.每个节点都有多个服务".应用程序检查每个节点的每个服务的可用性.

My goal is to create a simple monitoring service, with a Django-based web interface allowing me to check status of my "nodes" (servers). Each node has multiple "services". The application checks the availability of each service for each node.

我的问题是我不知道如何在我的数据库中表示不同类型的服务.我想到了两个解决方案":

My problem is that I have no idea how to represent different types of services in my database. I thought of two "solutions" :

  • 单一服务模型,有一个serviceType"字段,字段乱七八糟.(我在数据库建模方面没有丰富的经验,但这看起来......对我来说不好")
  • 多种服务模式.我喜欢这个解决方案,但我不知道如何在同一领域引用这些不同服务.
  • single service model, with a "serviceType" field, and a big mess with the fields. (I have no great experience in database modeling, but this looks... "bad" to me)
  • multiple service models. i like this solution, but then I have no idea how I can reference these DIFFERENT services in the same field.

这是我的 models.py 文件的简短摘录:(我删除了与此问题无关的所有内容)

This is a short excerpt from my models.py file : (I removed everything that is not related to this problem)

from django.db import models

# Create your models here.                                                                                                                          
class service(models.Model):
    port = models.PositiveIntegerField()
    class Meta:
        abstract = True

class sshService(service):
    username = models.CharField(max_length=64)
    pkey = models.TextField()   

class telnetService(service):
    username = models.CharField(max_length=64)
    password = models.CharField(max_length=64)

class genericTcpService(service):
    pass

class genericUdpService(service):
    pass

class node(models.Model):
    name = models.CharField(max_length=64)
    # various fields                                                                                                                                
    services = models.ManyToManyField(service)

当然,ManyToManyField 行是假的.我不知道用什么来代替*服务".我诚实地搜索了有关此的解决方案,我听说过通用关系",三联表,但我并没有真正理解这些东西.

Of course, the line with the ManyToManyField is bogus. I have no idea what to put in place of "*Service". I honestly searched for solutions about this, I heard of "generic relations", triple-join tables, but I did'nt really understand these things.

此外,英语不是我的母语,所以谈到数据库结构和语义,我对阅读的知识和理解是有限的(但那是我的问题)

Moreover, English is not my native language, so coming to database structure and semantics, my knowledge and understanding of what I read is limited (but that's my problem)

推荐答案

首先,使用 Django 的 多表继承,而不是你目前拥有的抽象模型.

For a start, use Django's multi-table inheritance, rather than the abstract model you have currently.

您的代码将变为:

from django.db import models

class Service(models.Model):
    port = models.PositiveIntegerField()

class SSHService(Service):
    username = models.CharField(max_length=64)
    pkey = models.TextField()   

class TelnetService(Service):
    username = models.CharField(max_length=64)
    password = models.CharField(max_length=64)

class GenericTcpService(Service):
    pass

class GenericUDPService(Service):
    pass

class Node(models.Model):
    name = models.CharField(max_length=64)
    # various fields                                                                                                                                
    services = models.ManyToManyField(Service)

在数据库级别,这将创建一个服务"表,其中的行将通过一对一关系链接到每个子服务的单独表.

On the database level, this will create a 'service' table, the rows of which will be linked via one to one relationships with separate tables for each child service.

这种方法的唯一困难是当您执行以下操作时:

The only difficulty with this approach is that when you do something like the following:

node = Node.objects.get(pk=node_id)

for service in node.services.all():
    # Do something with the service

您在循环中访问的服务"对象将是父类型.如果您事先知道这些将具有哪些子类,则可以通过以下方式访问子类:

The 'service' objects you access in the loop will be of the parent type. If you know what child type these will have beforehand, you can just access the child class in the following way:

from django.core.exceptions import ObjectDoesNotExist

try:
    telnet_service = service.telnetservice
except (AttributeError, ObjectDoesNotExist):
    # You chose the wrong child type!
    telnet_service = None

如果您事先不知道子类型,它会变得有点棘手.有一些笨拙/凌乱的解决方案,包括父模型上的serviceType"字段,但正如 Joe J 提到的,更好的方法是使用子类化查询集".来自 django-model-utils 的 InheritanceManager 类可能是最容易使用的.阅读它的文档这里,这是一段非常不错的代码.

If you don't know the child type beforehand, it gets a bit trickier. There are a few hacky/messy solutions, including a 'serviceType' field on the parent model, but a better way, as Joe J mentioned, is to use a 'subclassing queryset'. The InheritanceManager class from django-model-utils is probably the easiest to use. Read the documentation for it here, it's a really nice little bit of code.

这篇关于抽象类的外键(泛型关系)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆