Is there a way to add additional fields on an implicit many-to-many table in Django?

Viewed 50

Consider the following models

in models.py:

class Volunteer(models.Model):
    account = models.OneToOneField(
        UserAccount,
        on_delete=models.CASCADE,
        related_name= "volunteer",
        primary_key=True)


    request_offers = models.ManyToManyField('Request', related_name="volunteers", blank = True)
    volunteer_communities = models.ManyToManyField('Community', related_name="volunteers", blank = True)
class Request(models.Model):
    req_type = models.ForeignKey('RequestTypes', related_name="requests", on_delete = models.CASCADE, blank = False, null = False)

A volunteer can have many request_offers(type of request).

In the implicit appname_volunteer_request (many-to-many) table, I want another field called date besides the default fields -- id, request_id and volunteer_id.

Is there a way to add an additional field on the implicit table without creating a through table?

Thanks! :)

2 Answers

The simplest and most elegant way to do this is with a through=… model [Django-doc], this will eventually require the least amount of work to keep data in sync. In your through model, that will act as a junction table [wiki], you can specify a DateTimeField or any other field:

class Volunteer(models.Model):
    # …
    request_offers = models.ManyToManyField(
        'Request',
        related_name='volunteers',
        through='VolunteerRequest',
        blank = True
    )

class Request(models.Model):
    req_type = models.ForeignKey(
        'RequestTypes',
        related_name='requests',
        on_delete = models.CASCADE
    )

class VolunteerRequest(models.Model):
    volunteer = models.ForeignKey(
        Volunteer,
        on_delete=models.CASCADE
    )
    request = models.ForeignKey(
        Request,
        on_delete=models.CASCADE
    )
    date = models.DateTimeField(auto_now_add=True)

Making more tables will only require extra logic to keep these tables in sync, and will often make queries more complicated and will make the database less efficient.

Unfortunately, there is no way to do it without a through table.

You can attempt to create one more table where the id of through table will be paired with date, and then change it whenever a signal is fired on thorough table.Other option is to manage it manually by overriding methods of the manager save, delete, create and methods of the relation manager add, clean, remove, set


Information that might help you: https://docs.djangoproject.com/en/3.2/ref/signals/#post-save https://docs.djangoproject.com/en/4.0/topics/db/models/#intermediary-manytomany

Related