[Django] #35129: Support customize ForeignKey DDL when db_constraint=False

26 views
Skip to first unread message

Django

unread,
Jan 19, 2024, 4:46:14 AM1/19/24
to django-...@googlegroups.com
#35129: Support customize ForeignKey DDL when db_constraint=False
-------------------------------------+-------------------------------------
Reporter: elonzh | Owner: nobody
Type: | Status: new
Uncategorized |
Component: Database | Version: 5.0
layer (models, ORM) |
Severity: Normal | Keywords:
Triage Stage: | Has patch: 0
Unreviewed |
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
-------------------------------------+-------------------------------------
Sometimes we want to join tables without foreignkeys, so we define a
ForeignKey field with db_constraint=False to achieve this.

For example:

{{{
class Journal(Model):
issn = models.CharField(max_length=9, primary_key=True)
name = models.CharField(max_length=255)

class Biblio(Model):
# There already exists a field called issn in the Biblio model
# issn = models.CharField(max_length=50, default="", blank=True)
journal = models.ForeignKey(
Journal,
related_name="+",
db_column="issn",
db_constraint=False,
db_index=False,
on_delete=models.DO_NOTHING,
default="",
blank=True,
max_length=50,
)
}}}

In this example, we define a journal field from issn field and we want to
do a fake migration.

But the migratation will generate DDL like this:


{{{
--
-- Remove field issn from biblio
--
ALTER TABLE `userlibrary_biblio` DROP COLUMN `issn`;
--
-- Add field issn_record to biblio
--
ALTER TABLE `userlibrary_biblio` ADD COLUMN `issn` varchar(9) DEFAULT ''
NOT NULL;
ALTER TABLE `userlibrary_biblio` ALTER COLUMN `issn` DROP DEFAULT;
}}}

which is kind of awkward because that means Django will force max_length=9
and this is not we want.

--
Ticket URL: <https://code.djangoproject.com/ticket/35129>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Jan 19, 2024, 7:00:08 AM1/19/24
to django-...@googlegroups.com
#35129: Support customize ForeignKey DDL when db_constraint=False
-------------------------------------+-------------------------------------
Reporter: elonzh | Owner: nobody
Type: Uncategorized | Status: closed
Component: Database layer | Version: 5.0
(models, ORM) |
Severity: Normal | Resolution: invalid
Keywords: | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0

Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Mariusz Felisiak):

* status: new => closed
* resolution: => invalid


Comment:

`db_constraint` is only to disable creation of foreign key constraints in
the tables and to allow for handling legacy database structures (if you
don't other choice). It has nothing to do with a column data type that
should always match a data type of the referenced column. Moreover,
`max_length` is not a proper keyword argument for `ForeignKey` and as such
is ignored.

--
Ticket URL: <https://code.djangoproject.com/ticket/35129#comment:1>

Django

unread,
Jan 19, 2024, 8:58:24 AM1/19/24
to django-...@googlegroups.com
#35129: Support customize ForeignKey DDL when db_constraint=False
-------------------------------------+-------------------------------------
Reporter: elonzh | Owner: nobody
Type: Uncategorized | Status: closed
Component: Database layer | Version: 5.0
(models, ORM) |
Severity: Normal | Resolution: invalid
Keywords: | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by elonzh):

Replying to [comment:1 Mariusz Felisiak]:


> `db_constraint` is only to disable creation of foreign key constraints
in the tables and to allow for handling legacy database structures (if you
don't other choice). It has nothing to do with a column data type that
should always match a data type of the referenced column. Moreover,
`max_length` is not a proper keyword argument for `ForeignKey` and as such
is ignored.

I know those parameters are intentionally ignored, what I want is joining
tables without db_constraint. Django doesn't provide a method to achieve
this, so I define a fake ForeignKey as a workround.

I am curious that since it is allowed to set db_constraint=True for
handling legacy database structures, why `max_length` should be always


match a data type of the referenced column.

This behavior will make unnessary migrations for legacy database
structures, right?

--
Ticket URL: <https://code.djangoproject.com/ticket/35129#comment:2>

Django

unread,
Jan 19, 2024, 10:54:46 AM1/19/24
to django-...@googlegroups.com
#35129: Support customize ForeignKey DDL when db_constraint=False
-------------------------------------+-------------------------------------
Reporter: elonzh | Owner: nobody
Type: Uncategorized | Status: closed
Component: Database layer | Version: 5.0
(models, ORM) |
Severity: Normal | Resolution: invalid
Keywords: | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by Natalia Bidart):

Replying to [comment:2 elonzh]:
> [...] I want is joining tables without db_constraint. Django doesn't


provide a method to achieve this, so I define a fake ForeignKey as a
workround.

Another way of achieving this is by using a slightly more manual approach
involving subqueries. You could also consider seeking more help or ideas
in how to resolve this without using a foreign key by posting your
question n the [https://forum.djangoproject.com/c/users/using-the-orm/17
Django Forum], or using any of the user support channels from
[https://docs.djangoproject.com/en/dev/faq/help/#how-do-i-do-x-why-
doesn-t-y-work-where-can-i-go-to-get-help this link].

--
Ticket URL: <https://code.djangoproject.com/ticket/35129#comment:3>

Django

unread,
Jan 19, 2024, 11:11:25 AM1/19/24
to django-...@googlegroups.com
#35129: Support customize ForeignKey DDL when db_constraint=False
-------------------------------------+-------------------------------------
Reporter: elonzh | Owner: nobody
Type: Uncategorized | Status: closed
Component: Database layer | Version: 5.0
(models, ORM) |
Severity: Normal | Resolution: invalid
Keywords: | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by Simon Charette):

I think this will eventually come in a form or the other eventually
through a `Relation` object
[http://charettes.name/djangoconus2022/slides.html#39 that can be defined
at the model level] but in the mean time your best bet is to use (at your
own risks) the undocumented `django.db.models.ForeignObject` object to
define such relationships.

{{{#!python


class Journal(Model):
issn = models.CharField(max_length=9, primary_key=True)
name = models.CharField(max_length=255)

class Biblio(Model):


issn = models.CharField(max_length=50, default="", blank=True)

journal = models.ForeignObject(
Journal,
models.DO_NOTHING,
from_fields=["issn"],
to_fields=["issn"],
)
}}}

Under the hood `ForeignKey` is `Field` + `ForeignObject` + the equivalent
of a `ForeignKeyConstraint(ForeignObject)` entry in
`Model._meta.constraints` so if you care about the ORM + JOIN generation
part and don't want a database constraint it's likely what you're looking
for.

--
Ticket URL: <https://code.djangoproject.com/ticket/35129#comment:4>

Django

unread,
Jan 20, 2024, 12:32:25 PM1/20/24
to django-...@googlegroups.com
#35129: Support customize ForeignKey DDL when db_constraint=False
-------------------------------------+-------------------------------------
Reporter: elonzh | Owner: nobody
Type: Uncategorized | Status: closed
Component: Database layer | Version: 5.0
(models, ORM) |
Severity: Normal | Resolution: invalid
Keywords: | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by elonzh):

Replying to [comment:4 Simon Charette]:

Thanks for your suggestion, it's very helpful.

--
Ticket URL: <https://code.djangoproject.com/ticket/35129#comment:5>

Reply all
Reply to author
Forward
0 new messages