2

I'd like to create a model in which a user owns a certain number of shares in multiple companies. It seems like I should use the Django intermediate model relationship, but I'm not sure how to apply an intermediate model to the built-in Django User Model.

Right now, companies have a ManyToMany relationship with shareholders (users), how do I add number of shares to each specific company-shareholder relationship?

class Company(models.Model):
    name = models.CharField(max_length=200)
    shareholder = models.ManyToManyField(User, blank=True)
tei1
  • 35
  • 1
  • 8
  • See the docs on [extra fields on many-to-many relationships](https://docs.djangoproject.com/en/2.0/topics/db/models/#extra-fields-on-many-to-many-relationships) – Alasdair Jan 26 '18 at 16:54

2 Answers2

0

You can use the many to many field with a through attribute

from django.conf import settings


class Company(models.Model):
    name = models.CharField(max_length=200)
    shareholder = models.ManyToManyField(settings.AUTH_USER_MODEL, through='Foo', blank=True)

class Foo(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    company = models.ForeignKey('Company', on_delete=models.CASCADE)
    number_of_shares = models.FloatField()
at14
  • 1,194
  • 9
  • 16
  • Thank you! The big thing was using AUTH_USER_MODEL. I didn't know about that before. – tei1 Jan 26 '18 at 19:48
0

This is how I might do it:

from django.db import models
from django.contrib.auth.models import User

class Shareholder(models.Model):
    name = models.CharField(max_length=128)
    user = models.OneToOneField(to=User, related_name='shareholder_profile')

    def __str__(self):
        return self.name

class Company(models.Model):
    name = models.CharField(max_length=128)
    shareholders = models.ManyToManyField(Shareholder, through='Shareholding')

    def __str__(self):
        return self.name

class Shareholding(models.Model):
    shareholder = models.ForeignKey(Shareholder, on_delete=models.CASCADE)
    company = models.ForeignKey(Company, on_delete=models.CASCADE)
    date_shares_purchased = models.DateField()
    number_of_shares = models.PositiveIntegerField()

Instead of using the User model directly, I would create a Shareholder model with a one-to-one relationship with the User. Then I would create the many-to-many relationship between the Shareholders and Company with a Shareholding intermediate model.

This technique of extending the User model using a one-to-one relationship with a Profile model is described in more detail in the original docs and on this article

Kevin L.
  • 1,371
  • 11
  • 24
  • This is interesting, Kevin. What would be the pros/cons of using this method as opposed to using the User model directly, as suggested by at14? – tei1 Jan 26 '18 at 20:16
  • have a look at this https://simpleisbetterthancomplex.com/tutorial/2016/07/22/how-to-extend-django-user-model.html IMHO having a user profile (in this case shareholder profile) makes the code cleaner and more readable and you can operate/extend the Shareholder model without affecting the User model. – Kevin L. Jan 26 '18 at 20:31
  • in case it's not clear, i'm using the technique described in "Extending User Model Using a One-To-One Link" in the link above. – Kevin L. Jan 26 '18 at 20:39
  • I personally don't like using a UserProfile model, if you are starting a new project you can extend the AbstractUser class and swap out the django user for your own user (which can have any number of additional attributes, and still integrate well with django).If you are building a project that's already been in production, then making the 1-1 link is the only clean way to do it. Read more about extending the AbstractUse (https://docs.djangoproject.com/en/2.0/topics/auth/customizing/#using-a-custom-user-model-when-starting-a-project), Django itself recommends doing this on a new project.Cheers – at14 Jan 28 '18 at 05:38