Django Crosstab Model Structure

I have a system model and an interface model. An interface is a combination between two systems. Previously, this interface was presented as an Excel worksheet (crosstab). Now I would like to save it to the database.

I tried to create an interface model with two foreign keys for System. This does not work because:

  • It creates two different inverse relationships in the target model.
  • It does not avoid duplication (first and second rel swapped)

I used this code:

class SystemInterface(Interface): assigned_to = models.ManyToManyField(User) first_system = models.ForeignKey(System) second_system = models.ForeignKey(System) 

Is there a better way to do this?

I need to have a symmetrical relationship: it doesn't matter if the system is β€œfirst” or β€œsecond” in the interface.

+6
source share
3 answers

I think the easiest way to introduce these models is:

 class System(models.Model): pass class Interface(models.Model): assigned_to = models.ManyToManyField(to=User) system = models.ForeignKey(System) @property def systems(self): Interface.objects.get(system=self.system).interfacedsystem_set.all() class InterfacedSystem(models.Model): interface = models.ForeignKey(Interface) system = models.ForeignKey(System) 

Adding / removing a paired system is obviously left as an exercise for the reader, put should be fairly simple.

+4
source

You can use many, many relationships with extra fields , but it cannot be symmetric .

The table used for the many-many relationship contains a row for the relationship between the two models. The table used for many, many relationships from System to self has one row for each relationship between two systems. This is consistent with the fact that your model follows the model structure used for ManyToManyField.through .

Using an intermediate model allows you to add fields like assign_to to many tables.

This may be difficult to understand, but this should prevent the creation of a SystemInterface (left_system = system_ a , right_system = system_ b ). Note that I changed the "first" to "left" and the "second" to "right" in order to represent many, many row / instance relationships that have a "left" side and a "right" side.

Since they cannot be symmetrical, this will not solve the problem of having one SystemInterface (left_system = system_ a , right_system = system_ b ) and one with SystemInterface (left_system = system_ b , right_system = system_ a ). You must prevent this from the clean () method in SystemInterface β€” or any model used to represent many of the many tables using ManyToManyField. through the model.

+2
source

Since django does not support symmetrical many-to-many relationships with additional data, you probably need to force this yourself.

If you have a convenient, immutable value in the system (for example, the system identifier), you can create a predictable algorithm for which the system will be stored in a record in your table. If, at the time of creation of the System Interface object, they are always saved, you can use the primary key.

Then write a function to create the interface. For instance:

 class System(models.Model): def addInterface(self, other_system, user): system_interface = SystemInterface() system_interface.assigned_to = user if other_system.id < self.id: system_interface.first_system = other_system system_interface.second_system = self else: system_interface.first_system = self system_interface.second_system = other_system system_interface.save() return system_interface 

Using this construct, you can perform a routine check, duplication detection, etc. on the SystemInterface object. The main thing is that you apply the restriction in your code, not in the data model.

It makes sense?

+2
source

All Articles