My Site
Categories
Django: Using ModelAdmin to default to currently logged in user

Yeah, you may have noticed that I've been working on the blog lately. Poor openclue.org got flooded with already posted RSS feeds again. This happens all to often. Sorry guys.

Anyway, this blog system has the ability to have more than one person post articles. In the past, sjohannes used to post here too. The model for articles looks something like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
from django.contrib.auth.models import User
from django.db import models
import datetime

class Article(models.Model):
     title = models.CharField(max_length=250)
     slug = models.SlugField()
     article = models.TextField()
     pub_date = models.DateTimeField(
          default=datetime.datetime.now)
     publisher = models.ForeignKey(User)

As you can see, there's a ForeignKey to django.contrib.auth.models.User. The question here is: how do I make the "publisher" field default to the currently logged in user? It was harder than I thought it should be, but it can be done using hooks in the ModelAdmin for the Article model. Take a look:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
class ArticleAdmin(admin.ModelAdmin):
    list_display = ('pub_date', 'publisher', 'title', 'slug')
    search_fields = ('title', 'article')
    prepopulated_fields = {
        'slug': ('title',),
    }

    def get_form(self, req, obj=None, **kwargs):
        # save the currently logged in user for later
        self.current_user = req.user
        return super(ArticleAdmin, self).get_form(req, obj, **kwargs)

    def formfield_for_dbfield(self, field, **kwargs):
        from django import forms
        from django.contrib.auth import models
        if field.name == 'publisher':
            queryset = models.User.objects.all()
            return forms.ModelChoiceField(
                queryset=queryset, initial=self.current_user.id)
        return super(ArticleAdmin, self).formfield_for_dbfield(field, **kwargs)

admin.site.register(models.Article, ArticleAdmin)

As you can see, I overload "get_form" for one purpose: It takes the HttpRequest as the first argument, which we can use to save the currently logged in user. The other method that's overloaded, "formfield_for_dbfield" is called for every field in the model, and is made for the purpose of specifying your own custom form fields (and widgets). In this case, we use the same field type that the admin would have used - "ModelChoiceField" and give it an initial, which is the id of the currently logged in user.

There you have it. It's a little hacky, but it's the only way I could find to do it. If you've seen a cleaner way, let me know!"

Filed under: Programming, Python, Django
Comments:

From metamatik on Oct. 1 @ 4:29 p.m. 2009

Hi there,

I'm right now dealing with the same issue, sort of; except I don't want to leave the choice to the currently logged-in user.

I've found this in the Django doc, thought you might be interested:

---

ModelAdmin.save_model(self, request, obj, form, change)ΒΆ

The save_model method is given the HttpRequest, a model instance, a ModelForm instance and a boolean value based on whether it is adding or changing the object. Here you can do any pre- or post-save operations.

For example to attach request.user to the object prior to saving:

class ArticleAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
obj.user = request.user
obj.save()

---

( source: http://docs.djangoproject.com/en/1.0/ref/contrib/admin/#modeladmin-methods )

Cheers!
From mruwek on July 13 @ 7:32 a.m. 2010

Hi, take a look at this resolution:

from django.contrib.auth.models import User

def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == 'publisher':
kwargs['queryset'] = User.objects.all()
kwargs['initial'] = request.user.id
return db_field.formfield(**kwargs)
return super(ArticleAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
From nostradamnit on July 28 @ 3:57 a.m. 2010

metamatik's solution (the recommended one by the look of it) is right and works perfectly. Just implement the save_model method and you have access to all the info one might need.
From Jim on Dec. 2 @ 8:55 a.m. 2010

The original article helped me when I needed to alter a choice field that was not a foreign key field, so while the formfield_for_foreignkey is the right way to set the publisher, the initial article helped me get the right choices to another field based on the current user. Thanks.

Add a comment:
captcha

Optional, for comment reply notifications
 
Note: If you enter your email address, you will be subscribed to this article and will recieve comment updates via email. This is the only thing your address will be used for. A link will be provided at the end of each email that will allow you to unsubscribe should you need to, or you can go to http://synicworld.com//unsubscribe to unsubscribe from any/all updates.