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
14 changes: 13 additions & 1 deletion typedmodels/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,19 @@ def do_related_class(self, other, cls):
remote_field = field.remote_field
if isinstance(remote_field.model, TypedModel) and remote_field.model.base_class:
remote_field.limit_choices_to['type__in'] = remote_field.model._typedmodels_subtypes
field.contribute_to_class(base_class, field_name)

# Check if a field with this name has already been added to class
try:
duplicate_field = base_class._meta.get_field(field_name)
# Check if the field being added is _exactly_ the same as the field
# that already exists.
if duplicate_field.deconstruct()[1:] != field.deconstruct()[1:]:
raise ValueError("Can't add field '%s' from '%s' to '%s', field already exists.",
field_name, classname, base_class.__name__)
# Otherwise, the field already exists on the base class. Don't add it.
except FieldDoesNotExist:
field.contribute_to_class(base_class, field_name)

classdict.pop(field_name)
base_class._meta.fields_from_subclasses.update(declared_fields)

Expand Down
13 changes: 13 additions & 0 deletions typedmodels/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,16 @@ class Child1(Parent):

class Child2(Parent):
pass


class Employee(TypedModel):
pass


class Developer(Employee):
name = models.CharField(max_length=255, null=True)


class Manager(Employee):
# Adds the _exact_ same field as Developer. Shouldn't error.
name = models.CharField(max_length=255, null=True)
14 changes: 13 additions & 1 deletion typedmodels/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

from .models import TypedModelManager
from .test_models import AngryBigCat, Animal, BigCat, Canine, Feline, Parrot, AbstractVegetable, Vegetable, \
Fruit, UniqueIdentifier, Child2
Fruit, UniqueIdentifier, Child2, Employee


@pytest.fixture
Expand Down Expand Up @@ -308,3 +308,15 @@ def test_explicit_recast_with_string_on_untyped_instance():
animal.recast('typedmodels.feline')
assert animal.type == 'typedmodels.feline'
assert type(animal) is Feline


def test_same_field_name_in_two_subclasses():
with pytest.raises(ValueError):
class Tester1(Employee):
name = models.CharField(max_length=255, blank=True, null=True)
with pytest.raises(ValueError):
class Tester2(Employee):
name = models.CharField(max_length=254, null=True)
with pytest.raises(ValueError):
class Tester3(Employee):
name = models.IntegerField(null=True)