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

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

问题描述

我正在和Django建立一个个人项目来训练自己(因为我喜欢Django,但是我想念技能)。我有基本的要求,我知道Python,我仔细阅读了Django书两次,如果不是三次。



我的目标是创建一个简单的监控服务,基于Web的界面允许我检查我的节点(服务器)的状态。每个节点有多个服务。应用程序检查每个节点的每个服务的可用性。



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




  • 单一服务模型,使用serviceType字段,大场混乱。 (我在数据库建模方面没有很好的经验,但这看起来对我来说不好)

  • 多个服务模型。我喜欢这个解决方案,但是我不知道如何在同一个字段中引用这些不同的服务。



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

 从django.db导入模型

#在这里创建您的模型。
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

类节点(models.Model):
name = models.CharField(max_length = 64)
#各个字段
services = models .ManyToManyField(service)

当然,与ManyToManyField的行是假的。我不知道该怎么代替*服务。我诚实地寻求解决方案,我听说过通用关系,三连接表,但我没有真正理解这些东西。此外,英语不是我的母语,所以来到数据库结构和语义,我对我读的知识和理解是有限的(但这是我的问题)

解决方案

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



然后你的代码将成为:

 从django.db导入模型

类服务(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服务):
pass

class GenericUDPService(服务):
通过

类节点(models.Model):
name = models.CharField(max_length = 64)
#各个字段
服务= models.ManyToManyField(Service)

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



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

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

为节点中的服务。 services.all():
#使用服务执行某些操作

服务对象您在循环中的访问将是父类型。
如果你知道这些孩子预先有什么类型,你可以通过以下方式访问孩子类:

  from django.core.exceptions import ObjectDoesNotExist 

try:
telnet_service = service.telnetservice
except(AttributeError,ObjectDoesNotExist):
#你选择了错误的子类型!
telnet_service =无

如果您不预先知道孩子类型,比较棘手。有一些黑客/凌乱的解决方案,包括父模型上的'serviceType'字段,但是像Joe J所说的更好的方法是使用'子类化查询集'。来自django-model-utils的InheritanceManager类可能是最容易使用的。阅读文档这里,这是一个非常好的一点代码。


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.

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" :

  • 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.

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)

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)

解决方案

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

Your code would then become:

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

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.

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

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