Exemplo n.º 1
0
    def test_alter_column(self, initial_model, changed_field_name_model):
        initial_field = initial_model._meta.get_field("integer")
        new_field = changed_field_name_model._meta.get_field("changed")
        assert db_table_has_field("tests_initialmodel", "integer")
        assert not db_table_has_field("tests_initialmodel", "changed")

        FieldSchemaEditor(initial_field).alter_column(changed_field_name_model,
                                                      new_field)

        assert db_table_has_field("tests_initialmodel", "changed")
        assert not db_table_has_field("tests_initialmodel", "integer")
Exemplo n.º 2
0
    def test_alter_column(self, initial_model, changed_field_name_model):
        initial_field = initial_model._meta.get_field('integer')
        new_field = changed_field_name_model._meta.get_field('changed')
        assert db_table_has_field('tests_initialmodel', 'integer')
        assert not db_table_has_field('tests_initialmodel', 'changed')

        FieldSchemaEditor(initial_field).alter_column(changed_field_name_model,
                                                      new_field)

        assert db_table_has_field('tests_initialmodel', 'changed')
        assert not db_table_has_field('tests_initialmodel', 'integer')
Exemplo n.º 3
0
 def test_update_column_creates_if_not_exists(self, initial_model):
     initial_field = initial_model._meta.get_field("integer")
     assert not db_table_has_field("tests_initialmodel", "integer")
     FieldSchemaEditor().update_column(initial_model, initial_field)
     assert db_table_has_field("tests_initialmodel", "integer")
Exemplo n.º 4
0
 def test_add_column(self, initial_model):
     assert not db_table_has_field("tests_initialmodel", "integer")
     new_field = initial_model._meta.get_field("integer")
     FieldSchemaEditor().add_column(initial_model, new_field)
     assert db_table_has_field("tests_initialmodel", "integer")
Exemplo n.º 5
0
 def test_drop_column(self, initial_model):
     field = initial_model._meta.get_field('integer')
     assert db_table_has_field('tests_initialmodel', 'integer')
     FieldSchemaEditor().drop_column(initial_model, field)
     assert not db_table_has_field('tests_initialmodel', 'integer')
Exemplo n.º 6
0
class FieldSchema(models.Model):
    _PROHIBITED_NAMES = ('__module__', '_schema', '_declared')
    _MAX_LENGTH_DATA_TYPES = ('character', )

    name = models.CharField(max_length=63)
    model_schema = models.ForeignKey(ModelSchema,
                                     on_delete=models.CASCADE,
                                     related_name='fields')
    data_type = models.CharField(max_length=16,
                                 choices=FieldFactory.data_type_choices(),
                                 editable=False)
    null = models.BooleanField(default=False)
    unique = models.BooleanField(default=False)
    max_length = models.PositiveIntegerField(null=True)

    class Meta:
        unique_together = (('name', 'model_schema'), )

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._initial_name = self.name
        self._initial_null = self.null
        self._initial_field = self.get_registered_model_field()
        self._schema_editor = FieldSchemaEditor(self._initial_field)

    def save(self, **kwargs):
        self.validate()
        super().save(**kwargs)
        self.update_last_modified()
        model, field = self._get_model_with_field()
        self._schema_editor.update_column(model, field)

    def delete(self, **kwargs):
        model, field = self._get_model_with_field()
        self._schema_editor.drop_column(model, field)
        self.update_last_modified()
        super().delete(**kwargs)

    def validate(self):
        if self._initial_null and not self.null:
            raise NullFieldChangedError(
                f"Cannot change NULL field '{self.name}' to NOT NULL")

        if self.name in self.get_prohibited_names():
            raise InvalidFieldNameError(
                f'{self.name} is not a valid field name')

    def get_registered_model_field(self):
        latest_model = self.model_schema.get_registered_model()
        if latest_model and self.name:
            try:
                return latest_model._meta.get_field(self.name)
            except FieldDoesNotExist:
                pass

    @classmethod
    def get_prohibited_names(cls):
        # TODO: return prohbited names based on backend
        return cls._PROHIBITED_NAMES

    @classmethod
    def get_data_types(cls):
        return FieldFactory.get_data_types()

    @property
    def db_column(self):
        return slugify(self.name).replace('-', '_')

    def requires_max_length(self):
        return self.data_type in self.__class__._MAX_LENGTH_DATA_TYPES

    def update_last_modified(self):
        self.model_schema.last_modified = timezone.now()

    def get_options(self):
        """
        Get a dictionary of kwargs to be passed to the Django field constructor
        """
        options = {'null': self.null, 'unique': self.unique}
        if self.requires_max_length():
            options[
                'max_length'] = self.max_length or config.default_charfield_max_length(
                )
        return options

    def _get_model_with_field(self):
        model = self.model_schema.as_model()
        try:
            field = model._meta.get_field(self.db_column)
        except FieldDoesNotExist:
            field = None
        return model, field
Exemplo n.º 7
0
 def __init__(self, *args, **kwargs):
     super().__init__(*args, **kwargs)
     self._initial_name = self.name
     self._initial_null = self.null
     self._initial_field = self.get_registered_model_field()
     self._schema_editor = FieldSchemaEditor(self._initial_field)
Exemplo n.º 8
0
class FieldSchema(models.Model):
    _PROHIBITED_NAMES = ("__module__", "_declared")

    name = models.CharField(max_length=63)
    model_schema = models.ForeignKey(ModelSchema, on_delete=models.CASCADE, related_name="fields")
    class_name = models.TextField()
    kwargs = FieldKwargsJSON(default=dict)

    class Meta:
        unique_together = (("name", "model_schema"),)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._initial_name = self.name
        self._initial_null = self.null
        self._initial_field = self.get_registered_model_field()
        self._schema_editor = FieldSchemaEditor(self._initial_field)

    def save(self, **kwargs):
        self.validate()
        super().save(**kwargs)
        self.update_last_modified()
        model, field = self._get_model_with_field()
        self._schema_editor.update_column(model, field)

    def delete(self, **kwargs):
        model, field = self._get_model_with_field()
        self._schema_editor.drop_column(model, field)
        self.update_last_modified()
        super().delete(**kwargs)

    def validate(self):
        if self._initial_null and not self.null:
            raise NullFieldChangedError(f"Cannot change NULL field '{self.name}' to NOT NULL")

        if self.name in self.get_prohibited_names():
            raise InvalidFieldNameError(f"{self.name} is not a valid field name")

    def get_registered_model_field(self):
        latest_model = self.model_schema.get_registered_model()
        if latest_model and self.name:
            try:
                return latest_model._meta.get_field(self.name)
            except FieldDoesNotExist:
                pass

    @classmethod
    def get_prohibited_names(cls):
        # TODO: return prohbited names based on backend
        return cls._PROHIBITED_NAMES

    @property
    def db_column(self):
        return slugify(self.name).replace("-", "_")

    @property
    def null(self):
        return self.kwargs.get("null", False)

    @null.setter
    def null(self, value):
        self.kwargs['null'] = value

    def update_last_modified(self):
        cache.update_last_modified(self.model_schema.initial_model_name)

    def get_options(self):
        return self.kwargs.copy()

    def _get_model_with_field(self):
        model = self.model_schema.as_model()
        try:
            field = model._meta.get_field(self.db_column)
        except FieldDoesNotExist:
            field = None
        return model, field
Exemplo n.º 9
0
 def test_field_is_not_changed(self, initial_model):
     initial_field = initial_model._meta.get_field('integer')
     assert not FieldSchemaEditor(initial_field).has_changed(initial_field)
Exemplo n.º 10
0
 def test_field_is_changed(self, initial_model, changed_field_name_model):
     initial_field = initial_model._meta.get_field('integer')
     changed_field = changed_field_name_model._meta.get_field('changed')
     assert FieldSchemaEditor(initial_field).has_changed(changed_field)