user1563285
user1563285

Reputation:

Django - checking for model field format


I have defined a simple model in Django:

class Student(models.Model):
    s_name = models.CharField(max_length=32)
    s_gpa = models.FloatField(min=0.0, max=5.0, default=5.0)
    s_year = models.IntegerField(min=1, max=10, default=1)
    s_registered = models.DateTimeField(auto_now_add=True)

    def __unicode__(self):
        return self.username

    def modify(self, **kwargs):
        if valid(self, kwargs):
            for k,v in kwargs.iteritems():
                setattr(self, k, v)
            self.save()

def valid(s, kwargs):
    # For all k,v pairs in kwargs
    # (1) Checks if k is one of the attributes of s. Returns False if fails.
    # (2) Checks if v fits the format defined for attribute k of s.
    # Returns False if fails.
    # Returns True if reaches this point.

I'm writing the function valid, which I'd like to execute the commands detailed in the comments.
For (1), I use

if k not in s.__dict__: return False

I would need some help with (2).
That is, how can I check if a value fits the format defined for an attribute (Django model field)?

For instance: valid(s_name=True) and valid(s_name=33*'a') should both return False.

Note: I'm trying to solve this validation without using Forms.

Upvotes: 0

Views: 788

Answers (2)

Aidan Ewen
Aidan Ewen

Reputation: 13328

Both your valid and modify functions should probably be replaced with a clean method.

Have a look at the docs on model validation

UPDATE 1

You could probably drop the valid method altogether and simply call self.clean_feilds() instead. That will validate the fields -

def modify(self, **kwargs):
    try:
        self.clean_fields()
        for k,v in kwargs.iteritems():
            setattr(self, k, v)
        self.save()
    except:
        pass

UPDATE 2

It sounds from your comments that you don't need to call any validation yourself at all. Just call save and then catch the ValidationError thrown if your changes are invalid.

def modify(self, **kwargs):
    try:
        for k,v in kwargs.iteritems():
            setattr(self, k, v)
        self.save()
    except ValidationError:
        #... do something?

It's worth noting that many python programmers prefer the try / except pattern to if valid / then. It's known as the 'better to ask forgiveness than permission' principle (amongst other things it provides protection against race conditions - probably not relevant in this case)

Upvotes: 1

Cole
Cole

Reputation: 2509

Use s or self as needed.

def valid(self, kwargs):
    for k, v in kwargs:
        old_v = self.__dict__[k]
        self.__dict__[k] = v
        try:
            self.save()
            self.__dict__[k] = old_v
            self.save()
        except:
            return False

        return True

There is likely a more direct way to perform your test than an actual 'self.save()' failure, but its a good place to begin.

Alternatively:

field_list = ['s_name', 's_gpa', 's_year', 's_registered']
def valid(self, kwargs):
    for k, v in kwargs:
        exclude_list = [f for f in field_list if f != k]
        try:
            self.clean_fields(exclude=exclude_list)
        except ValidationError:
            return False

        return True

With list comprehension, eliminate the exclude_list line and change the self.clean_fields line to:

self.clean_fields(exclude=[f for f in field_list if f != k])

Upvotes: 0

Related Questions