2
votes

Django - Relation symétrique OneToOneField

J'écris et j'utilise une application pour gérer mes équipements réseau. J'ai créé un modèle, RJ45port, que je peux ajouter à mon équipement au besoin. Un port RJ45 peut être branché sur un autre port RJ45 et un seul.

Voici le modèle que j'ai créé:

def save(self, *args, **kwargs):
    super(RJ45port, self).save()    
    self.plugged_into.plugged_into = self

Quand je "branche" un port RJ45 dans un autre, je veux que le second ait "plugged_into" réglé sur le premier . Je veux que la relation soit symétrique. Si je "débranche", je veux que les deux ports RJ45 aient "plugged_into" mis à null ou vide.

J'ai trouvé un peu de code, ça pourrait être un indice:

class RJ45port(models.Model):
    plugged_into = models.OneToOneField('self', on_delete=models.SET_NULL, blank=True, null=True)

Pour être honnête je suis un peu perdu ici et c'est la dernière étape J'ai besoin de rendre cette application fonctionnelle ...


0 commentaires

3 Réponses :


1
votes

Vous êtes mieux adapté en créant simplement une méthode modèle plug_into () , puis en l'utilisant pour "brancher" une instance dans une autre, ainsi qu'un unplug ()

Exemple:

port_1 = Port.objects.all()[0]  # First port
port_2 = Port.objects.all()[1]  # Second port
port_1.plug_into(port_2)  # Should return [instance, instance]
port_1.unplug()  # Should return [None, None]

Et puis vous pouvez l'appeler comme ceci:

class RJ45port(models.Model):
    plugged_into = models.OneToOneField('self', on_delete=models.SET_NULL, blank=True, null=True)

    def plug_into(self, instance):
        self.plugged_into = instance
        instance.plugged_into = self

        self.save(update_fields=['plugged_into'])
        instance.save(update_fields=['plugged_into'])
        return [self.plugged_into, instance.plugged_into]

    def unplug(self):
        self.plugged_into.plugged_into = None
        self.plugged_into = None

        self.plugged_into.save(update_fields=['plugged_into'])
        self.save(update_fields=['plugged_into'])
        return [self.plugged_into, instance.plugged_into]


6 commentaires

Cela semble intéressant, mais comment appeler plug_into et le débrancher dans ma page d'administration?


@vjuluss Je remplacerais la méthode admin save_model () pour appeler les méthodes plug_int () et unplug () . Un exemple peut être montré ici: stackoverflow.com/a/21852651/3345051


si self.plugged_into, appelez plug_into, sinon appelez unplug?


@vjuluss Je vérifierais si l'instance a changé, et si c'est le cas, j'appelle obj.plug_into () ou obj.unplug () selon s'il y a une nouvelle valeur pour obj.plugged_into . Vous pouvez voir comment procéder ici stackoverflow.com/questions/8056179/...


Eh bien, je ne peux pas le faire fonctionner ... ça ne devrait pas fonctionner sur un problème comme celui-ci à la fin de la journée ...


@vjuluss Pas de problème! Parfois, vous devez faire une pause pour avoir l'esprit clair. Je voudrais vous aider davantage, mais cela devient très difficile car je n'ai pas un bon environnement de test. Vous devriez réessayer bientôt, et vous pourrez toujours poser une autre question concernant le remplacement de save_model () dans django admin (dont je connais très peu). J'espère que quelqu'un pourra vous aider à résoudre cette deuxième partie du problème.



1
votes

Vous avez raison. Remplacez simplement la méthode de sauvegarde. Mais appelez super (). Save () à la fin:

class RJ45port(models.Model):
    plugged_into = models.OneToOneField('self', on_delete=models.SET_NULL, blank=True, null=True)

    def save(self, *args, **kwargs): 
        self.plugged_into.plugged_into = self
        super(RJ45port, self).save()   


2 commentaires

Il y a trois problèmes avec cela. 1) self.plugged_into.plugged_into n'est jamais enregistré, 2) Il y a une condition de concurrence si vous utilisez self.plugged_into.plugged_into.save () - qui se produira en premier, le .save () de l'instance secondaire ou l'instance initiale? 3) Il y aura une boucle infinie de méthodes save () qui s’appelleront


Le problème avec ceci est que lorsque je veux "débrancher", Django renvoie une erreur disant que None n'a pas d'objet "plugged_into"



0
votes

Une autre option consiste à utiliser un related_name afin de pouvoir effectuer un accès inverse à partir de l'instance référencée, de sorte que vous puissiez dire que la relation devient "symétrique". Le seul inconvénient est que vous ne pouvez pas utiliser le même nom pour référencer les deux connexions:

class RJ45port(models.Model):
    plugged_into = models.OneToOneField('self', on_delete=models.SET_NULL, blank=True, null=True, related_name='plugged_from')

Dans cet exemple, plugged_from peut être interrogé comme n'importe quel autre champ du instance référencée.


1 commentaires

Je pense comprendre votre suggestion. Je pourrais essayer plus tard quand je pourrai coder. Mais je ne pense pas que cela montrera la connexion inverse dans l'interface d'administration ...?