custom - login url django
Django: Rellenar ID de usuario al guardar un modelo (13)
¿cuál es el problema con el uso de algo así 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
Ahora llámalo como myform.save(request.user)
en las vistas .
aquí está la función de guardar de ModelForm , que tiene solo un parámetro de commit
.
Tengo un modelo con un campo created_by que está vinculado al modelo estándar de usuario de Django. Necesito rellenar esto automáticamente con el ID del usuario actual cuando se guarda el modelo. No puedo hacer esto en la capa Admin, ya que la mayoría de las partes del sitio no usarán el administrador incorporado. ¿Alguien puede aconsejarme sobre cómo debo hacer esto?
Basado en la respuesta de , encontré una solución ya que en realidad no funcionaba para mí.
aplicación / 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
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'', ]
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)
Estoy usando python 3.5 y django 1.11.3
El método ''guardar'' de forms.ModelForm devuelve el instanciado guardado.
Debería agregar una última línea a MyModelForm:
...
obj regreso
Este cambio es necesario si está utilizando vistas genéricas create_object o update_object.
Usan el objeto guardado para hacer la redirección.
La forma menos obstructiva es usar un CurrentUserMiddleware
para almacenar el usuario actual en un objeto local thread:
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
Ahora solo necesita agregar este middleware a MIDDLEWARE_CLASSES después del middleware de autenticación.
settings.py
MIDDLEWARE_CLASSES = (
...
''django.contrib.auth.middleware.AuthenticationMiddleware'',
...
''current_user.CurrentUserMiddleware'',
...
)
Su modelo ahora puede usar la función get_current_user
para acceder al usuario sin tener que pasar el objeto de solicitud.
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)
Insinuación:
Si está utilizando Django CMS, ni siquiera necesita definir su propio CurrentUserMiddleware, pero puede usar cms.middleware.user.CurrentUserMiddleware
y la función cms.utils.permissions.get_current_user
para recuperar el usuario actual.
La respuesta de Daniel no funcionará directamente para el administrador porque necesita pasar el objeto de solicitud. Es posible que pueda hacer esto anulando el método get_form
en su clase ModelAdmin
, pero probablemente sea más fácil mantenerse alejado de la personalización del formulario y simplemente anular save_model
en su 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()
No creo que la respuesta de Daniel sea la mejor, ya que cambia el comportamiento predeterminado de un formulario modelo al guardar siempre el objeto.
El código que usaría:
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
Para futuras referencias, la mejor solución que encontré sobre este tema:
https://pypi.python.org/pypi/django-crum/0.6.1
Esta biblioteca consiste en algún middleware. Después de configurar esta biblioteca, simplemente anule el método de guardar del modelo y haga lo siguiente,
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)
si crea y abstrae el modelo y lo hereda para todo su modelo, obtendrá sus campos auto poblados create_by y changed_by.
Para hacer esto en el sitio de administración, consulte Autocompletar el campo created_by con el sitio de administración de Django
Si usa vistas basadas en clases, la respuesta de Daniel necesita más. Agregue lo siguiente para asegurarse de que el objeto de solicitud esté disponible para nosotros en su 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
Además, como ya se mencionó, debe devolver el obj al final de ModelForm.save ()
Tenga en cuenta que si estaba buscando esto, pero agregando lo siguiente
user = models.ForeignKey(''auth.User'')
a un modelo trabajará para agregar la identificación del usuario al modelo.
A continuación, cada jerarquía pertenece a un usuario.
class Hierarchy(models.Model):
user = models.ForeignKey(''auth.User'')
name = models.CharField(max_length=200)
desc = models.CharField(max_length=1500)
Todo este enfoque me molestó mucho. Quería decirlo exactamente una vez, así que lo implementé en middleware. Simplemente agregue WhodidMiddleware después de su middleware de autenticación.
Si sus campos created_by & modified_by están configurados como editable = False
entonces no tendrá que cambiar ninguno de sus formularios.
"""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
así es como lo hago con 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)
Si desea algo que funcione tanto en el administrador como en cualquier otro lugar, debe usar un formulario modelo personalizado. La idea básica es anular el método __init__
para tomar un parámetro adicional - solicitud - y almacenarlo como un atributo del formulario, luego también anular el método guardar para establecer la identificación del usuario antes de guardarla en la base de datos.
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