2010-06-10 6 views
12

Tengo dos modelos, un modelo principal y un modelo en línea relacionado que me gustaría mostrar como un en línea en el administrador. Este modelo en línea se puede utilizar para, por ejemplo, tomar notas sobre el modelo y debe hacer un seguimiento del usuario administrador que realiza cambios. Si bien esto parece simple (y, de hecho, los documentos muestran un ejemplo de esto cuando el campo de usuario es parte del MainModel), parece que no puedo entenderlo cuando el campo está en línea.Django InlineModelAdmin - establecer el campo en línea desde la solicitud al guardar (establecer el campo de usuario automáticamente) (save_formset vs save_model)

Para ser más específicos, mi objetivo es:

  1. usuario edita MainModel
  2. usuario añade un InlineModel, no llenar en el campo de usuario
  3. usuario presiona ahorrar
  4. Código rellena el campo de usuario para las instancias de InlineModel recién creadas
  5. (el campo de usuario de Bonus! es solo para instancias existentes y está oculto para las nuevas líneas)

Y mis preguntas:

  1. ¿Es esto correcto? Su demasiado bajo save_model no se llama para las instancias de InlineModelAdmin
  2. ¿Hacerlo de esta manera me permite guardar sin causar un error? (se requiere usuario, la validación lo señala)
  3. ¿Cómo puedo ocultar el campo de entrada del usuario para las nuevas líneas y que sea de solo lectura para las líneas en línea existentes?

Estas son mis ideas actuales:


#models.py 
class MainModel(models.Model): 
    some_info = models.IntegerField() 

class InlineModel(models.Model): 
    main = models.ForeignKey(MainModel) 
    data = models.CharField(max_length=255) 
    user = models.ForeignKey('auth.User') 

#admin.py 
class InlineModelInline(admin.TabularInline): 
    model = InlineModel 
    fields = ('data', 'user') 
    #readonly_fields = ('data', 'user') #Bonus question later 

class MainModelAdmin(admin.ModelAdmin): 
    list_display = ('id', 'some_info') 
    inlines = [InlineModelInline] 

    #def save_model(self, request, obj, form, change): 
     #http://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.save_model 
     #Only called for MainModel, not for any of the inlines 
     #Otherwise, would be ideal 

    def save_formset(self, request, form, formset, change): 
     #http://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.save_formset 
     #Experimenting showd this is called once per formset (where the formset is a group of inlines) 
     #See code block at http://code.djangoproject.com/browser/django/tags/releases/1.2.1/django/contrib/admin/options.py#L894 
     if not isinstance(formset.model, InlineModel): 
      return super(MainModelAdmin, self).save_formset(request, form, formset, change) 
     instances = formset.save(commit=False) 
     for instance in instances: 
      if not instance.pk: 
       instance.user = request.user 
     instance.save() 
     formset.save_m2m() 

Respuesta

9

He resuelto la primera parte de mi pregunta:

def save_formset(self, request, form, formset, change): 
    if formset.model != InlineModel: 
     return super(MainModelAdmin, self).save_formset(request, form, formset, change) 
    instances = formset.save(commit=False) 
    for instance in instances: 
     if not instance.pk: 
      instance.user = request.user 
     instance.save() 
    formset.save_m2m() 

Ahora estoy interesado en el comportamiento de bonificación:

  1. Estoy obligado a seleccionar un usuario al agregar un nuevo en línea debido a las reglas de validación. Mi mejor opción es no incluir el campo 'usuario' en mi tupla InlineModelInline.fields, pero esto no mostrará el autor de las instancias existentes de InlineModel. (Editar: agregar 'usuario' a readonly_fields funciona aquí)

  2. (Editar) ¿Cómo puedo hacer que las líneas existentes representen 'datos' como de solo lectura, pero aún así poder editarlos al agregar una nueva línea?

+1

Una nota a mí mismo, este save_formset es un método de la admin.ModelAdmin, y procesará todos los niños inlines asignado en el ModelAdmin – monkut

+0

Gracias por su pregunta/respuestas aquí. En cuanto a la funcionalidad de 'bonificación': después de marcar el usuario foreignKey en el modelo django con editable = False, el formset en línea pasó la validación, el campo de usuario todavía estaba establecido y todo era kosher. user = models.ForeignKey (Usuario, editable = Falso) – sdailey

+0

Hm, se olvidó por completo de editable = Falso en el modelo. Nice ca tch, gracias. –

1

Me funcionó. This enfoque no me permitirá eliminar elementos en línea.

def save_formset(self, request, form, formset, change): 
    for form in formset.forms: 
     form.instance.user = request.user 
    formset.save() 
0

Para responder a la pregunta de experiencia: "¿Cómo puedo hacer que los inlines existentes hacen 'datos' como de sólo lectura, pero aún así ser capaz de editarlo cuando se añade una nueva línea?":

utilizo dos inlines para el mismo modelo:.

#admin.py 
class InlineModelInline(admin.TabularInline): 
    model = InlineModel 
    extra = 1 
    max_num = 1 

#admin.py 
class InlineModelExistingInline(admin.TabularInline): 
    model = InlineModel 
    readonly_fields = ('data', 'user') #All Fields here except pk 
    can_delete = False 
    extra = 0 
    max_num = 0 

class MainModelAdmin(admin.ModelAdmin): 
    ... 
    inlines = [InlineModelInline, InlineModelExistingInline] 
    ... 
Cuestiones relacionadas