Ok, problem solved:

``Model.full_clean()``

    def full_clean(self, exclude=None, validate_unique=True):
        """
        Calls clean_fields, clean, and validate_unique, on the model,
        and raises a ``ValidationError`` for any errors that occured.
        """
        errors = {}
        if exclude is None:
            exclude = []

        try:
            self.clean_fields(exclude=exclude)
        except ValidationError, e:
            errors = e.update_error_dict(errors)

        # Form.clean() is run even if other validation fails, so do
the
        # same with Model.clean() for consistency.
        try:
            self.clean()
        except ValidationError, e:
            errors = e.update_error_dict(errors)

        # Run unique checks, but only for fields that passed
validation.
        for name in errors.keys():
            if name != NON_FIELD_ERRORS and name not in exclude:
                exclude.append(name)

        if validate_unique:
            try:
                self.validate_unique(exclude=exclude)
            except ValidationError, e:
                errors = e.update_error_dict(errors)

        if errors:
            raise ValidationError(errors)


``ModelForm._post_clean()``

    def _post_clean(self):
        exclude = self._get_validation_exclusions()
        opts = self._meta

        # Update the model instance with self.cleaned_data.
        self.instance = construct_instance(self, self.instance,
opts.fields, opts.exclude)

        # Clean the model instance and catch any and all fields.
        try:
            self.instance.full_clean(exclude=exclude,
validate_unique=self._validate_unique)
        except ValidationError, e:
            # Add the field errors in and NON_FIELD_ERRORS here (I
don't know the ins and outs of how `ValidationError` works).


This single change allows for so much more to be done in the model
layer instead of repetitive views. It allows you to actually do what
the docs say and use `Model.clean()` to do necessary additions to an
instance before it's saving, and without regards to data integrity,
because **this allows for you to wrap `Model.full_clean()` in a
transaction** and trust that it will always be used. I'm no RoR fan,
but Rails' policy of keeping data related logic inside of models is a
very wise one.



On Apr 19, 9:53 am, James Bennett <ubernost...@gmail.com> wrote:
> On Mon, Apr 19, 2010 at 10:16 AM, Richard Laager <rlaa...@wiktel.com> wrote:
> > On Mon, 2010-04-19 at 07:55 -0700, orokusaki wrote:
> >> With all respect, you still haven't addressed my main concern: You
> >> told me that it was because of backward compatibility that this simple
> >> change couldn't be put in the trunk. It is backward compatible. If I'm
> >> wrong, it would suffice to have a simple explanation of what it
> >> breaks.
>
> > I'd like to second this question. orokusaki suggested a couple of things
> > in ticket #13100, but I'm seconding specifically this comment:
> >http://code.djangoproject.com/ticket/13100#comment:8
>
> The difference between how ModelForm works and how Model works is
> that, if you're overriding clean() on a ModelForm subclass, you don't
> automatically get uniqueness validation -- you have to call up to the
> parent clean(), or manually apply the uniqueness validation in your
> own clean().
>
> In Django 1.0 and 1.1, this is documented behavior:
>
> http://docs.djangoproject.com/en/1.0/topics/forms/modelforms/#overrid...http://docs.djangoproject.com/en/1.1/topics/forms/modelforms/#overrid...
>
> As such, changing ModelForm to always behave identically to, or to
> always call, Model.full_clean() would have to change documented
> behavior. We can't do that in the 1.1 -> 1.2 jump, and for future
> consideration trying to force them to behave identically is probably
> unworkable (better would be to come up with API that lets you
> explicitly control uniqueness validation).
>
> This is why that ticket has been changed to a documentation issue: the
> wording of the documentation with respect to ModelForm and model
> validation is pretty bad right now, and needs to be cleaned up for the
> 1.2 release. And this is why for a month now multiple committers have
> been saying that the proposed code changes are backwards-incompatible:
> ModelForm.clean() and Model.full_clean() *cannot* be made to function
> identically right now without changing documented behavior.
>
> And for the record, my own frustration on that ticket boils down to a
> simple thing: Joseph pointed out there was a backwards-compatibility
> issue, and opted to salvage the most workable solution by changing it
> to a documentation issue. The reporter reverted that. Russell chimed
> in and pointed out that Joseph was probably right and set the ticket
> back to a documentation issue. At that point our intrepid bug reporter
> could've gotten all the discussion he wanted by paying attention to
> something he'd been told multiple times, and which is clearly pointed
> out in the contributing docs we encourage everyone to read as they
> dive in: if you don't like the decision a committer made on a ticket,
> start a thread here on the dev list to talk about it. Instead he
> opened duplicate tickets, ranted in the tracker, insulted people, and
> generally turned the whole thing into a big radioactive mess that
> nobody wanted to touch with a ten-foot pole.
>
> And with that I'm going to bow out of this thread; Jacob's already
> posted a separate message to collect concrete suggestions, and that's
> the discussion I plan to pay attention to, since I think this one's
> pretty much boiled down to the same people endlessly saying the same
> things at each other and expecting different results.
>
> --
> "Bureaucrat Conrad, you are technically correct -- the best kind of correct."
>
> --
> You received this message because you are subscribed to the Google Groups 
> "Django developers" group.
> To post to this group, send email to django-develop...@googlegroups.com.
> To unsubscribe from this group, send email to 
> django-developers+unsubscr...@googlegroups.com.
> For more options, visit this group 
> athttp://groups.google.com/group/django-developers?hl=en.

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers" group.
To post to this group, send email to django-develop...@googlegroups.com.
To unsubscribe from this group, send email to 
django-developers+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-developers?hl=en.

Reply via email to