How to relate an 'Object' to several 'Objects' Foreigkey

2

Asking for your support again, I am making an application to inventory the electrical and optical ports of various equipment, and it is not clear to me how to relate a model with several models.

I have the following two objects:

class ITarjeta(models.Model):
    tipo_tarjeta = models.ForeignKey('catalogo.Tarjeta')
    nomenclatura = models.CharField(max_length=30)
    etiqueta = models.CharField(max_length=30)
    equipo = models.ForeignKey(IEquipo)

    autor = models.ForeignKey(settings.AUTH_USER_MODEL)
    fecha_hora_alta = models.DateTimeField(
        null=True, blank=True, default=timezone.now)

    class Meta:
        verbose_name_plural = "Tarjetas"

    def __str__(self):
        return str(self.nomenclatura)

class ISwitch(models.Model):
    tipo_switch = models.ForeignKey('catalogo.Switch')
    nomenclatura = models.CharField(max_length=30)
    etiqueta = models.CharField(max_length=30)
    rack = models.ForeignKey(IRack)

    autor = models.ForeignKey(settings.AUTH_USER_MODEL)
    fecha_hora_alta = models.DateTimeField(
        null=True, blank=True, default=timezone.now)

    class Meta:
        verbose_name_plural = "Switc's"

    def __str__(self):
        return str(self.nomenclatura)

And also created two other objects that are what I want to relate:

class IPuertoOptico(models.Model):
    nomenclatura = models.CharField(max_length=30)
    equipo = models.ForeignKey(ITarjeta) //tambien lo quiero relacionar con ISwtch

    autor = models.ForeignKey(settings.AUTH_USER_MODEL)
    fecha_hora_alta = models.DateTimeField(
    null=True, blank=True, default=timezone.now)

    class Meta:
        verbose_name_plural = "Puertos Opticos en Equipos"

    def __str__(self):
            return '%s' % (self.nomenclatura)


class IPuertoElectrico(models.Model):
    nomenclatura = models.CharField(max_length=30)
    equipo = models.ForeignKey(ITarjeta) //tambien lo quiero relacionar con ISwtch


    autor = models.ForeignKey(settings.AUTH_USER_MODEL)
    fecha_hora_alta = models.DateTimeField(
        null=True, blank=True, default=timezone.now)

    class Meta:
        verbose_name_plural = "Puertos Electricos en Equipos"

    def __str__(self):
            return '%s' % (self.nomenclatura)

I decided to relate the ports with the equipment since the equipment can have many ports, but a port can only have one computer. The problem comes when I want to relate the 'IPuertoElectrico' model to the 'ISwitch' and 'ITarjeta' models.

Someone can guide me on what is the best way to make these relationships.

Greetings.

    
asked by Rocke 20.08.2016 в 11:59
source

1 answer

1

If you want to be able to use the same ForeignKey that points to multiple models, it is possible. I imagine that a IPuertoElectrico can only point to a Tarjeta or a Switch .

What Toledo suggests is feasible, you would have two columns, one pointing to ITarjeta and another to ISwitch , only that always one of them will be NULL and when wanting to pull data you will have to see which of them is the valid one In addition to adding logic to your application so that it does not allow assigning the object to a switch and a card simultaneously.

To use the same ForeignKey that can point to more than one model, you can use the Generic ForeignKey of the Django Content Types Framework. Also known as polymorphic relationships. ( documentation )

In your settings.py file of your project, make sure you have the contenttypes app installed

#settings.py

INSTALLED_APPS = (
    'otra_aplicacion',
    'django.contrib.contenttypes',
    'mira_otra_aplicacion',
)

In your models you would make the following changes.

from django.db import models
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType

class IPuertoOptico(models.Model):
    nomenclatura = models.CharField(max_length=30)

    # ---------------- #
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey('content_type', 'object_id')
    # ---------------- #

    autor = models.ForeignKey(settings.AUTH_USER_MODEL)
    fecha_hora_alta = models.DateTimeField(
        null=True, blank=True, default=timezone.now)

    class Meta:
        verbose_name_plural = "Puertos Opticos en Equipos"

    def __str__(self):
        return '%s' % (self.nomenclatura)

The content_type field stores the id of the type of model you are relating to. This points to a record in the django_content_type table of your database. If you open it there you can find each model registered in your project. In summary, he tells Django which model we are going to use for the relationship.

The object_id field stores the id of the object you are relating, this points to a record inside the related object table. In summary, we tell Django that the specific record of the model is related.

The field content_object is where we declare the relation itself and in which we pass the names of the two previous fields.

Example, we are going to associate an ITarjeta and an ISwitch to two IPuertoOptico:

We import the models

>>> from tu_aplicacion.models import ITarjeta, ISwitch, IPuertoOptico

We got the optical ports, here we assume that there are ids 1 and 2.

>>> puerto_1 = IPuertoOptico.objects.get(id=1)
>>> puerto_2 = IPuertoOptico.objects.get(id=2)

We got the card and switch. We also assume that there are ids 1

>>> tarjeta = ITarjeta.objects.get(id=1)
>>> switch = ISwitch.objects.get(id=1)

We associate the objects.

>>> puerto_1.content_object = tarjeta
>>> puerto_1.save()
>>> puerto_1.content_object
<ITarjeta: tu_nomenclatura>

>>> puerto_2.content_object = switch
>>> puerto_2.save()
>>> puerto_2.content_object
<ISwitch: tu_nomenclatura>

If you notice now we only have to pass the instance of the object that we want to relate and voila! is related no matter what type of object it is. Depending on the complexity of your system, it may be necessary to add other configurations.

    
answered by 20.08.2016 / 18:16
source