开发者

Django form validation error with incomplete fields but complete instance

开发者 https://www.devze.com 2023-04-11 00:23 出处:网络
I want to be able to do: def update_profile(request, username): user = Profile.objects.get(user__username=username)

I want to be able to do:

def update_profile(request, username):
    user = Profile.objects.get(user__username=username)

    # update subset of profile, eg value_to_company is set in request.POST
    # but user (or an arbitrary number of other attributes) is not
    profile = ProfileForm(request.POST, instance=user)

    if not profile.is_valid():
        print profile.errors  #user is required

The problem that I have with this is that user definitely exists and is part of the instance, and I can't find anything in the docs to suggest that instance data wouldn't get into the bound data. But I also can't find anything that explicitly says that it will.

(The rest of this is justification for why I'm doing things the way I am, and ideas for solutions, you probably don't need to read it.)

If you want to know why I'm going through a form--not essential to the question--it's because I've got something like this:

class Profile(models.Model):
    user = models.ForeignKey(auth.models.User)
    value_to_company = models.IntegerField()

class ValueField(forms.Field):
    def to_python(self, value):
        vals = {'high': 0,
                'mid': 1}
        return vals[value]

class ProfileForm(forms.ModelForm):
    value_to_company = ValueField()

    class Meta:
        model = Profile

That is, I'm doing type api-to-internal-representation-coercion in my forms already and I'd like to continue using that.

I could reimplement the forms.is_valid() loop, just checking for the fields on the form that already exist, something hacky like:

# replaces `if not profile.is_valid()` above:
errors = []
for field in request.POST.iterkeys():
    if field in profile.f开发者_JS百科ields:
        profile.fields[field].to_python()
        if not profile.fields['field'].clean():
            errors.append #something

(I haven't actually looked at the logic internal logic, so I know that's wrong, but you get the idea.)


You likely just need to add exclude = ('user',) to your form. The forms instance mostly determines initial values, if your form includes the user field, but that field is posted with a blank value it will try to blank out the user field, resulting in the error.


I found this solution in django-piston.

It adds additional form method merge_from_initial which you call before you call is_valid and it populates the missing fields from the object given.

I have changed it a bit and am using:

class BaseModelForm(forms.ModelForm):
    """
    Subclass of `forms.ModelForm` which makes sure that the instance values are present in the form
    data, so you don't have to send all old values for the form to actually validate. Django does not
    do this on its own.
    """

    def merge_from_instance(self):
        # Internals
        self.data._mutable = True

        fun = lambda v: v not in self.data.keys()
        for field in filter(fun, self.fields.keys()):
            if field not in self.initial:
                continue
            value = self.initial.get(field)
            if isinstance(self.instance._meta.get_field(field), related.ManyToManyField):
                self.data.setlist(field, value)
            else:
                self.data[field] = value
0

精彩评论

暂无评论...
验证码 换一张
取 消