5

In my application I have a CreateView that must initialize some fields of the model with a default value, different from the default defined inside the model.

I do not want the user to edit the value, thus I put the field in the exclude list

class AForm(ModelForm):
    class Meta:
        model = AModel
        exclude = ['a_field']

class AView(CreateView):
    form_class = AForm

The question is: where do I set the value of a_field?

I tried to define clean methods inside AForm, like thus

class AForm(ModelForm):
    [...]
    def clean(self):
        d = super(AForm, self).clean()
        d['a_field'] = 10
        return d

however a_field is set to whatever its default value defined in the model is, rather than 10. I also tried defining clean_a_field, but that is simply not executed.

If I remove a_field from the exclude list, then the clean and clean_a_field will work, but the form won't validate unless I render some <input name="a_field"> inside the template, which is not optimal.

4
  • Did you define clean_a_field or just clean? Commented May 18, 2014 at 5:10
  • I tried both. They are both ignored. Commented May 18, 2014 at 10:36
  • Really? The form's clean method should always be called. An alternative is to override the form's save method. Commented May 18, 2014 at 12:21
  • Tried removing the fields from exclude, making them hidden(or not required and not displaying in the front end), then setting the default value in the clean method Commented May 18, 2014 at 17:55

4 Answers 4

4

I managed to solve the issue in a way that makes me satisfied, although I'm still not 100% happy with the code.

a_field is a required (by the model) field, thus it is necessary to render an <input name="a_field"> inside the template. The trick was to make a_field non-required:

class AForm(ModelForm):
    a_field = Field(required=False, 
                    widget=forms.HiddenInput)
    class Meta:
        model = AModel

    def clean_a_field(self):
        return 10

This way I can avoid rendering the field in my template, and the form will still validate. And even if the form is rendered with {{ form.as_p }}, widget=forms.HiddenInput saves my day.

Sign up to request clarification or add additional context in comments.

2 Comments

where did you import Field from?
django.forms.Field
4

Exclude the field from the form, then in the view you can set the value before you save the form:

form = AForm(request.POST)
if form.is_valid():
    new_record = form.save(commit=False)
    new_record.a_field = 10
    new_record.save()

You also might want to avoid the exclude list and specify which fields you'd like to include with the fields attr of the form definition. See the first paragraph here in the docs.

1 Comment

This is a nice idea, but in my opinion it does not blend cleanly with CreateView. The form is saved by CreateView.form_valid(); overwriting this method without calling super doesn't look very future proof to me.
0

You set a default value in the model. From the official document,
a_field = models.CharField(max_length=7, default=''), for example

5 Comments

This does not prevent the user from modifying the value.
Are you using modelForm to do this? If then, you need to add attribute disabled = "disabled" in the input field. Google yielded this: stackoverflow.com/questions/19489699/…
Yes, I am using ModelForm. Disabling the field in HTML does not prevent the user from editing it if she really wants to (or if she has an old browser not recognizing the disabled attribute). Besides the field is still going to show in the form, which is not what I want: I want to choose the value for the user. Using HiddenIntput does not help either: the user can still edit if he wants to. Combining with clean or clean_a_field would work, but is against DRY, and I can't believe there is no simpler way.
Gotcha ! choosing the value for the user is backend stuff. For front-end, can't you render the value of that field as text so it is uneditable?
Not very different from using a hidden field, and not what I want.
0

I have a way to Face this situation. Follow the following process:

  1. Remove 'a_field' from the excludes in AForm.

  2. Do not expose 'a_field' in HTML template. i.e. Don't give the user option to change the value via Form in Template. This would ensure that normal user's wont modify the value.

  3. To prevent completely, over-ride get_form_kwargs in the View. This would provide or over-ride your desired value to 'a_field' and save that

e.g.

class AView(CreateView):
    form_class = AForm

    def get_form_kwargs(self):
        kwargs = super(AView, self).get_form_kwargs()
        if self.request.method in {'POST', 'PUT'}:
            # Change post data to over-ride or provide value of 'a_field'
            data = self.request.POST.copy()
            data.update({
                'a_field': 'value'
            })
            kwargs['data'] = data
        return kwargs

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.