38

I have a database of articles with a

submitter = models.ForeignKey(User, editable=False)

Where User is imported as follows:

from django.contrib.auth.models import User. 

I would like to auto insert the current active user to the submitter field when a particular user submits the article.

Anyone have any suggestions?

Serjik
  • 10,543
  • 8
  • 61
  • 70
FurtiveFelon
  • 14,714
  • 27
  • 76
  • 97

6 Answers6

50

Just in case anyone is looking for an answer, here is the solution i've found here: http://demongin.org/blog/806/

To summarize: He had an Essay table as follows:

from django.contrib.auth.models import User

class Essay(models.Model):
    title = models.CharField(max_length=666)
    body = models.TextField()
    author = models.ForeignKey(User, null=True, blank=True)

where multiuser can create essays, so he created a admin.ModelAdmin class as follows:

from myapplication.essay.models import Essay
from django.contrib import admin

class EssayAdmin(admin.ModelAdmin):
    list_display = ('title', 'author')
    fieldsets = [
        (None, { 'fields': [('title','body')] } ),
    ]

    def save_model(self, request, obj, form, change):
        if getattr(obj, 'author', None) is None:
            obj.author = request.user
        obj.save()
FurtiveFelon
  • 14,714
  • 27
  • 76
  • 97
  • This only works if author has null=True. Without it I get "raise self.field.rel.to.DoesNotExist" from the "getattr" line. Can I require null=False? – dfrankow May 27 '12 at 17:49
  • @dfrankow, I'm not sure if you figured this out yet, but if you remove the `if getattr` line, you can do this with a `null=False` column. – Andy Aug 08 '12 at 20:00
  • 2
    You can also add 'if not change:' to handle the case of entry creation. The 'else' is if it's being modified. – XIrrad May 16 '14 at 03:31
12

Let's say that user B saves a record created by user A. By using this approach above the record will be saved with user B. In some scenarios this might not be the best choice, because each user who saves that record will be "stealing" it. There's a workaround to this, that will save the user only once (the one who creates it):

models.py

from django.contrib.auth.models import User

class Car(models.Model):
    created_by = models.ForeignKey(User,editable=False,null=True,blank=True)
    car_name = models.CharField(max_length=40)

admin.py

from . models import *

class CarAdmin(admin.ModelAdmin):
    list_display = ('car_name','created_by')
    actions = None

    def save_model(self, request, obj, form, change):
        if not obj.created_by:
            obj.created_by = request.user
        obj.save()
Lourenzo Costa
  • 129
  • 1
  • 2
3

If you don't want to keep foreignkey in you model to user, then in your admin.py override save method

obj.author = request.user.username
obj.save()

This will store the username who is logged in your db.

arulmr
  • 8,620
  • 9
  • 54
  • 69
ha22109
  • 8,036
  • 13
  • 44
  • 48
1

It's time for a better solution override the get_form method

let's say we have this model

models.py

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


class Post(models.Model):
    title = models.CharField(max_length=256)
    content = models.TextField()
    author = models.ForeignKey(User, on_delete=models.CASCADE)


    def __str__(self):
        return self.title

admin.py

class PostAdmin(admin.ModelAdmin):
    # you should prevent author field to be manipulated 
    readonly_fields = ['author']

    def get_form(self, request, obj=None, **kwargs):
        # here insert/fill the current user name or id from request
        Post.author = request.user
        return super().get_form(request, obj, **kwargs)


    def save_model(self, request, obj, form, change):
        obj.author = request.user
        obj.last_modified_by = request.user
        obj.save()


admin.site.register(Post, PostAdmin)
Fathy
  • 377
  • 5
  • 13
  • ModelAdmin.get_form returns a form class and not a form instance, so it's not really suitable to set any specific form fields (for a bound form, that will then save the object). Additionally, you seem to be setting a Post class level attribute, that I don't think will do anything. The save_model implementation is indeed the way to go (you just don't need to set both obj.author and obj.authori_id, Django will take care of the id under the hood). – Ion Scerbatiuc Mar 16 '21 at 14:03
0

As per http://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.prepopulated_fields you can't use ForeignKey with the prepopulated_field admin directive, alas

But this thread might help you. In my answer I also link to a Google-scanned version of Pro Django, which has a great solution for this kind of thing. Ideally, am sure it's better if you can buy the book, but Google seems to have most of the relevant chapter anyway.

Community
  • 1
  • 1
Steve Jalim
  • 11,989
  • 1
  • 37
  • 54
0

You can't do it directly. However you can achieve this creating middleware and using current user as global variable. But there is a package already doing it : django-currentuser

First install it then

setting.py

 MIDDLEWARE = (
    ...,
    'django_currentuser.middleware.ThreadLocalUserMiddleware',
)

and import it in the model file

from django_currentuser.middleware import ( get_current_user, get_current_authenticated_user)

And use;

class Foo(models.Model):
    created_by = CurrentUserField()
    updated_by = CurrentUserField(on_update=True)
bekir çelik
  • 170
  • 5