List Info

Thread: Enforcing model representation invariants




Enforcing model representation invariants
country flaguser name
United States
2007-04-16 21:42:51
I have a model with two DateTimeFields, named start and end.
 As Python
datetime objects, I'd like to ensure that (start < end)
for all valid
instances of this model.  What's the right way to enforce
this
invariant?

I tried making a custom Validator object and adding it to
start.validator_list, and then trying to enter an invalid
pair of
datetimes in the admin interface, but the problem seems to
be that the
actual representation in the all_data parameter is divided
between
"start_date" and "start_time" (and
"end_date" and "end_time").  These
are simply the form element names, and the all_data
dictionary contains
the raw strings inputted from the form.  

Two reasons why I don't like this:
     1. I really don't think that this is the right place to
be putting
        this validator, as I want the normal DateTimeField
validators to
        run too, and I don't want to have to duplicate their
work.  (I
        even appended mine to the end of validator_list, but
it seems to
        get caught anyway.)
     2. I also don't want to have to be cleaning up the
user's mess with
        strings and just want to be operating on two
(Python) datetime
        objects.

My "big stick" solution is just to override the
save() method of the
model, and to have it swap the start and end fields.  I'm
sure this
approach can be made to work (neglecting the start==end
case), but
wanted to see in general if there was a more general way to
enforce
model invariants, particularly if it's something where real
user
interaction is needed to correct it.

Best,
Mike



--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the
Google Groups "Django users" group.
To post to this group, send email to django-usersgooglegroups.com
To unsubscribe from this group, send email to
django-users-unsubscribegooglegroups.com
For more options, visit this group at htt
p://groups.google.com/group/django-users?hl=en
-~----------~----~----~----~------~----~------~--~---


Re: Enforcing model representation invariants
country flaguser name
Australia
2007-04-16 22:06:27
Hi Michael,

On Mon, 2007-04-16 at 22:42 -0400, Michael F. Robbins
wrote:
> I have a model with two DateTimeFields, named start and
end.  As Python
> datetime objects, I'd like to ensure that (start <
end) for all valid
> instances of this model.  What's the right way to
enforce this
> invariant?
> 
> I tried making a custom Validator object and adding it
to
> start.validator_list, and then trying to enter an
invalid pair of
> datetimes in the admin interface, but the problem seems
to be that the
> actual representation in the all_data parameter is
divided between
> "start_date" and "start_time" (and
"end_date" and "end_time").  These
> are simply the form element names, and the all_data
dictionary contains
> the raw strings inputted from the form.  
> 
> Two reasons why I don't like this:
>      1. I really don't think that this is the right
place to be putting
>         this validator, as I want the normal
DateTimeField validators to
>         run too, and I don't want to have to duplicate
their work.  (I
>         even appended mine to the end of
validator_list, but it seems to
>         get caught anyway.)
>      2. I also don't want to have to be cleaning up the
user's mess with
>         strings and just want to be operating on two
(Python) datetime
>         objects.

The "problem" here is that validators run before
the data input is
converted to Python objects. This is partially so that a
validator has a
chance to detect that the conversion to Python cannot
possibly work.

Something we are wanting to add in the future is model-aware
validation.
This isn't an amazingly well specified concept (aside from
giving that
portion of the validation process access to the current
model instance,
which you cannot easily do with validators), but one thing
it might be
able to do is also enforce constraint-based requirements
like this. We
have quite a lot of other things going on at the moment, so
right now
isn't the time to be starting a developers discussion about
model-aware
validation, but it's definitely on my list (and a few other
developers',
I suspect) for talking about and completing before 1.0, if
we possibly
can.

> My "big stick" solution is just to override
the save() method of the
> model, and to have it swap the start and end fields.

A conceptual problem with this approach is that it's doing
validation in
the wrong place. Validation and saving are intentionally
separated in
Django. The idea is that if you have any validation failure,
you can go
back to the data supplier and get more information. Saving
should
*never* raise a validation problem. We cannot avoid errors
entirely,
because database integrity errors may be thrown (another
process,
completely unrelated to Django may have put data in the
database that
caused the problem before we saved), however, in most cases,
saving is a
"safe" operation.

So, the short summary answer would be: at the moment, you
have to mess
around with the string versions or else "silently"
fix the errors in
save(). We are aware of this limitation, though, and it is
something we
want to fix.

Regards,
Malcolm


>   I'm sure this
> approach can be made to work (neglecting the start==end
case), but
> wanted to see in general if there was a more general
way to enforce
> model invariants, particularly if it's something where
real user
> interaction is needed to correct it.
> 
> Best,
> Mike
> 
> 
> 
> > 
> 


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the
Google Groups "Django users" group.
To post to this group, send email to django-usersgooglegroups.com
To unsubscribe from this group, send email to
django-users-unsubscribegooglegroups.com
For more options, visit this group at htt
p://groups.google.com/group/django-users?hl=en
-~----------~----~----~----~------~----~------~--~---


Re: Enforcing model representation invariants
country flaguser name
United States
2007-04-17 11:09:17


On Apr 17, 4:06 am, Malcolm Tredinnick <malc...pointy-stick.com>
wrote:
> > My "big stick" solution is just to
override the save() method of the
> > model, and to have it swap the start and end
fields.
>
> A conceptual problem with this approach is that it's
doing validation in
> the wrong place. Validation and saving are
intentionally separated in
> Django. The idea is that if you have any validation
failure, you can go
> back to the data supplier and get more information.
Saving should
> *never* raise a validation problem. We cannot avoid
errors entirely,
> because database integrity errors may be thrown
(another process,
> completely unrelated to Django may have put data in the
database that
> caused the problem before we saved), however, in most
cases, saving is a
> "safe" operation.

Malcolm is right when he's talking about validation of
user-entered
data. However, invariants are also used to catch programming
errors;
it's certainly possible to have buggy business logic code
which causes
invariant checks to fail. An alternative to overriding the
save()
method is to hook the pre_save event and call a model-class
invariant
method to check if, from the model point of view, the model
instance
is valid. (Note that the model point of view can be stricter
and also
more complex than database constraints can easily capture.)
If the
invariant fails, an exception can be thrown, and caught in
the view to
display an appropriate user-friendly message.

Just my 2 cents,


Vinay Sajip


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the
Google Groups "Django users" group.
To post to this group, send email to django-usersgooglegroups.com
To unsubscribe from this group, send email to
django-users-unsubscribegooglegroups.com
For more options, visit this group at htt
p://groups.google.com/group/django-users?hl=en
-~----------~----~----~----~------~----~------~--~---


Re: Enforcing model representation invariants
country flaguser name
United States
2007-04-18 01:11:51
On Tue, 2007-04-17 at 09:09 -0700, Vinay Sajip wrote:
> Malcolm is right when he's talking about validation of
user-entered
> data. However, invariants are also used to catch
programming errors;
> it's certainly possible to have buggy business logic
code which causes
> invariant checks to fail. An alternative to overriding
the save()
> method is to hook the pre_save event and call a
model-class invariant
> method to check if, from the model point of view, the
model instance
> is valid. (Note that the model point of view can be
stricter and also
> more complex than database constraints can easily
capture.) If the
> invariant fails, an exception can be thrown, and caught
in the view to
> display an appropriate user-friendly message.

Vinay,

Thanks very much.  I was browsing through the Validator
code, but wasn't
aware of the pre_save hook.  That sounds like the right
place to put
these kinds of checks.  

I've always been taught to design with class invariants
explicitly
defined and checked (when not detrimental to performance). 
Definitely a
practice I'd recommend, and putting it in a centralized
place like this
(rather than in every view that might touch the object) is
consistent
with the DRY principle.

Mike


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the
Google Groups "Django users" group.
To post to this group, send email to django-usersgooglegroups.com
To unsubscribe from this group, send email to
django-users-unsubscribegooglegroups.com
For more options, visit this group at htt
p://groups.google.com/group/django-users?hl=en
-~----------~----~----~----~------~----~------~--~---


[1-4]

about | contact  Other archives ( Real Estate discussion Medical topics )