ForeignKey для абстрактного класса (общие отношения)
Я создаю персональный проект с Django, чтобы тренироваться (потому что я люблю Django, но я пропускаю навыки). У меня есть основные требования, я знаю Python, я внимательно читал книгу Django дважды, если не трижды.
Моя цель - создать простую службу мониторинга с помощью веб-интерфейса на основе Django, позволяющего проверить статус моих "узлов" (серверов). Каждый node имеет несколько "сервисов". Приложение проверяет доступность каждой службы для каждого node.
Моя проблема в том, что я понятия не имею, как представлять различные типы сервисов в моей базе данных. Я подумал о двух "решениях":
- единственная модель сервиса с полем "serviceType" и большой беспорядок с полями. (У меня нет большого опыта в области моделирования баз данных, но это выглядит... "плохо" для меня).
- несколько моделей обслуживания. Мне нравится это решение, но потом я понятия не имею, как я могу ссылаться на эти службы РАЗНЫЕ в том же поле.
Это короткий отрывок из моего файла models.py: (я удалил все, что не связано с этой проблемой)
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 является фиктивной. Я понятия не имею, что поставить вместо "Сервис". Я честно искал решения об этом, я слышал о "родовых отношениях", таблицах с тройным соединением, но я действительно этого не понимал.
Кроме того, английский не является моим родным языком, поэтому, приходя в структуру и семантику базы данных, мои знания и понимание того, что я читаю, ограничены (но это моя проблема)
Ответы
Ответ 1
Для начала используйте Django наследование нескольких таблиц, а не абстрактную модель, которую вы сейчас используете.
Тогда ваш код будет выглядеть следующим образом:
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)
На уровне базы данных это создаст таблицу "службы", строки которой будут связаны друг с другом отношениями с отдельными таблицами для каждой дочерней службы.
Единственная проблема с этим подходом заключается в том, что когда вы делаете что-то вроде следующего:
node = Node.objects.get(pk=node_id)
for service in node.services.all():
# Do something with the service
Объекты "службы", к которым вы обращаетесь в цикле, будут иметь тип родителя.
Если вы знаете, какой тип ребенка они будут иметь заранее, вы можете просто получить доступ к дочернему классу следующим образом:
from django.core.exceptions import ObjectDoesNotExist
try:
telnet_service = service.telnetservice
except (AttributeError, ObjectDoesNotExist):
# You chose the wrong child type!
telnet_service = None
Если вы не знаете тип ребенка заранее, это становится немного сложнее. Существует несколько хакерских/беспорядочных решений, в том числе поле "serviceType" в родительской модели, но лучший способ, как сказал Джо Дж, - использовать "набор запросов подкласса". Класс InheritanceManager из django-model-utils, вероятно, самый простой в использовании. Прочитайте документацию для него здесь, это действительно хороший маленький код.
Ответ 2
Я думаю, что один из подходов, который вы можете рассмотреть, - это "выборка для подкласса". В принципе, он позволяет запрашивать родительскую модель и возвращает экземпляры дочерних моделей в наборе запросов результатов. Это позволит вам делать такие запросы, как:
models.service.objects.all()
и верните ему результаты, как показано ниже:
[ <sshServiceInstance>, <telnetServiceInstance>, <telnetServiceInstance>, ...]
В некоторых примерах о том, как это сделать, посмотрите ссылки в блоге, приведенные ниже.
http://jazstudios.blogspot.com/2009/10/django-model-inheritance-with.html
Однако, если вы используете этот подход, вы не должны объявлять свою модель обслуживания абстрактной, как в примере. Конечно, вы добавите дополнительное соединение, но в целом я обнаружил, что запрос на выполнение подкласса работает очень хорошо для возврата смешанного набора объектов в набор запросов.
В любом случае, надеюсь, что это поможет,
Джо
Ответ 3
Если вы ищете общие отношения с внешним ключом, вы должны проверить структуру содержимого Django (встроенный в Django). Документы в значительной степени объясняют, как использовать его и как работать с родовыми отношениями.
Ответ 4
Фактическое обслуживание может быть только на одном node, правильно? В этом случае, когда не имеет поля
node = models.ForeignKey('node', related_name='services')
в классе service
?