I'm working with an Account model and I want to inner join it with a Settings model without having to create an additional settings_id
column in my Account model, because the PK on the Account table matches the PK on the settings table exactly. I've been trying to set up a OneToOne relationship between these tables & columns, but can't figure out how to do that without having to create a new column or something. I'm trying to work with the existing schema as much as possible and would prefer to not create unnecessary columns.
Class Account(models.Model):
login_id = models.AutoField(primary_key=True)
settings = models.OneToOneField('Settings', to_field='login_id', null=True,
related_name='settings', db_column='login_id') # Doesn't work because login_id already exists....
Class Settings(model.Model):
login_id = models.OneToOneField('Account', to_field='login_id', related_name='account')
Basically, the query I'm trying to replicate is:
SELECT * FROM account
INNER JOIN settings
ON account.login_id=settings.login_id
WHERE account.login_id=1
Based on the errors, Django's ORM seems really persistent on creating a new column in the Account table, but I don't see the point of adding a new column when the relationship between the 2 tables is so simple: account.login_id = settings.login_id
Do Django models support multiple-column primary keys? ¶ No. Only single-column primary keys are supported.
Your intermediate model must contain one - and only one - foreign key to the source model (this would be Group in our example), or you must explicitly specify the foreign keys Django should use for the relationship using ManyToManyField.
Django will create or use an autoincrement column named id by default, which is the same as your legacy column.
By default, Django adds an id field to each model, which is used as the primary key for that model. You can create your own primary key field by adding the keyword arg primary_key=True to a field. If you add your own primary key field, the automatic one will not be added.
Although I've never tried it myself, declaring the OneToOneField
as the primary key should work.
class Account(models.Model):
login_id = models.AutoField(primary_key=True)
class Settings(model.Model):
account = models.OneToOneField('Account', to_field='login_id',
primary_key=True, related_name='settings')
Declaring the primary_key
will keep Django from trying to create a primary key column for you, and with this setup you can access account.settings
and settings.account
or settings.account_id
.
Here's what I ended up doing:
class Account(models.Model):
login_id = models.AutoField(primary_key=True)
def get_settings_dict(self):
try:
return self.settings.to_dict()
except Settings.DoesNotExist:
return Settings.get_defaults_dict()
class Settings(model.Model):
account = models.OneToOneField('Account', to_field='login_id', related_name='settings')
# other settings properties
# other settings properties
def to_dict(self):
# return current values as dict
@staticmethod
def get_defaults_dict():
# return default values dict
This allowed me to access a user's settings via account.settings
without having to create an additional settings_id
column on the Account model. The OneToOne relationship wasn't needed on both models.
Also, the get_settings_dict
method returns the default settings when the settings do not exist yet for a user. This is a nice convenience that prevents me from having to do a null check every time I access the user's settings via account.settings
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With