Set field value in Django Form clean() method, if this field not passed in constructor

11,901

Solution 1

The previous answer would work, but I like encapsulating all the form's internal operations like what to show and what not, within the form. I know you mentioned you don't want to send a field value to the constructor, but if you don't mind sending the user, your solution would work. i.e., your constructor:

def __init__(self, user):
    self.user = user
    super(BaseForm, self).__init__()

then in your clean, you just change the user to self.user. There is another added benefit to this. Say tomorrow you want to assign more fields based on your user, you don't need to add anything to the views, you can simply add it to the form.

EDIT: When you add a field to exclude, it is not available in the cleaned data. Instead, set its widget as hidden.

active = forms.BooleanField(widget=forms.HiddenInput)

EDIT 2: If you really don't want the field in the form In this case, instead of overriding the clean, why don't you override the save?

def save (self):
    super(BaseForm, self).save()
    if user.is_admin():
        self.instance.active=True
    super(BaseForm, self).save()

Solution 2

Don't do this in the form's clean() method, do this in the view.

def your_view(request):
    if request.method == 'POST':
        form = MessageForm(data=request.POST)
        if form.is_valid():
            new_message = form.save(commit=False)
            if user.is_admin():
                new_message.active = True

However, if you also want to handle the case where your user is not admin using the same form, you can look at incorporating similar logic in the form's init() instead of the view, probably by passing info about the user from the view to the form's init()

Solution 3

Use this:

def message_form_factory(user):
    class MessageForm(forms.ModelForm):
        def clean(self):
            # check if user is blocked
            if user.is_admin():
                self.cleaned_data['active'] = True
            return self.cleaned_data
    return MessageForm

And in your view use:

form = message_form_factory(request.user)()
form = message_form_factory(request.user)(request.POST)
Share:
11,901

Related videos on Youtube

Admin
Author by

Admin

Updated on June 04, 2022

Comments

  • Admin
    Admin almost 2 years

    I need set field value, not passed to Django Form constructor.

    I have model and form like this:

    class Message(models.Model):
        created     = models.DateTimeField()
        text        = models.CharField(max_length=200, blank=True, null=True)
        active      = models.BooleanField(default=False)
    
    class MessageForm(forms.ModelForm):
        class Meta:
            model   = Message
            exclude = ('created', 'active')
    
        def clean(self):
            # check if user is blocked
            if user.is_admin():
                self.cleaned_data['active'] = True
            return self.cleaned_data
    

    Expected: if current user is admin - I need automatically set message as active. User should not pass this parameter by form.

    Actual: I see that saved message always have flag "False" (I can delete condition and in this case I also see that message is not active).

    Please help me understand, how can I do set this "active" flag in clean() method.

    • Elf Sternberg
      Elf Sternberg over 13 years
      How and where does the "user" variable get set?

Related