2

So I just tested one thing, making the following tables.

# Dump of table driverclass
# ------------------------------------------------------------

CREATE TABLE `driverclass` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

# Dump of table event
# ------------------------------------------------------------

CREATE TABLE `event` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

# Dump of table driver
# ------------------------------------------------------------

CREATE TABLE `driver` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

# Dump of table driver_driverclass_event
# ------------------------------------------------------------

CREATE TABLE `driver_driverclass_event` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `driver_id` int(11) unsigned DEFAULT NULL,
  `event_class_id` int(11) unsigned DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `driver_id` (`driver_id`),
  KEY `event_class_id` (`event_class_id`),
  CONSTRAINT `driver_driverclass_event_ibfk_2` FOREIGN KEY (`event_class_id`) REFERENCES `driverclass_event` (`id`),
  CONSTRAINT `driver_driverclass_event_ibfk_1` FOREIGN KEY (`driver_id`) REFERENCES `driver` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

# Dump of table driverclass_event
# ------------------------------------------------------------

CREATE TABLE `driverclass_event` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `event_id` int(11) unsigned DEFAULT NULL,
  `driverclass_id` int(11) unsigned DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `event_id` (`event_id`),
  KEY `driverclass_id` (`driverclass_id`),
  CONSTRAINT `driverclass_event_ibfk_2` FOREIGN KEY (`driverclass_id`) REFERENCES `driverclass` (`id`),
  CONSTRAINT `driverclass_event_ibfk_1` FOREIGN KEY (`event_id`) REFERENCES `event` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

Which should be relations in terms of ManyToManyField. However, Djangos inspectdb looked at it as 5 models with tons of ForeignKeys. Doesn't Djangos inspectdb take ManyToManyFields into account, or is my databasemodel wrong?

Martol1ni
  • 4,684
  • 2
  • 29
  • 39

1 Answers1

5

Your database schema appears to be alright. However Django doesn't automatically create Many-To-Many fields as you have found out. The models for driverclass_event and ** driver_driverclass_event** are a so-called 'through' models. Normally you would also define ManyToManyField on both ends of the relationship and specify the correct 'through' model:

class Event(db.Model):
    pass

class DriverClass(db.Model):
    events = db.ManyToManyField(Event, through='DriverClassEvent')

class DriverClassEvent(db.Model):
    driver_class = db.ForeignKeyField(DriverClass)
    event = db.ForeignKeyField(Event)

See also: https://docs.djangoproject.com/en/dev/topics/db/models/#extra-fields-on-many-to-many-relationships

Normally through models are used when you want to store information about the relationship, like the start date of the relationship or to refer to this relationship using a foreign key. In your example, you store which drivers have a relationship to a DriverClassEvent. So DriverClassEvent should have a model to be able to refer to it.

class DriverDriverClassEvent(db.Model):
    driver = db.ForeignKeyField(Driver)
    driver_class_event = db.ForeignKeyField(DriverClassEvent)

class Driver(db.Model):
    driver_class_events = db.ManyToManyField(DriverClassEvent, through='DriverDriverClassEvent')

Now you could drop the DriverDriverClassEvent as you don't store any data about that relationship, or refer to the relationship in other models. So the last example becomes*:

class Driver(db.Model):
    driver_class_events = db.ManyToManyField(DriverClassEvent, db_table='driver_driverclass_event')

* Note that you don't have control over the field names, so those would have to match to Django's auto-generated field names.

Bouke
  • 11,768
  • 7
  • 68
  • 102
  • Thanks alot for the post. I'm not sure if you understand the model, but it doesn't feel quite right. I'm simply trying to connect the driver to a certain class and a certain event. Also, in the last example, can i write ManyToManyField(DriverClassEvent... without specifying a model for DriverClassEvent? – Martol1ni Aug 06 '13 at 13:28
  • See also my edit, I got confused by the table names. -- Your database model defines a many-to-many between **driverclass** and **event**, called **driverclass_event**. Then there is a relation between **driverclass_event** and **driver**, called **driver_driverclass_event**. So there you have 3 simple entities with 2 relations, resulting in 5 tables and 5 models. It appears that you don't want to have two binary relations, but one ternary relation. That would also require a different database schema design. – Bouke Aug 06 '13 at 16:13