-
Notifications
You must be signed in to change notification settings - Fork 96
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Foreign keys in partitioned models #178
Comments
This is technically supported because PostgreSQL 12 added support for this. Example: https://www.2ndquadrant.com/en/blog/postgresql-12-foreign-keys-and-partitioned-tables/ It doesn't quite work because of the SQL Django generates to create the foreign key. Django uses the following to create the foreign key: https://github.com/django/django/blob/d4c5d2b52c897ccc07f04482d3f42f976a79223c/django/db/backends/base/schema.py#L119 It should drop the migrations.SeparateDatabaseAndState(
state_operations=[
migrations.AddField(
model_name="mymodel",
field=models.ForeignKey("mypartitionedmodel", on_delete=models.CASCADE),
),
],
database_operations=[
# Create the field without the db constraint
migrations.AddField(
model_name="mymodel",
field=models.ForeignKey("mypartitionedmodel", on_delete=models.CASCADE, db_constraint=False),
),
# Create the constraint manually
migrations.RunSQL(
"ALTER TABLE myapp_mymodel ADD CONSTRAINT <constraint name> REFERENCES mypartitionedmodel",
"ALTER TABLE myapp_mymodel DROP CONSTRAINT <constraint name>",
),
],
) |
I was not I'm afraid. We didn't need partitioning for our workload in the end so we moved on. |
Okay Thanks for the update @keyz182, we need partitioning in our case, but it seems the documentation is not clear and needs to fight a little to get it work. |
I unfortunately haven't been successful in getting foreign keys to a partition table to work either. Note that here I'm trying to have a partitioned model have a foreign key to a second partitioned model. Both have unique id fields as the primary key, and use range partitioning on created_at. Examples of what I've tried: This produces a syntax error since you need a type of reference: REFERENCE [some type]
Using just SQL ends up with this error:
I'd still prefer to use foreign keys, but for now it looks like I'll have to just store the id as a regular old integer and take care of data integrity in some other way. So if there is actually a way to pull this off, I'm happy to try again. |
That's a legit error, you need 2 columns for a FK that references 2 columns. So you will need to add two fields, then separately issue the FK:
https://www.postgresql.org/message-id/24581.1501335701%40sss.pgh.pa.us Now the question is how to get a single name into Django ORM for the referred object - until then, you'd have to change the |
Here is my working example. Initially I had this:
Then I partitioned Task by (func, args) to obtain TaskPartitioned. Now I have these:
And on the other table, SQL migrations: operations = [
# Create the constraint manually
migrations.RunSQL(
"""ALTER TABLE data_taskdependencypartitioned
ADD CONSTRAINT data_taskdependencypartitioned_fk_next
FOREIGN KEY (next_func, next_args)
REFERENCES data_taskpartitioned (func, args)
ON DELETE CASCADE
""",
"""ALTER TABLE data_taskdependencypartitioned
DROP CONSTRAINT data_taskdependencypartitioned_fk_next""",
),
migrations.RunSQL(
"""ALTER TABLE data_taskdependencypartitioned
ADD CONSTRAINT data_taskdependencypartitioned_fk_prev
FOREIGN KEY (prev_func, prev_args)
REFERENCES data_taskpartitioned (func, args)
ON DELETE CASCADE
""",
"""ALTER TABLE data_taskdependencypartitioned
DROP CONSTRAINT data_taskdependencypartitioned_fk_prev""",
),
] I'll post the custom lookup if i get it working. And then maybe we can see if we could wrap all of this boilerplate under some custom Edit: Adding a FK like this will prevent you from deleting the partitions. When trying to revert a "AddPartitions" transaction that came after the FK above, I get this error:
So this means the "AddPartition" transaction needs to happen before creation of the FK - and also means you can't dynamically delete any partitions after FK creation. This might be a problem with rolling timestamp RANGE partitions |
That's great to see! I reckon the approach mentioned here for truncating a table would also work for this use case. Specifically, the first comment by Laurenz about dropping the constraint, deleting or detaching the table or partition, then re-creating the constraint it if needed. |
@Photonios what is the update about this ? |
@gabriel-v 's code does the trick, I was able to use a variation of it to get FKs to datetime range partitioned table data. I havent yet attempted a custom lookup. At the risk of repetition, here's what I did:
Then the model itself:
|
Ok i see thanks. I am not a big fan of this solution since the relationship between the two tables only appears in the postgresql constraint and not in the django code itself. For my use case, i think that i will go for a solution using |
I'm trying to create an FK pointing to the pk of a partitioned table. The docs only mention that this isn't supported in Postgres 10.x, so I'm using 13.
I have a pair of test models:
I create a migration with
python ./manage.py pgmakemigrations
. Then try to runmigrate
but I get:My guess at the moment from some poking around is that maybe the FK creation is looking for a unique constraint on the
id
field, but because it's partitioned, the unique constraint is actually acrossid
andcreated_on
. If I try to create a unique constraint onid
it of course complains due to it not includingcreated_on
.Is this actually supported? Have I missed something, or am I doing something wrong? Or is this a bug?
The text was updated successfully, but these errors were encountered: