0

I have a model called Event in my Django project:

from django.db import models
from django.contrib.auth.models import User


class Event(models.Model):
    organizer = models.CharField(blank=False, max_length=200) # TODO
    author = models.ForeignKey(User)

This model also has a form attached:

from django import forms from .models import Event

class EventForm(forms.ModelForm):
    class Meta:
        model = Event
        fields = ['organizer',
                  ]

(there are other fields, but they are irrelevant)

What is the best practice if I want to automatically populate the author field? At the moment, the view that saves the model saves it like so:

def event_created(request):
    form = EventForm(request.POST)
    if form.is_valid():
        obj = form.save(commit=False)
        obj.author = request.user
        obj.save()

This works, but I am worried because it means that when some other view will save this, it will have to jump through the same loop. Is there some way to tell the model itself "when I save you, set user to current user"? The problem is that the model does not know which request is triggering its save, and if I provide the request from the view, that, again, seems like code duplication...

5xum
  • 5,250
  • 8
  • 36
  • 56
  • http://stackoverflow.com/a/862870/3033586 – madzohan Jul 29 '15 at 15:15
  • @madzohan This answer claims that the modelform should save the user, but you still have to send the request to its save method. How is that saving anything? – 5xum Jul 29 '15 at 15:25
  • `form = EventForm(request.POST, request=request); if form.is_valid(): form.save()` ... if you want more clear code - use class based views – madzohan Jul 29 '15 at 15:34

2 Answers2

2

One way would be to pass the request object to EventForm and use this request object to get the user when saving.

You can do that by creating the form instance by EventForm(request.POST, request=request).

class EventForm(forms.ModelForm):

   def __init__(self, *args, **kwargs):
       self.request = kwargs.pop('request', None) # set 'request' if passed as kwarg
       return super(EventForm, self).__init__(*args, **kwargs)

Then in the save() method of the form, you can move the logic of saving author from your event_created view to it.

But for this, you will have to make sure that you are passing request everytime when creating a form instance so that author is set to the request.user.

I would suggest the original method which you are doing as it is neat and clean. You don't have to worry about passing request everytime and override the __init__() method and the save() method of EventForm.

Rahul Gupta
  • 46,769
  • 10
  • 112
  • 126
  • But is that any better than my current solution? It still demands that I repeat code in views, does it not? – 5xum Jul 29 '15 at 15:28
  • Yes there would be some repetition in code but then otherwise you have to make sure that everywhere `request` is being passed. In case you miss passing the `request`, there would be validation error in `save()`. If you can ensure that without fail, then sure you can use the other method posted above. It would be even more clean if you use `FormView` CBV. – Rahul Gupta Jul 29 '15 at 17:12
1

There was a similar question that was answered here.

Basically that model can get created and updated in more places that just a view (manage command and the post save listener). In those cases we will not have a request to update who the user is.

Community
  • 1
  • 1
Eric Bulloch
  • 827
  • 6
  • 10