Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

charettes
Copy link
Member

…rd-only arguments.

Using keyword only arguments follows the `Index.__init__` pattern signature to
easen the addition of constraint options in the future.

Also renamed the `constraint` argument to `check` to better represent which
part of the constraint the provided `Q` object represents.

This change will be particularily useful when we add partial constraint support
because an additional `Q` object passing be required.
This type of constraint is currently similar to the unique_together entries of
a model but allow a name to be specified.

Eventually it will be possible to pass conditions to it in order to define
partial unique constraints.
@charettes charettes requested review from MarkusH and felixxm August 6, 2018 03:47
Copy link
Member Author

@charettes charettes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My main request for feedback at this point is whether or not this would be better implemented as Index(unique=True) instead.

In all cases I think the schema level refactor and the BaseConstraint extraction are worth merging because it allows the definition of custom constraints without too much boiler plate.

For example, PostgreSQL exclusion constraints could be defined in django.contrib.postgres without too much work.



class CheckConstraint(BaseConstraint):
def __init__(self, *, check, name):
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The motivation behind this signature change it detailed in the commit message but I wanted to gather feedback about it here.

  1. Using keyword only arguments aligns this API with the Index one and makes sure arguments are explicitly named. This is something that was mentioned during the review of Fixed #11964 -- Added support for check constraints in model Meta. #7615 related to the ordering of constraint and name.
  2. Changed the constraint name to check because it wasn't the actual constraint that was being provided. Maybe unnecessary.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1: I'm definitely happy with this. I'm not sure why I didn't go for it myself.
2: Fine by me, I don't feel strongly.

@LilyAcorn
Copy link
Contributor

My instinct on the Index vs Constraint question is that a Constraint is probably more intuitive and discoverable.

class UniqueConstraint(BaseConstraint):
def __init__(self, *, fields, name):
if not fields:
raise ValueError('At least one field is required to define an index.')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Getting an error about an index when creating a constraint is confusing unless you understand the implementation details.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Completely right, this was copy-pasted from Index.__init__().

.. module:: django.db.models.constraints

.. currentmodule:: django.db.models

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps this file should be renamed to constraints.txt and the title changed to Constraints reference.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed.

constraint to enforce.

For example ``UniqueConstraint(fields=['room', 'date'], name='unique_location')``
ensures only a room location can exist for each ``date``.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"only one" reads slightly better I think.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, this docs is quite rough so far.

Copy link
Member Author

@charettes charettes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Ian-Foote

My instinct on the Index vs Constraint question is that a Constraint is probably more intuitive and discoverable.

That's how I felt as well. My main concern what that there's so such thing as partial unique constraints.

From PostgreSQL docs

A uniqueness restriction covering only some rows cannot be written as a unique constraint, but it is possible to enforce such a restriction by creating a unique partial index.

So it'd probably be less effort to add Index(unique=True) support once #10140 lands instead because such constraints would have to be created using the CREATE INDEX syntax anyway.

constraint to enforce.

For example ``UniqueConstraint(fields=['room', 'date'], name='unique_location')``
ensures only a room location can exist for each ``date``.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, this docs is quite rough so far.

.. module:: django.db.models.constraints

.. currentmodule:: django.db.models

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed.

class UniqueConstraint(BaseConstraint):
def __init__(self, *, fields, name):
if not fields:
raise ValueError('At least one field is required to define an index.')
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Completely right, this was copy-pasted from Index.__init__().

@LilyAcorn
Copy link
Contributor

I don't think we should let the implementation details of partial unique constraints on postgres prevent us choosing the more intuitive api in Django for full unique constraints.

When we have support for partial unique indexes, we can add a note to the constraints documentation explaining the workaround.

model._meta.get_field(field_name).column for field_name in self.fields
)
return schema_editor.sql_unique_constraint % {
'columns': ', '.join(map(schema_editor.quote_name, columns))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe you could turn columns into a list comprehension that uses schema_editor.quote_name and get rid of the map() here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@orf I wouln't mind switching to a generator expression if deemed necessary, I just found the former shorter then

 ', '.join(schema_editor.quote_name(c) for c in columns)

@charettes
Copy link
Member Author

Closing in favor of #10337.

@charettes charettes closed this Aug 29, 2018
@charettes charettes deleted the unique-constraint branch August 29, 2018 04:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants