Django set creator/owner for the object when created
Asked Answered
C

3

8

Let's say I have a simple model:

class Contact(models.Model):
    owner = models.ForeignKey(User, editable=False)
    first_name = models.CharField(max_length=255,)
    last_name = models.CharField(max_length=255,)
    email = models.EmailField()

I would like to set owner (request.user, logged in user) for the object automatically when it is created. I've searched a lot of different options but most of them are related to how you do it in admin side and other ones just don't work for me. I tried this for example http://blog.jvc26.org/2011/07/09/django-automatically-populate-request-user and then I've tried many ways to override save method or some kind of pre_save signal stuff. Nothing seems to do the trick, I just get an error

IntegrityError at /new
null value in column "owner_id" violates not-null constraint

What is the right way to do that? I know that this is simple think to do but I just can't find the way to do it.

...EDIT... My create view looks like this:

class CreateContactView(LoginRequiredMixin, ContactOwnerMixin, CreateWithInlinesView):
    model = models.Contact
    template_name = 'contacts/edit_contact.html'
    form_class = forms.ContactForm
    inlines = [forms.ContactAddressFormSet]

    def form_valid(self, form):
        obj = form.save(commit=False)
        obj.owner = self.request.user
        obj.save()
        return HttpResponseRedirect(self.get_success_url())

    def get_success_url(self):
        return reverse('contacts-list')

    def get_context_data(self, **kwargs):
        context = super(CreateContactView, self).get_context_data(**kwargs)
        context['action'] = reverse('contacts-new')
        return context

That is just one way I tried to solve that problem so far. I found that solution from http://blog.jvc26.org/2011/07/09/django-automatically-populate-request-user

Cards answered 3/3, 2014 at 16:6 Comment(4)
Where is the code that produced the error?Justinejustinian
@Cards show the view code where you save the modelDecrescendo
I forgot to say that I'm using class based views, I edited the questionCards
I manged to get this work when I changed my view to use django's generic CreateView instead of CreateWithInlinesView. I posted a new question about that problem. Thank you guys from your help!Cards
D
6

Assuming you are using ContactForm ModelForm:

def contact(request):
    if request.method == 'POST':
        form = ContactForm(request.POST)
        if form.is_valid():
            contact = form.save(commit=False)
            contact.owner = request.user
            contact.save()
            return HttpResponseRedirect('/thanks/')
    else:
         # do stuff
Decrescendo answered 3/3, 2014 at 16:26 Comment(1)
Nothing happened.Delouse
S
0

please post the exact code of what you tried.

If your view requires that a user is logged in, make sure it is enforced. This can be done by using the @login_required decorator

If you are in a view, and using a ModelForm to create the Contact, pass the commit=False kwarg to save method (like the example in the link you posted). This will keep the contact from being created until you assign the owner = request.user.

Since a logged in user is only available within the context of a request, just make sure that you are setting owner attribute it the views when creating a new Contact

Summerwood answered 3/3, 2014 at 16:9 Comment(3)
That's exactly what I've tried but I still get that error: null value in column "owner_id" violates not-null constraint It looks like form_valid is never called. Do you have any idea what I should do for that?Cards
@well also make sure that request has a user. You could do this with the @login_required decorator. I'm assuming the user is not logged in that's why request.user is NoneSummerwood
I'm using that LoginRequiredMixin, it should do the same thing. It's from the django-braces.Cards
C
0

The problem is that the default implementation of the form_valid method sets self.object, which is then used by get_success_url to determine where to redirect to.

If you replace your local obj variable with self.object, you should be fine:

def form_valid(self, form):
    self.object = form.save(commit=False)
    self.object.owner = self.request.user
    self.object.save()
    return HttpResponseRedirect(self.get_success_url())

I find a quick check of the original implementation for side-effects on the Classy Class-Based Views Web site, or the Django source-code on GitHub useful for spotting any side effects I need to reproduce in a subclass implementation.

Castellany answered 4/4, 2016 at 21:7 Comment(1)
Nothing Happened.Delouse

© 2022 - 2024 — McMap. All rights reserved.