Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions django/db/models/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -709,9 +709,17 @@ def _set_pk_val(self, value):

def _is_pk_set(self, meta=None):
pk_val = self._get_pk_val(meta)

def _is_set(value):
return (
value is None
# Empty value when db_default is used.
or isinstance(value, DatabaseDefault)
)

return not (
pk_val is None
or (isinstance(pk_val, tuple) and any(f is None for f in pk_val))
_is_set(pk_val)
or (isinstance(pk_val, tuple) and any(_is_set(f) for f in pk_val))
)

def get_deferred_fields(self):
Expand Down
1 change: 1 addition & 0 deletions tests/basic/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,7 @@ def test_is_pk_unset(self):
cases = [
Article(),
Article(id=None),
PrimaryKeyWithDbDefault(),
]
for case in cases:
with self.subTest(case=case):
Expand Down
3 changes: 2 additions & 1 deletion tests/composite_pk/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from .tenant import Comment, Post, Tenant, TimeStamped, Token, User
from .tenant import Comment, Post, PostDbDefault, Tenant, TimeStamped, Token, User

__all__ = [
"Comment",
"Post",
"PostDbDefault",
"Tenant",
"TimeStamped",
"Token",
Expand Down
6 changes: 6 additions & 0 deletions tests/composite_pk/models/tenant.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ class Post(models.Model):
id = models.UUIDField(default=uuid.uuid4)


class PostDbDefault(models.Model):
pk = models.CompositePrimaryKey("tenant_id", "id")
tenant = models.ForeignKey(Tenant, on_delete=models.CASCADE, default=1)
id = models.IntegerField(db_default=1)


class TimeStamped(models.Model):
pk = models.CompositePrimaryKey("id", "created")
id = models.SmallIntegerField(unique=True)
Expand Down
8 changes: 7 additions & 1 deletion tests/composite_pk/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from django.forms import modelform_factory
from django.test import TestCase

from .models import Comment, Post, Tenant, TimeStamped, Token, User
from .models import Comment, Post, PostDbDefault, Tenant, TimeStamped, Token, User


class CommentForm(forms.ModelForm):
Expand Down Expand Up @@ -64,6 +64,12 @@ def test_pk_updated_if_field_updated(self):
self.assertIsNone(user.id)
self.assertIs(user._is_pk_set(), False)

def test_pk_not_set_db_default(self):
post = PostDbDefault(tenant=self.tenant)
self.assertEqual(post.tenant_id, self.tenant.pk)
self.assertIsNotNone(post.id)
self.assertIs(post._is_pk_set(), False)

def test_hash(self):
self.assertEqual(hash(User(pk=(1, 2))), hash((1, 2)))
self.assertEqual(hash(User(tenant_id=2, id=3)), hash((2, 3)))
Expand Down
22 changes: 22 additions & 0 deletions tests/inline_formsets/models.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from django.db import models
from django.db.models.functions import UUID4


class School(models.Model):
Expand All @@ -21,6 +22,27 @@ class Meta:
]


class ParentUUIDPk(models.Model):
uuid = models.UUIDField(primary_key=True, db_default=UUID4(), editable=False)

class Meta:
required_db_features = {
"supports_uuid4_function",
"supports_expression_defaults",
}


class ChildUUIDPk(models.Model):
parent = models.ForeignKey(ParentUUIDPk, models.CASCADE)
name = models.CharField(max_length=100)

class Meta:
required_db_features = {
"supports_uuid4_function",
"supports_expression_defaults",
}


class Poet(models.Model):
name = models.CharField(max_length=100)

Expand Down
14 changes: 13 additions & 1 deletion tests/inline_formsets/tests.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from django.forms.models import ModelForm, inlineformset_factory
from django.test import TestCase, skipUnlessDBFeature

from .models import Child, Parent, Poem, Poet, School
from .models import Child, ChildUUIDPk, Parent, ParentUUIDPk, Poem, Poet, School


class DeletionTests(TestCase):
Expand Down Expand Up @@ -113,6 +113,18 @@ def test_save_new(self):
obj.save()
self.assertEqual(school.child_set.count(), 1)

@skipUnlessDBFeature("supports_uuid4_function", "supports_expression_defaults")
def test_add_form_uuid_pk(self):
ChildFormSet = inlineformset_factory(ParentUUIDPk, ChildUUIDPk, fields=["name"])
data = {
"child_set-TOTAL_FORMS": "1",
"child_set-INITIAL_FORMS": "1",
"child_set-MAX_NUM_FORMS": "0",
"child_set-0-name": "child",
}
formset = ChildFormSet(data)
self.assertIs(formset.is_valid(), False)


class InlineFormsetFactoryTest(TestCase):
def test_inline_formset_factory(self):
Expand Down
Loading