4

As part of a form validation in Django, I want to check when a user last made a post.

I've had a look at this, and this question on stackoverflow, which appear to address this issue, and initially used the accepted answer here. Essentially the process at the moment has been to add the request.user object during the

def form_valid(self, form):

method of the CreateView subclass. However, this doesn't allow the user variable to be used during form validation.

Since I want to access the user variable during validation, as the check on time since last post is logically validation, I need the user variable injected to the form earlier.

I've tried altering the get_initial() method:

def get_initial(self):
    initial = super(ArticleCreateView, self).get_initial()
    initial['user'] = self.request.user
    return initial

This successfully sets the ['user'] key in the initial dictionary, but this never makes it through the cleaning process, which deals only with the stuff in the ['data'] dictionary, and removes anything in initial. I've deliberately excluded user from the form display, but this appears to also remove it from the cleaning process and validation.

Is the correct way to do this to override the init() method of the Form, and the get_initial() method of the view, putting 'user' into initial, and then the form pulling the extra information from initial into the form at init()?

I'm looking to pass the request.user to the form, and then I can access it within the form-wide clean() method to do the additional checks, which amount to validation.

def clean(self):
    super(ArticleForm, self).clean()
    **check whether user has posted recently, if so, raise ValidationError**
    return self.cleaned_data

J

Community
  • 1
  • 1
jvc26
  • 6,363
  • 6
  • 46
  • 75
  • does the form have a reference to the user? if so you can access that via `self.cleaned_data['user']` – second Nov 13 '11 at 16:18
  • The Model the form is based off has a field for user, but this is excluded from the form as the user should not be able to select the user, it should be set to them automatically. At present I've been injecting the user variable in at the form_valid() part of the CreateView subclass. Is it possible to edit the **kwargs which are passed to the validation step? (i.e. via get_form_kwargs()?) – jvc26 Nov 13 '11 at 16:31

3 Answers3

5

You can override get_form_kwargs method of the CreateView (ArticleCreateView in your case) to pass user to the form.

def get_form_kwargs(self):
    kwargs = super(ArticleCreateView, self).get_form_kwargs()
    kwargs['user'] = self.request.user
    return kwargs

Override your form's init method

...
def __init__(self, *args, **kwargs):
    self.user = kwargs.pop("user")

Now you can use self.user in the clean method.

nmb.ten
  • 2,158
  • 1
  • 20
  • 18
4

The way I've solved this at the moment is to keep validation within the form, and the rest of the business logic in the view. Consequently, I've done the following:

In the view:

def get_initial(self):
    initial = super(MyCreateView, self).get_initial()
    initial['user'] = self.request.user
    return initial

In the form:

def __init__(self, *args, **kwargs):
    self.user = kwargs['initial']['user']
    super(MyObjectForm, self).__init__(self, *args, **kwargs)

def clean(self):
    # Clean all the submitted data
    super(MyObjectForm, self).clean()

    # Validate that the user submitted > n time ago
    profile = self.user.get_profile()

    if datetime.now() - profile.lastpost < timedelta(hours=1)
        raise forms.ValidationError("Need to wait longer than n=1 hours")
    else:
        self.cleaned_data['user'] = self.user

    return self.cleaned_data

Which seems to work - are there any flaws I haven't seen with this solution?

jvc26
  • 6,363
  • 6
  • 46
  • 75
0

i would probably override the form init method to take a user argument, and set this somewhere on the form.

class MyForm()
    def __init__(self, user, *args, **kwargs):
        super(MyForm, self)__init__(*args, **kwargs)
        self.user = user


    def clean_field(...)
        if self.user ...

etc

second
  • 28,029
  • 7
  • 75
  • 76
  • Thanks for the suggestion - when for something slightly different in the end. I wanted to avoid setting the user on the form if possible, so went for http://stackoverflow.com/questions/8112859/django-how-do-i-add-data-to-a-modelform-subclass-before-validation/8113226#8113226 which allowed me to put the validation logic within the Form, and to pass the user object into the form's namespace. Not sure whether there are inherent problems with my solution which I've missed - input from someone more experienced would be appreciated! – jvc26 Nov 13 '11 at 17:26