Using request.user with Django ModelForm

I'm having a problem with logged users and a Django ModelForm. I have a class named _Animal_ that has a ForeignKey to User and some data related to the animal like age, race, and so on.

A user can add Animals to the db and I have to track the author of each animal, so I need to add the request.user that is logged when the user creates an animal instance.

models.py

class Animal(models.Model):
    name = models.CharField(max_length=300)
    age = models.PositiveSmallIntegerField()
    race = models.ForeignKey(Race)
    ...
    publisher = models.ForeignKey(User)
    def __unicode__(self):
        return self.name

class AnimalForm(ModelForm):
    class Meta:
        model = Animal

The main goal is hide the publisher field in the form, and submit the logged user when hitting save button.

I can catch the current user in the view using initial, but what I also want is not display the field.

views.py

@login_required
def new_animal(request):
    if request.method == "POST":
        form = AnimalForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect('/')
        else:
            variables = RequestContext(request, {'form': form})
            return render_to_response('web/animal_form.html', variables)
    else:
        form = AnimalForm(initial={'publisher': request.user})
    variables = RequestContext(request, {'form': form})
    return render_to_response('web/animal_form.html', variables)

You just need to exclude it from the form, then set it in the view.

class AnimalForm(ModelForm):
    class Meta:
        model = Animal
        exclude = ('publisher',)

... and in the view:

    form = AnimalForm(request.POST)
    if form.is_valid():
        animal = form.save(commit=False)
        animal.publisher = request.user
        animal.save()

(Note also that the first else clause - the lines immediately following the redirect - is unnecessary. If you leave it out, execution will fall through to the two lines at the end of the view, which are identical.)


Another way (slightly shorter):
You need to exclude the field as well:

class AnimalForm(ModelForm):
    class Meta:
        model = Animal
        exclude = ('publisher',)

then in the view:

animal = Animal(publisher=request.user)  
form = AnimalForm(request.POST, instance=animal)
if form.is_valid():
     animal.save()

I would add it directly to the form:

class AnimalForm(ModelForm):
    class Meta:
        model = Animal
        exclude = ('publisher',)

    def save(self, commit=True):
        self.instance.publisher = self.request.user
        return super().save(commit=commit)

This is in my opinion the cleanest version and you may use the form in different views.