Django: Preencher ID de usuário ao salvar um modelo

votos
39

Eu tenho um modelo com um campo created_by que está ligado ao modelo de usuário Django padrão. Eu preciso preencher automaticamente este com o ID do usuário atual quando o modelo é salvo. Eu não posso fazer isso na camada de administrador, como a maioria das partes do site não vai usar o Administrador embutido. Alguém pode aconselhar sobre como eu deveria ir sobre isso?

Publicado 14/05/2009 em 11:02
fonte usuário
Em outras línguas...                            


14 respostas

votos
31

Se você quer algo que vai trabalhar tanto na administração e em outros lugares, você deve usar um modelform personalizado. A idéia básica é a de substituir o __init__método para tirar um parâmetro extra - pedido - e armazená-lo como um atributo do formulário, em seguida, também substituir o método salvar para definir o ID de usuário antes de salvar o banco de dados.

class MyModelForm(forms.ModelForm):

   def __init__(self, *args, **kwargs):
       self.request = kwargs.pop('request', None)
       return super(MyModelForm, self).__init__(*args, **kwargs)


   def save(self, *args, **kwargs):
       kwargs['commit']=False
       obj = super(MyModelForm, self).save(*args, **kwargs)
       if self.request:
           obj.user = self.request.user
       obj.save()
       return obj
Respondeu 14/05/2009 em 12:43
fonte usuário

votos
23

A resposta de Daniel não vai trabalhar diretamente para o administrador, porque você precisa para passar no objeto de solicitação. Você pode ser capaz de fazer isso, substituindo o get_formmétodo na sua ModelAdminclasse, mas é provavelmente mais fácil para ficar longe da personalização forma e apenas substituir save_modelna sua ModelAdmin.

def save_model(self, request, obj, form, change):
    """When creating a new object, set the creator field.
    """
    if not change:
        obj.creator = request.user
    obj.save()
Respondeu 07/07/2011 em 18:36
fonte usuário

votos
22

A maneira menos obstrusive é usar um CurrentUserMiddlewarepara armazenar o usuário atual em um objeto local de segmento:

current_user.py

from threading import local

_user = local()

class CurrentUserMiddleware(object):
    def process_request(self, request):
        _user.value = request.user

def get_current_user():
    return _user.value

Agora você só precisa adicionar esse middleware para seus MIDDLEWARE_CLASSES após o middleware de autenticação.

settings.py

MIDDLEWARE_CLASSES = (
    ...
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    ...
    'current_user.CurrentUserMiddleware',
    ...
)

Seu modelo pode agora usar a get_current_userfunção para acessar o usuário sem ter que passar o objeto do pedido ao redor.

models.py

from django.db import models
from current_user import get_current_user

class MyModel(models.Model):
    created_by = models.ForeignKey('auth.User', default=get_current_user)

dica:

Se você estiver usando Django CMS você não precisa mesmo de definir o seu próprio CurrentUserMiddleware mas pode usar cms.middleware.user.CurrentUserMiddlewareea cms.utils.permissions.get_current_userfunção para recuperar o usuário atual.

Respondeu 14/02/2014 em 19:23
fonte usuário

votos
13

Esta abordagem totalmente grampeado o Parreira fora de mim. Eu queria dizer que exatamente uma vez, então eu implementou em middleware. Basta adicionar WhodidMiddleware após o seu middleware de autenticação.

Se seus CREATED_BY & modified_by campos são definidos para editable = False, então você não terá que mudar algumas de suas formas em tudo.

"""Add user created_by and modified_by foreign key refs to any model automatically.
   Almost entirely taken from https://github.com/Atomidata/django-audit-log/blob/master/audit_log/middleware.py"""
from django.db.models import signals
from django.utils.functional import curry

class WhodidMiddleware(object):
    def process_request(self, request):
        if not request.method in ('GET', 'HEAD', 'OPTIONS', 'TRACE'):
            if hasattr(request, 'user') and request.user.is_authenticated():
                user = request.user
            else:
                user = None

            mark_whodid = curry(self.mark_whodid, user)
            signals.pre_save.connect(mark_whodid,  dispatch_uid = (self.__class__, request,), weak = False)

    def process_response(self, request, response):
        signals.pre_save.disconnect(dispatch_uid =  (self.__class__, request,))
        return response

    def mark_whodid(self, user, sender, instance, **kwargs):
        if 'created_by' in instance._meta.fields and not instance.created_by:
            instance.created_by = user
        if 'modified_by' in instance._meta.fields:
            instance.modified_by = user
Respondeu 19/10/2012 em 16:37
fonte usuário

votos
7

Se você estiver usando visualizações de classe base a resposta de Daniel precisa de mais. Adicione o seguinte para garantir que o objeto de solicitação está disponível para nós em seu objeto ModelForm

class BaseCreateView(CreateView):
    def get_form_kwargs(self):
        """
        Returns the keyword arguments for instanciating the form.
        """
        kwargs = {'initial': self.get_initial()}
        if self.request.method in ('POST', 'PUT'):
            kwargs.update({
                'data': self.request.POST,
                'files': self.request.FILES,
                'request': self.request})
        return kwargs

Além disso, como já mencionado, você precisa devolver o obj no final do ModelForm.save ()

Respondeu 02/03/2012 em 02:49
fonte usuário

votos
6

aqui está como eu faço isso com vistas genéricas:

class MyView(CreateView):
    model = MyModel

    def form_valid(self, form):
        object = form.save(commit=False)
        object.owner = self.request.user
        object.save()
        return super(MyView, self).form_valid(form)
Respondeu 21/03/2013 em 06:25
fonte usuário

votos
3

Baseado em bikeshedder resposta 's, eu encontrei uma solução desde a sua realmente não funciona para mim.

  1. app / middleware / current_user.py

    from threading import local
    
    _user = local()
    
    class CurrentUserMiddleware(object):
    
    def __init__(self, get_response):
        self.get_response = get_response
    
    def __call__(self, request):
        _user.value = request.user
        return self.get_response(request)
    
    def get_current_user():
        return _user.value
    
  2. settings.py

    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
    
        'common.middleware.current_user.CurrentUserMiddleware',
    ]
    
  3. model.py

    from common.middleware import current_user
    created_by = models.ForeignKey(User, blank=False, related_name='created_by', editable=False, default=current_user.get_current_user)
    

Eu estou usando python 3.5 e Django 1.11.3

Respondeu 04/08/2017 em 01:01
fonte usuário

votos
2

Para fazer isso no site de administração, consulte Auto-preenchimento de campo created_by com o site de administração do Django

Respondeu 15/06/2011 em 02:01
fonte usuário

votos
1

Eu não acredito que a resposta de Daniel é o melhor que existe, uma vez que altera o comportamento padrão de um modelo de formulário por sempre salvar o objeto.

O código que eu usaria:

forms.py

from django import forms

class MyModelForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        self.user = kwargs.pop('user', None)
        super(MyModelForm, self).__init__(*args, **kwargs)

    def save(self, commit=True):
        obj = super(MyModelForm, self).save(commit=False)

        if obj.created_by_id is None:
            obj.created_by = self.user

        if commit:
            obj.save()
        return obj
Respondeu 20/12/2014 em 14:46
fonte usuário

votos
1

O método 'salvar' a partir forms.ModelForm retorna a salvo instanced.

Você deve adicionar uma última linha para MyModelForm:
...
voltar obj

Esta alteração é necessária se você estiver usando create_object ou update_object views genéricas.
Eles usam o objeto salvo para fazer o redirecionamento.

Respondeu 04/08/2010 em 18:56
fonte usuário

votos
0

A partir da documentação Django Models e request.user :

"Para rastrear o usuário que criou um objeto usando uma CreateView, você pode usar um ModelForm personalizado. Na visão, garantir que você não incluir [o campo do usuário] na lista de campos para editar e substituir form_valid () para adicionar o usuário:

from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic.edit import CreateView
from myapp.models import Author

class AuthorCreate(LoginRequiredMixin, CreateView):
    model = Author
    fields = ['name']

    def form_valid(self, form):
        form.instance.created_by = self.request.user
        return super().form_valid(form)
Respondeu 19/06/2019 em 00:13
fonte usuário

votos
0

qual é o problema com o uso de algo como:

class MyModelForm(forms.ModelForm):
    class Meta:
        model = MyModel
        exclude = ['created_by']

    def save(self, user):
        obj = super().save(commit = False)
        obj.created_by = user
        obj.save()
        return obj

Agora chamá-lo como myform.save(request.user)nas vistas .

aqui é a função de economia de ModelForm , que tem apenas um commitparâmetro.

Respondeu 07/07/2018 em 04:14
fonte usuário

votos
0

Para referências futuras, melhor solução que eu encontrei sobre este assunto:

https://pypi.python.org/pypi/django-crum/0.6.1

Esta biblioteca consistem em alguns middleware. Depois de configurar esta libary, simplesmente substituir o método salvar de modelo e fazer o seguinte,

from crum import get_current_user        


def save(self, *args, **kwargs):
    user = get_current_user()
    if not self.pk:
        self.created_by = user
    else:
        self.changed_by = user
    super(Foomodel, self).save(*args, **kwargs)

se você criar e modelo abstrato e herdar a partir dele por todo o seu modelo, você começa suas auto povoada campos CREATED_BY e changed_by.

Respondeu 11/07/2015 em 23:53
fonte usuário

votos
-4

Nota certeza se você estivesse olhando para isso, mas adicionando a seguinte

user = models.ForeignKey('auth.User')

a um modelo irá trabalhar para adicionar o ID de usuário para o modelo.

A seguir, cada hierarquia pertence a um usuário.

class Hierarchy(models.Model):
    user = models.ForeignKey('auth.User')
    name = models.CharField(max_length=200)
    desc = models.CharField(max_length=1500)
Respondeu 06/01/2014 em 00:25
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more