28

I'd like to do something like this:

class Task(models.Model):
    ...
    created_by = models.ForeignKey(User, **default=[LoggedInUser]** blank=True, null=True, related_name='created_by')

Is this possible? I couldn't find what's the proper way to get the logged in user, apart from doing request.user, in a view, which doesn't seem to work here.

PS_ I realise I could initialize the Model data by other means, but I think this is the cleanest way.

a_m0d
  • 12,034
  • 15
  • 57
  • 79
Ignacio
  • 7,947
  • 15
  • 63
  • 74

5 Answers5

40

If you want to achieve this within the admin interface, you can use the save_model method. See below an example:

class List(models.Model):
    title = models.CharField(max_length=64)
    author = models.ForeignKey(User)

class ListAdmin(admin.ModelAdmin):
    fields = ('title',)
    def save_model(self, request, obj, form, change):
        obj.author = request.user
        obj.save()
scaraveos
  • 1,016
  • 2
  • 10
  • 12
12

No, you can't do it this way. Django (and Python) has pretty much zero global values, and that's a Good Thing(tm). Normally you get the current user in the view(request) with request.user. You can then pass that as a param to various methods/functions, but trying to set a global user will only lead to tears in a multi-threaded environment.

There should be a bumper sticker that says, Globals are Evil. This will give you a good idea about my Number One problem with PHP.

Peter Rowell
  • 17,605
  • 2
  • 49
  • 65
  • Fair enough. I'll see if I can get it to work with signals, which I think it may be the best way to go then. Thanks – Ignacio Mar 10 '10 at 13:13
6

SOLVED: I will use an example, but the important part is the funciton on the views.py. User is automatically available by django. Note the 'autor' model field has a ForeignKey to the 'User'. In the 'def form_valid' below I assign the currently logged in user as the default value.

If this is your model:

class ProspectoAccion(models.Model):
"""
Model representing a comment against a blog post.
"""
    descripcion = models.TextField(max_length=1000)
    autor = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
    accion_date = models.DateTimeField(auto_now_add=True)
    prospecto= models.ForeignKey(Prospecto, on_delete=models.CASCADE)
    tipo_accion = models.ForeignKey('Accion', on_delete=models.SET_NULL, null=True)

And you have a class based view, do the following:

class ProspectoAccionCreate(LoginRequiredMixin, CreateView):
"""
Form for adding una acción. Requires login (despues poner)
"""
    model = ProspectoAccion
    fields = ['tipo_accion','descripcion',]

    def form_valid(self, form):

        #Add logged-in user as autor of comment THIS IS THE KEY TO THE SOLUTION
        form.instance.autor = self.request.user

        # Call super-class form validation behaviour
        return super(ProspectoAccionCreate, self).form_valid(form)

HERE IS AN EXAMPLE FROM THE DOCUMENTATION: https://docs.djangoproject.com/en/2.0/topics/class-based-views/generic-editing/#models-and-request-user

Derek Adair
  • 21,846
  • 31
  • 97
  • 134
1

If use ModelForm, the following will fill a default value for a special field. such as, owner filed is a charfield for user's name

def fillview(request):
    instance = YourModel(owner=request.user.username)
    form = YourModelForm(instance=instance)

    if request.method == 'POST':
        form = YourModelForm(request.POST, request.FILES)
        if form.is_valid():
            pass
            return render(request, 'success.html')

    return render(request, 'fill.html', {'form': form})

When logged in, you could see owner filed is current user's name.

WeizhongTu
  • 6,124
  • 4
  • 37
  • 51
-2

By default, Django already creates a "created_by" attribute. You don't need to create your own.

If you nonetheless need to save this information separately to, let's say, have the possibility to change the user later on without affecting the original creator value, then you could override the save function to retrieve the value that Django assigns by default to "created_user":

class Application(models.Model):
    property = models.ForeignKey(Property, on_delete=models.CASCADE)
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='applications', editable=False, null=True)
    ...

    def save(self, *args, **kwargs):
        super().save(*args, **kwargs)
        if not self.user:
            self.user = self.created_by
            super(Application, self).save(*args, **kwargs)
  • django doesn't provide these fields. the link in the answer is what somebody came up with for their own project – rptmat57 Jan 30 '21 at 18:38