Django, adding excluded properties to the submitted modelform
Asked Answered
T

4

13

I've a modelform and I excluded two fields, the create_date and the created_by fields. Now I get the "Not Null" error when using the save() method because the created_by is empty.

I've tried to add the user id to the form before the save() method like this: form.cleaned_data['created_by'] = 1 and form.cleaned_data['created_by_id'] = 1. But none of this works.

Can someone explain to me how I can 'add' additional stuff to the submitted modelform so that it will save?

class Location(models.Model):
    name = models.CharField(max_length = 100)
    created_by = models.ForeignKey(User)
    create_date = models.DateTimeField(auto_now=True)

class LocationForm(forms.ModelForm):
    class Meta:
        model = Location
        exclude = ('created_by', 'create_date', )
Taxidermy answered 29/4, 2011 at 12:11 Comment(0)
A
19

Since you have excluded the fields created_by and create_date in your form, trying to assign them through form.cleaned_data does not make any sense.

Here is what you can do:

If you have a view, you can simply use form.save(commit=False) and then set the value of created_by

def my_view(request):
    if request.method == "POST":
        form = LocationForm(request.POST)
        if form.is_valid():
            obj = form.save(commit=False)
            obj.created_by = request.user
            obj.save()
        ...
        ...

`

If you are using the Admin, you can override the save_model() method to get the desired result.

class LocationAdmin(admin.ModelAdmin):
    def save_model(self, request, obj, form, change):
        obj.created_by = request.user
        obj.save()
Andesine answered 29/4, 2011 at 12:34 Comment(3)
Seriously, the Pony would be proud.Frerichs
The above was not working for me. In my ModelForm Meta, I was specifying the fields to include, instead of exclude. Turned out the problem was I was using the class variable "include", when I should have been using "fields". Thus the fields I wanted to exclude were being included and the form would not validate.Planck
In case the aforementioned approaches don't work, you can use another approach: do not exclude the field you want to hide and overwrite it with a custom hidden widget as suggested here: https://mcmap.net/q/904434/-how-to-exclude-django-form-field-from-render-but-still-keep-it-for-validationCommunicable
B
6

Pass a user as a parameter to form constructor, then use it to set created_by field of a model instance:

def add_location(request):
    ...
    form = LocationForm(user=request.user)
    ...

class LocationForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        user = kwargs.pop('user')
        super(forms.ModelForm, self).__init__(*args, **kwargs)
        self.instance.created_by = user
Brabant answered 29/4, 2011 at 12:26 Comment(0)
P
2

The correct solution is to pass an instance of the object with pre-filled fields to the model form's constructor. That way the fields will be populated at validation time. Assigning values after form.save() may result in validation errors if fields are required.

LocationForm(request.POST or None, instance=Location(
    created_by=request.user,
    create_date=datetime.now(),
))

Notice that instance is an unsaved object, so the id will not be assigned until form saves it.

Parrotfish answered 16/6, 2016 at 13:16 Comment(1)
I personally feel this is a better approachSiliceous
T
0

One way to do this is by using form.save(commit=False) (doc)

That will return an object instance of the model class without committing it to the database.

So, your processing might look something like this:

form = some_form(request.POST)
location = form.save(commit=False)
user = User(pk=1)
location.created_by = user
location.create_date = datetime.now()
location.save()
Truelove answered 29/4, 2011 at 12:27 Comment(2)
note that you also have to make a call to form's save_m2m() methodBrabant
True, if there are many-to-many relations attached to the model.Truelove

© 2022 - 2024 — McMap. All rights reserved.