Keeping database foreign keys consistent
up vote
3
down vote
favorite
I am trying to write a django app with a PostgreSQL database. My problem can be reduced to the following minimal example:
Organization
- has 0 ... N workers
Worker
- belongs to an organization
Task
- belongs to an organization
- is assigned to no-one, or assigned to one worker within the same organization
I am unsure of how to design the database in a way that prevents inconsistent state - since both Worker and Task need to have a foreign key pointing to the Organization they belong to, it is possible to end up with an inconsistent state where a worker from organization A is assigned a task from organization B.
The only solution I could think of was verifying the constraint in the save method:
class Organization(models.Model):
name = models.CharField(max_length=255)
class Worker(models.Model):
name = models.CharField(max_length=255)
organization = models.ForeignKey(Organization, on_delete=models.CASCADE)
class Task(models.Model):
name = models.CharField(max_length=255)
organization = models.ForeignKey(Organization, on_delete=models.CASCADE)
assigned_to = models.ForeignKey(Worker, null=True, on_delete=models.SET_NULL)
def save(self, *args, **kwargs):
if self.assigned_to and self.assigned_to.organization != self.organization:
raise ValidationError('Task and Worker belong in different Organizations.')
return super(Task, self).save(*args, **kwargs
Is it possible to create a better solution which still prevents inconsistent state? My own solution doesn't seem like a good one from a database design point of view.
python django database schema normalization
New contributor
add a comment |
up vote
3
down vote
favorite
I am trying to write a django app with a PostgreSQL database. My problem can be reduced to the following minimal example:
Organization
- has 0 ... N workers
Worker
- belongs to an organization
Task
- belongs to an organization
- is assigned to no-one, or assigned to one worker within the same organization
I am unsure of how to design the database in a way that prevents inconsistent state - since both Worker and Task need to have a foreign key pointing to the Organization they belong to, it is possible to end up with an inconsistent state where a worker from organization A is assigned a task from organization B.
The only solution I could think of was verifying the constraint in the save method:
class Organization(models.Model):
name = models.CharField(max_length=255)
class Worker(models.Model):
name = models.CharField(max_length=255)
organization = models.ForeignKey(Organization, on_delete=models.CASCADE)
class Task(models.Model):
name = models.CharField(max_length=255)
organization = models.ForeignKey(Organization, on_delete=models.CASCADE)
assigned_to = models.ForeignKey(Worker, null=True, on_delete=models.SET_NULL)
def save(self, *args, **kwargs):
if self.assigned_to and self.assigned_to.organization != self.organization:
raise ValidationError('Task and Worker belong in different Organizations.')
return super(Task, self).save(*args, **kwargs
Is it possible to create a better solution which still prevents inconsistent state? My own solution doesn't seem like a good one from a database design point of view.
python django database schema normalization
New contributor
It would be great if the downvoter taught me what I did wrong, instead of just voting me down...
– けんじ
yesterday
One factor to consider is what happens if a worker changes organizations. Is that allowed? Do their tasks switch organizations too, or do they become unassigned? And so on. That might inform your design.
– Kevin Christopher Henry
yesterday
1
You want a task FK (worker, org) to worker. A FK says subrows must appear elsewhere a PKs. We need to identify all the restrictions that our database tables have & declare what we can as constraints & enforce others via triggers. This is a faq, that you might find if you googled many clear concise specific phrasings of your question/problem/goal. with & without your particular strings/names. PS Re downvoter presumably they think it is either unclear and/or not useful (maybe because it's a faq or there's no Minimal, Complete, and Verifiable example)--see the downvote arrow mouseover text.
– philipxy
yesterday
You'd need to implement acheck
. I got it from this answer: stackoverflow.com/a/39884447/1637351
– schillingt
23 hours ago
To add to @philipxy answer, I have found this post which also suggests a composite foreign key. To that end I have found this django module: django-composite-foreignkey
– CoffeeBasedLifeform
6 hours ago
add a comment |
up vote
3
down vote
favorite
up vote
3
down vote
favorite
I am trying to write a django app with a PostgreSQL database. My problem can be reduced to the following minimal example:
Organization
- has 0 ... N workers
Worker
- belongs to an organization
Task
- belongs to an organization
- is assigned to no-one, or assigned to one worker within the same organization
I am unsure of how to design the database in a way that prevents inconsistent state - since both Worker and Task need to have a foreign key pointing to the Organization they belong to, it is possible to end up with an inconsistent state where a worker from organization A is assigned a task from organization B.
The only solution I could think of was verifying the constraint in the save method:
class Organization(models.Model):
name = models.CharField(max_length=255)
class Worker(models.Model):
name = models.CharField(max_length=255)
organization = models.ForeignKey(Organization, on_delete=models.CASCADE)
class Task(models.Model):
name = models.CharField(max_length=255)
organization = models.ForeignKey(Organization, on_delete=models.CASCADE)
assigned_to = models.ForeignKey(Worker, null=True, on_delete=models.SET_NULL)
def save(self, *args, **kwargs):
if self.assigned_to and self.assigned_to.organization != self.organization:
raise ValidationError('Task and Worker belong in different Organizations.')
return super(Task, self).save(*args, **kwargs
Is it possible to create a better solution which still prevents inconsistent state? My own solution doesn't seem like a good one from a database design point of view.
python django database schema normalization
New contributor
I am trying to write a django app with a PostgreSQL database. My problem can be reduced to the following minimal example:
Organization
- has 0 ... N workers
Worker
- belongs to an organization
Task
- belongs to an organization
- is assigned to no-one, or assigned to one worker within the same organization
I am unsure of how to design the database in a way that prevents inconsistent state - since both Worker and Task need to have a foreign key pointing to the Organization they belong to, it is possible to end up with an inconsistent state where a worker from organization A is assigned a task from organization B.
The only solution I could think of was verifying the constraint in the save method:
class Organization(models.Model):
name = models.CharField(max_length=255)
class Worker(models.Model):
name = models.CharField(max_length=255)
organization = models.ForeignKey(Organization, on_delete=models.CASCADE)
class Task(models.Model):
name = models.CharField(max_length=255)
organization = models.ForeignKey(Organization, on_delete=models.CASCADE)
assigned_to = models.ForeignKey(Worker, null=True, on_delete=models.SET_NULL)
def save(self, *args, **kwargs):
if self.assigned_to and self.assigned_to.organization != self.organization:
raise ValidationError('Task and Worker belong in different Organizations.')
return super(Task, self).save(*args, **kwargs
Is it possible to create a better solution which still prevents inconsistent state? My own solution doesn't seem like a good one from a database design point of view.
python django database schema normalization
python django database schema normalization
New contributor
New contributor
New contributor
asked yesterday
けんじ
191
191
New contributor
New contributor
It would be great if the downvoter taught me what I did wrong, instead of just voting me down...
– けんじ
yesterday
One factor to consider is what happens if a worker changes organizations. Is that allowed? Do their tasks switch organizations too, or do they become unassigned? And so on. That might inform your design.
– Kevin Christopher Henry
yesterday
1
You want a task FK (worker, org) to worker. A FK says subrows must appear elsewhere a PKs. We need to identify all the restrictions that our database tables have & declare what we can as constraints & enforce others via triggers. This is a faq, that you might find if you googled many clear concise specific phrasings of your question/problem/goal. with & without your particular strings/names. PS Re downvoter presumably they think it is either unclear and/or not useful (maybe because it's a faq or there's no Minimal, Complete, and Verifiable example)--see the downvote arrow mouseover text.
– philipxy
yesterday
You'd need to implement acheck
. I got it from this answer: stackoverflow.com/a/39884447/1637351
– schillingt
23 hours ago
To add to @philipxy answer, I have found this post which also suggests a composite foreign key. To that end I have found this django module: django-composite-foreignkey
– CoffeeBasedLifeform
6 hours ago
add a comment |
It would be great if the downvoter taught me what I did wrong, instead of just voting me down...
– けんじ
yesterday
One factor to consider is what happens if a worker changes organizations. Is that allowed? Do their tasks switch organizations too, or do they become unassigned? And so on. That might inform your design.
– Kevin Christopher Henry
yesterday
1
You want a task FK (worker, org) to worker. A FK says subrows must appear elsewhere a PKs. We need to identify all the restrictions that our database tables have & declare what we can as constraints & enforce others via triggers. This is a faq, that you might find if you googled many clear concise specific phrasings of your question/problem/goal. with & without your particular strings/names. PS Re downvoter presumably they think it is either unclear and/or not useful (maybe because it's a faq or there's no Minimal, Complete, and Verifiable example)--see the downvote arrow mouseover text.
– philipxy
yesterday
You'd need to implement acheck
. I got it from this answer: stackoverflow.com/a/39884447/1637351
– schillingt
23 hours ago
To add to @philipxy answer, I have found this post which also suggests a composite foreign key. To that end I have found this django module: django-composite-foreignkey
– CoffeeBasedLifeform
6 hours ago
It would be great if the downvoter taught me what I did wrong, instead of just voting me down...
– けんじ
yesterday
It would be great if the downvoter taught me what I did wrong, instead of just voting me down...
– けんじ
yesterday
One factor to consider is what happens if a worker changes organizations. Is that allowed? Do their tasks switch organizations too, or do they become unassigned? And so on. That might inform your design.
– Kevin Christopher Henry
yesterday
One factor to consider is what happens if a worker changes organizations. Is that allowed? Do their tasks switch organizations too, or do they become unassigned? And so on. That might inform your design.
– Kevin Christopher Henry
yesterday
1
1
You want a task FK (worker, org) to worker. A FK says subrows must appear elsewhere a PKs. We need to identify all the restrictions that our database tables have & declare what we can as constraints & enforce others via triggers. This is a faq, that you might find if you googled many clear concise specific phrasings of your question/problem/goal. with & without your particular strings/names. PS Re downvoter presumably they think it is either unclear and/or not useful (maybe because it's a faq or there's no Minimal, Complete, and Verifiable example)--see the downvote arrow mouseover text.
– philipxy
yesterday
You want a task FK (worker, org) to worker. A FK says subrows must appear elsewhere a PKs. We need to identify all the restrictions that our database tables have & declare what we can as constraints & enforce others via triggers. This is a faq, that you might find if you googled many clear concise specific phrasings of your question/problem/goal. with & without your particular strings/names. PS Re downvoter presumably they think it is either unclear and/or not useful (maybe because it's a faq or there's no Minimal, Complete, and Verifiable example)--see the downvote arrow mouseover text.
– philipxy
yesterday
You'd need to implement a
check
. I got it from this answer: stackoverflow.com/a/39884447/1637351– schillingt
23 hours ago
You'd need to implement a
check
. I got it from this answer: stackoverflow.com/a/39884447/1637351– schillingt
23 hours ago
To add to @philipxy answer, I have found this post which also suggests a composite foreign key. To that end I have found this django module: django-composite-foreignkey
– CoffeeBasedLifeform
6 hours ago
To add to @philipxy answer, I have found this post which also suggests a composite foreign key. To that end I have found this django module: django-composite-foreignkey
– CoffeeBasedLifeform
6 hours ago
add a comment |
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
けんじ is a new contributor. Be nice, and check out our Code of Conduct.
けんじ is a new contributor. Be nice, and check out our Code of Conduct.
けんじ is a new contributor. Be nice, and check out our Code of Conduct.
けんじ is a new contributor. Be nice, and check out our Code of Conduct.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53179127%2fkeeping-database-foreign-keys-consistent%23new-answer', 'question_page');
}
);
Post as a guest
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
It would be great if the downvoter taught me what I did wrong, instead of just voting me down...
– けんじ
yesterday
One factor to consider is what happens if a worker changes organizations. Is that allowed? Do their tasks switch organizations too, or do they become unassigned? And so on. That might inform your design.
– Kevin Christopher Henry
yesterday
1
You want a task FK (worker, org) to worker. A FK says subrows must appear elsewhere a PKs. We need to identify all the restrictions that our database tables have & declare what we can as constraints & enforce others via triggers. This is a faq, that you might find if you googled many clear concise specific phrasings of your question/problem/goal. with & without your particular strings/names. PS Re downvoter presumably they think it is either unclear and/or not useful (maybe because it's a faq or there's no Minimal, Complete, and Verifiable example)--see the downvote arrow mouseover text.
– philipxy
yesterday
You'd need to implement a
check
. I got it from this answer: stackoverflow.com/a/39884447/1637351– schillingt
23 hours ago
To add to @philipxy answer, I have found this post which also suggests a composite foreign key. To that end I have found this django module: django-composite-foreignkey
– CoffeeBasedLifeform
6 hours ago