peewee-validates icon indicating copy to clipboard operation
peewee-validates copied to clipboard

Problems with ManyModelChoiceField validation.

Open LolusKekus opened this issue 8 years ago • 0 comments

Hello! I have model like this:

class TestModel(peewee.Model):
    foo = peewee.ForeignKeyField(ModelOne)
    bar = peewee.ForeignKeyField(ModelTwo)
    class Meta:
        indexes = (
            (("foo", "bar"), True),
        )

And when i use <select multiple> i have a mysql error like this: ERROR 1241 (21000): Operand should contain 1 column(s)

So, i'd made some research and find the problem.

    def perform_index_validation(self, data):
        """
        Validate any unique indexes specified on the model.
        This should happen after all the normal fields have been validated.
        This can add error messages to multiple fields.

        :return: None
        """
        # Build a list of dict containing query values for each unique index.
        index_data = []
        for columns, unique in self.instance._meta.indexes:
            if not unique:
                continue
            index_data.append({col: data.get(col, None) for col in columns})

        # Then query for each unique index to see if the value is unique.
        for index in index_data:
            _query = self.instance.filter(**index)_
            # If we have a primary key, need to exclude the current record from the check.
            if self.pk_field and self.pk_value:
                query = query.where(~(self.pk_field == self.pk_value))
            if query.count():
                err = ValidationError('index', fields=str.join(', ', index.keys()))
                for col in index.keys():
                    self.add_error(col, err)

query = self.instance.filter(**index) generate invalid sql query:

Count(*) 
FROM testmodel AS t1 
INNER JOIN modelone AS t2 ON (t1.foo_id = t2.id) 
INNER JOIN modeltwo AS t3 ON (t1.bar_id = t3.id) 
WHERE ((t1.foo_id = 7) AND (t1.bar_id = (2, 4)));

(t1.bar_id = (2, 4))) - this is a problem sql

I know, this is a peewee orm error, but you can solve this problem on your side like this:

    def perform_index_validation(self, data):
        """
        Validate any unique indexes specified on the model.
        This should happen after all the normal fields have been validated.
        This can add error messages to multiple fields.

        :return: None
        """
        # Build a list of dict containing query values for each unique index.
        index_data = []
        for columns, unique in self.instance._meta.indexes:
            if not unique:
                continue
            index_data.append({col: data.get(col, None) for col in columns})

        # Then query for each unique index to see if the value is unique.
        for index in index_data:
            new_index = {}
            for k, v in index.items():
                if issubclass(type(v), Iterable):
                    k = '%s__in' % k
                new_index[k] = v
            query = self.instance.filter(**new_index)
            # If we have a primary key, need to exclude the current record from the check.
            if self.pk_field and self.pk_value:
                if issubclass(type(self.pk_value), Iterable):
                    query = query.where(~(self.pk_field >> self.pk_value))
                else:
                    query = query.where(~(self.pk_field == self.pk_value))
            if query.count():
                err = ValidationError('index', fields=str.join(', ', index.keys()))
                for col in index.keys():
                    self.add_error(col, err)

p.s. Your product wery handy. Thank you for it!

LolusKekus avatar Aug 30 '17 11:08 LolusKekus