ForeignKey a la clase abstracta (relaciones genéricas)

Estoy construyendo un proyecto personal con Django, para entrenarme (porque amo a Django, pero pierdo habilidades). Tengo los requisitos básicos, sé Python, leí cuidadosamente el libro de Django dos veces, si no tres.

Mi objective es crear un servicio de monitoreo simple, con una interfaz web basada en Django que me permita verificar el estado de mis “nodos” (servidores). Cada nodo tiene múltiples “servicios”. La aplicación verifica la disponibilidad de cada servicio para cada nodo.

Mi problema es que no tengo idea de cómo representar diferentes tipos de servicios en mi base de datos. Pensé en dos “soluciones”:

  • modelo de servicio único , con un campo “tipo de servicio” y un gran desorden con los campos. (No tengo una gran experiencia en el modelado de bases de datos, pero esto me parece … “malo” para mí)
  • Múltiples modelos de servicio. Me gusta esta solución, pero no tengo idea de cómo puedo hacer referencia a estos servicios DIFERENTES en el mismo campo.

Este es un breve extracto de mi archivo models.py : (eliminé todo lo que no está relacionado con este problema)

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) 

Por supuesto, la línea con el ManyToManyField es falsa. No tengo idea de qué poner en lugar de “* Servicio”. Honestamente busqué soluciones sobre esto, escuché de “relaciones genéricas”, tablas de triple unión, pero realmente no entendí estas cosas.

Además, el inglés no es mi idioma nativo, por lo que, al llegar a la base de datos y la semántica, mi conocimiento y comprensión de lo que leo es limitado (pero ese es mi problema)

Para empezar, use la herencia de múltiples tablas de Django, en lugar del modelo abstracto que tiene actualmente.

Tu código se convertiría entonces en:

 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) 

En el nivel de la base de datos, esto creará una tabla de ‘servicio’, cuyas filas se vincularán mediante relaciones individuales con tablas separadas para cada servicio secundario.

La única dificultad con este enfoque es que cuando haces algo como lo siguiente:

 node = Node.objects.get(pk=node_id) for service in node.services.all(): # Do something with the service 

Los objetos de ‘servicio’ a los que accede en el bucle serán del tipo principal. Si sabe de antemano qué tipo de niño tendrá, puede acceder a la clase de niños de la siguiente manera:

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

Si no conoce el tipo de niño de antemano, se vuelve un poco más complicado. Hay algunas soluciones de hacky / desordenados, incluido un campo ‘serviceType’ en el modelo principal, pero una mejor manera, como mencionó Joe J, es usar un ‘queryset de subclases’. La clase InheritanceManager de django-model-utils es probablemente la más fácil de usar. Lee la documentación aquí , es un pequeño código realmente bueno.

Creo que un enfoque que podría considerar es un “conjunto de consultas de subclases”. Básicamente, le permite consultar el modelo principal y devolverá instancias de los modelos secundarios en el conjunto de consultas de resultados. Te permitiría hacer consultas como:

 models.service.objects.all() 

Y haz que te devuelva resultados como los siguientes:

 [ , , , ...] 

Para ver algunos ejemplos sobre cómo hacer esto, echa un vistazo a los enlaces en la publicación del blog que se encuentra a continuación.

http://jazstudios.blogspot.com/2009/10/django-model-inheritance-with.html

Sin embargo, si utiliza este enfoque, no debe declarar su modelo de servicio tan abstracto como lo hace en el ejemplo. Concedido, introducirás una combinación adicional, pero en general he encontrado que el conjunto de consultas de subclases funciona bastante bien para devolver un conjunto mixto de objetos en un conjunto de consultas.

De todos modos, espero que esto ayude, Joe.

Si está buscando relaciones genéricas de clave externa, debe verificar el marco de los tipos de contenido de Django (integrado en Django). Los documentos explican en gran medida cómo usarlo y cómo trabajar con relaciones genéricas.

Un servicio real solo puede estar en un nodo, ¿verdad? En ese caso cuando no tengas un campo.

 node = models.ForeignKey('node', related_name='services') 

en la clase de service ?