Complex validation

32 views
Skip to first unread message

Lachlan Musicman

unread,
Dec 4, 2013, 11:04:55 PM12/4/13
to django...@googlegroups.com
Hola,

I have an object Part that has a method part_number()

part_number is a function that returns an identifying string based on
a number of different vars on the model.

part_number needs to be unique, but the building of the part_number is
complex enough that it cannot just be done via class Meta:
unique_together

The model's clean():

pn = self.part_number()
all_parts = Part.objects.all()
for part in all_pns:
if pn == part.part_number():
raise ValidationError('Part numbers must be unique.
Part number %s already exists.' % part.part_number())


It's fairly straight forward.

Ideally I would like to make the %s in the error message to an <a>
link for reference value.

Is it possible to use/pass context data like that in a ValidationError message?

eg:

raise ValidationError(mark_safe('Part numbers must be unique. Part
number %s <a href="parts/{{ part.slug }}'>already exists</a>.' %
part.part_number()))


cheers
L.


--
From this perspective it is natural that anarchism be marked by
spontaneity, differentiation, and experimentation that it be marked by
an expressed affinity with chaos, if chaos is understood to be what
lies outside or beyond the dominant game or system. Because of the
resistance to definition and categorisation, the anarchist principle
has been variously interpreted as, rather than an articulated
position, “a moral attitude, an emotional climate, or even a mood”.
This mood hangs in dramatic tension between utopian hope or dystopian
nihilism...
-----
http://zuihitsu.org/godspeed-you-black-emperor-and-the-politics-of-chaos

Lachlan Musicman

unread,
Dec 4, 2013, 11:18:03 PM12/4/13
to django...@googlegroups.com
Actually, as a corollary to my previous question, I can't tell from
the Docs whether the model's validation process (in particular, the
clean() method) is called at save() or called when validating via a
form?

IE, I want the clean() method invoked at save - so that data imported
via fixtures or SQL is also validated. Should I move those validation
fields to the save method?


Cheers
L.

Mike Dewhirst

unread,
Dec 5, 2013, 2:10:14 AM12/5/13
to django...@googlegroups.com
On 5/12/2013 3:18pm, Lachlan Musicman wrote:
> Actually, as a corollary to my previous question, I can't tell from
> the Docs whether the model's validation process (in particular, the
> clean() method) is called at save() or called when validating via a
> form?

clean() isn't called by save() it is called by the form. But you can
call it yourself from anywhere at any time. Especially in unit tests.

It should be ok to override save() and call clean() provided it is not
making any changes which might confuse save(). Raising exceptions or
returning None is probably all you want.


>
> IE, I want the clean() method invoked at save - so that data imported
> via fixtures or SQL is also validated. Should I move those validation
> fields to the save method?

I tend to write little validation methods and call them from clean().
That lets me pick and choose.

Mike

Mike Dewhirst

unread,
Dec 5, 2013, 2:21:32 AM12/5/13
to django...@googlegroups.com
On 5/12/2013 3:04pm, Lachlan Musicman wrote:
> Hola,
>
> I have an object Part that has a method part_number()
>
> part_number is a function that returns an identifying string based on
> a number of different vars on the model.
>
> part_number needs to be unique, but the building of the part_number is
> complex enough that it cannot just be done via class Meta:
> unique_together
>
> The model's clean():
>
> pn = self.part_number()
> all_parts = Part.objects.all()
> for part in all_pns:
> if pn == part.part_number():
> raise ValidationError('Part numbers must be unique.
> Part number %s already exists.' % part.part_number())

What happens if clean() is called for an existing Part?

>
>
> It's fairly straight forward.
>
> Ideally I would like to make the %s in the error message to an <a>
> link for reference value.

IMHO, "ideally" is a deadly whirlpool which sucks your life away without
measurable gain. I reckon you should aim for the most basic/simple/easy
mechanism. Then later on, if users can actually make a decent case for
extra information via a hyperlink you could add the extra feature.

Good luck

Mike

Lachlan Musicman

unread,
Dec 5, 2013, 6:06:35 PM12/5/13
to django...@googlegroups.com
On 5 December 2013 18:21, Mike Dewhirst <mi...@dewhirst.com.au> wrote:
> On 5/12/2013 3:04pm, Lachlan Musicman wrote:
>> The model's clean():
>>
>> pn = self.part_number()
>> all_parts = Part.objects.all()
>> for part in all_pns:
>> if pn == part.part_number():
>> raise ValidationError('Part numbers must be unique.
>> Part number %s already exists.' % part.part_number())
>
>
> What happens if clean() is called for an existing Part?

Stop. Brain hurt.

>
>>
>>
>> It's fairly straight forward.
>>
>> Ideally I would like to make the %s in the error message to an <a>
>> link for reference value.
>
>
> IMHO, "ideally" is a deadly whirlpool which sucks your life away without
> measurable gain. I reckon you should aim for the most basic/simple/easy
> mechanism. Then later on, if users can actually make a decent case for extra
> information via a hyperlink you could add the extra feature.

You are right - thanks for the tip.

Lachlan Musicman

unread,
Dec 5, 2013, 6:14:10 PM12/5/13
to django...@googlegroups.com
On 5 December 2013 18:10, Mike Dewhirst <mi...@dewhirst.com.au> wrote:
> On 5/12/2013 3:18pm, Lachlan Musicman wrote:
>>
>> Actually, as a corollary to my previous question, I can't tell from
>> the Docs whether the model's validation process (in particular, the
>> clean() method) is called at save() or called when validating via a
>> form?
>
>
> clean() isn't called by save() it is called by the form. But you can call it
> yourself from anywhere at any time. Especially in unit tests.
>
> It should be ok to override save() and call clean() provided it is not
> making any changes which might confuse save(). Raising exceptions or
> returning None is probably all you want.

>>
>> IE, I want the clean() method invoked at save - so that data imported
>> via fixtures or SQL is also validated. Should I move those validation
>> fields to the save method?
>
>
> I tend to write little validation methods and call them from clean(). That
> lets me pick and choose.


I think that's the most sensible way to do it, rather than calling
clean() in save().

And regards your Q " What happens if clean() is called for an existing
Part?" I will use if self.pk is not None



if self.pk is not None:
pn = self.part_number()
all_parts = Part.objects.all()
for part in all_parts:
if pn == part.part_number():
raise ValidationError('Part numbers must be unique.
Part number %s already exists.' % part.part_number())



Cheers
Reply all
Reply to author
Forward
0 new messages