16

I have the following:

from django.contrib.auth.models import User

class ClientDetails(models.Model):
    created_by = models.ForeignKey(User)
    ...

How do I make created_by default to the currently logged in user?

(I want to do this so I can hide it in the admin view mainly but also because when I save an instance I don't want to be filling it every time)

Robert Johnstone
  • 5,431
  • 12
  • 58
  • 88

6 Answers6

19

Since you need to get the currently logged in user from a request object you cannot get it in the model's save-method,but you can eg override the model admin's save_model-method:

class MyAdmin(admin.ModelAdmin):
    def save_model(self, request, instance, form, change):
        user = request.user 
        instance = form.save(commit=False)
        if not change or not instance.created_by:
            instance.created_by = user
        instance.modified_by = user
        instance.save()
        form.save_m2m()
        return instance
Bernhard Vallant
  • 49,468
  • 20
  • 120
  • 148
14

You have to override get_changeform_initial_data method in your model Admin class in admin.py as follows:

# admin.py

class ClientDetailsAdmin(admin.ModelAdmin):
    def get_changeform_initial_data(self, request):
        get_data = super(ClientDetailsAdmin, self).get_changeform_initial_data(request)
        get_data['created_by'] = request.user.pk
        return get_data

admin.site.register(ClientDetails, ClientDetailsAdmin)

In such way you obtain the most elegant solution since the created_by field is filed up when you create new record.

PaulWebbster
  • 1,480
  • 2
  • 14
  • 27
  • This is very nice! Could this be extended to work for `updated_by` on every update? (Ideally less messily than overriding `ModelAdmin._changeform_view`, and pre-render like this, so not overriding `save_model`.) – Chris Aug 25 '19 at 20:40
  • Overriding `formfield_for_foreignkey` you can force the queryset to be the current user only, which is close but not as nice as the above, which permits a user to override this if necessary. (Idea from [here](https://timonweb.com/posts/auto-select-current-user-in-django-admin-form/).) – Chris Aug 25 '19 at 20:56
  • **NOTE:** will work on new ones, not on existing ones – ajinzrathod Jul 07 '21 at 08:45
6

Building on the accepted answer, if you're looking to do this with Class Based views, you can follow the instructions in the docs, overriding the form_valid() method on the class view:

# views.py

from django.views.generic.edit import CreateView

class CreateClient(CreateView):
    def form_valid(self, form):
        form.instance.created_by = self.request.user
        return super(CreateClient, self).form_valid(form)
Ian Lee
  • 502
  • 1
  • 5
  • 12
6

I had a similar issue recently, this is from my views.py file

def CircleAdd(request):

    form = CircleAddForm(request.POST)

    if form.is_valid():

        Circle = form.save(commit=False)
        Circle.Author = request.user
        Circle = Circle.save()

And then I had a form for the 'circles' model, which was just a wrapper really (forms.py)

class CircleAddForm(ModelForm):
    class Meta:
        model = Circle

Remember to import the form in your view!

Edit: not even sure if you even need to bother with the separate form, the key bit is the fake commit, followed by the real

hcliff
  • 433
  • 5
  • 16
2

Normal modelfields have a default argument. But ForeignKeys do not as far as I know, so I guess you need to work with a post_save signal.

Bjorn
  • 5,272
  • 1
  • 24
  • 35
1

I found:

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

class CurrentUserField(models.ForeignKey):
    def __init__(self, **kwargs):
        super(CurrentUserField, self).__init__(User, null=True, **kwargs)

    def contribute_to_class(self, cls, name):
        super(CurrentUserField, self).contribute_to_class(cls, name)
        registry = registration.FieldRegistry()
        registry.add_field(cls, self)

class ClientDetails(models.Model):
    created_by = CurrentUserField()
...

from here. But isn't there an easier way?

Robert Johnstone
  • 5,431
  • 12
  • 58
  • 88