Question

I need to add a field validator through an abstract class.

The code I'm working with supposes that every class inheriting from this abstract class has a field name, but this field itself isn't defined in the abstract class unfortunately.

So I tried the following, but I'm not sure what is the good way of finding the field in self._meta.fields, since this is a list..??

class AbsClass(models.Model):
    class Meta:
        abstract = True
    def __init__(self, *args, **kw):
        super(AbsClass, self).__init__(*args, **kw)
        name_field = [f for f in self._meta.fields if f.name == 'name'][0]  # Is there another way?
        name_field.validators.append(my_validator)
Était-ce utile?

La solution

You need Options.get_field:

...
name_field = self._meta.get_field('name')
name_field.validators.append(my_validator)
...

Your approach, however, doesn't seem like a good idea: you model's field instances are shared between all instances of your model (their references are stored in a class attribute, not in instance attributes). This means that every time you instantiate an object of your model, you'll be adding another copy of my_validator to the field's validators, because you're adding it to the same field instance.

You could implement a metaclass for your abstract base class and add the validator at compile time instead of tampering with field instances at runtime, something along the lines of this (not tested):

from django.utils.six import with_metaclass
from django.db.models.base import ModelBase

# inherit from Django's model metaclass
class AbsClassMeta(ModelBase):

    def __new__(cls, name, bases, attrs):
        if 'name' in attrs:
            attrs['name'].validators.append(my_validator)
        elif name != 'AbsClass':
            # is it an error to not have a "name" field in your subclasses?
            # handle situation appropriately
        return super(AbsClassMeta, cls).__new__(cls, name, bases, attrs)

class AbsClass(with_metaclass(AbsClassMeta, models.Model)):
    ...

Note that your AbsClass class itself will also be created using this metaclass. If you decide to throw an exception in AbsClassMeta.__new__ if the class doesn't have a name field, you need to take this into account, since your AbsClass class doesn't have a name field.

Autres conseils

In Django 2.x

instead of

name_field = self._meta.get_field('name')
name_field.validators.append(my_validator)

you can do:

name_field = self.fields['name']
name_field.validators.append(my_validator)
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top