2011-02-03 12 views
13

Tengo un modelo, Foo. Tiene varias propiedades de base de datos y varias propiedades que se calculan en función de una combinación de factores. Me gustaría presentar estas propiedades calculadas al usuario como si fueran propiedades de la base de datos. (Los factores de respaldo se cambiarían para reflejar la entrada del usuario.) ¿Hay alguna manera de hacer esto con la interfaz de administración de Django?Django: ¿falsificando un campo en la interfaz de administración?

+0

¿Desea presentarlos en la lista de cambios del administrador o en el formulario? –

+0

@lazerscience No estoy seguro de cuál es la lista de cambios de administrador. Definitivamente la forma. –

+0

Si desea que se muestren (se muestren, no se puedan editar) en el formulario, y están disponibles como métodos en el modelo, puede copiar el archivo "change_form.html" en su $ {TEMPLATE_ROOT}/admin/APPNAME/MODELNAME/change_form.html y edítelo según su corazón. –

Respuesta

30

yo sugeriría que una subclase de ModelForm Foo (FooAdminForm) para añadir sus propios campos que no están respaldados por la base de datos. Su validación personalizada puede residir en los métodos clean_* de ModelForm.

Dentro del método save_model de FooAdmin obtiene la solicitud, una instancia de Foo y los datos del formulario, por lo que podría hacer todo el procesamiento de los datos antes/después de guardar la instancia.

Aquí se muestra un ejemplo de un modelo con un formulario personalizado registrado en administración de Django:

from django import forms 
from django.db import models 
from django.contrib import admin 


class Foo(models.Model): 
    name = models.CharField(max_length=30) 


class FooAdminForm(forms.ModelForm): 
    # custom field not backed by database 
    calculated = forms.IntegerField() 

    class Meta: 
     model = Foo 


class FooAdmin(admin.ModelAdmin): 
    # use the custom form instead of a generic modelform 
    form = FooAdminForm 

    # your own processing 
    def save_model(self, request, obj, form, change): 
     # for example: 
     obj.name = 'Foo #%d' % form.cleaned_data['calculated'] 
     obj.save() 


admin.site.register(Foo, FooAdmin) 

Proporcionar los valores iniciales de los campos personalizados en base a datos de instancia

(soy no estoy seguro de si esta es la mejor solución, pero debería funcionar.)

Cuando se forma un modelo para una instancia de modelo existente en el databa se construye, se pasa esta instancia. Por lo tanto, en FooAdminForm's __init__ se pueden cambiar los atributos de los campos en función de los datos de la instancia.

def __init__(self, *args, **kwargs): 
     # only change attributes if an instance is passed    
     instance = kwargs.get('instance') 
     if instance: 
      self.base_fields['calculated'].initial = (instance.bar == 42) 
     forms.ModelForm.__init__(self, *args, **kwargs) 
+0

Se ve bien. Sin embargo, cuando uso un 'CheckboxInput' en vez de' IntegerField', no aparece. Además, ¿cómo puedo establecer el valor inicial de la casilla de verificación? Dice que a la función 'check_true' se le dará el" valor "del campo, pero ¿cómo configuro cuál es ese valor? –

+0

Use un 'BooleanField' (usa CheckboxInput como su widget predeterminado). Los campos de formulario en django aceptan un argumento de palabra clave 'initial', por ejemplo:' bar = forms.BooleanField (initial = True) ' –

+0

es bueno saberlo. ¿Cómo puedo establecer el valor inicial como una función de la instancia del modelo de respaldo? –

1

En el formulario de edición, ponga el nombre de la propiedad en readonly_fields (1.2 arriba solamente).

En la lista de cambios, póngalo en list_display.

+2

Pero sí quiero que la propiedad sea editable; simplemente no se corresponde directamente con una fila de la base de datos, necesito hacer mi propio procesamiento para cambiar los datos de back-end en consecuencia. –

1

Usted puede utilizar el decorador @property en su modelo (Python> = 2.4):

class Product(models.Model): 

    @property 
    def ranking(self): 
     return 1 

"ranking" puede entonces ser utilizado en list_display:

class ProductAdmin(admin.ModelAdmin): 
    list_display = ('ranking', 'asin', 'title') 
+1

'@ property' no es obligatorio. 'list_display' aceptará cualquier método en el modelo (o ModelAdmin) –

4

Es fácil suficiente para obtener datos arbitrarios para aparecer en la lista de cambios o hacer que un campo aparezca en el formulario: list_display toma arbitrariamente las propiedades del modelo real, o los métodos definidos en el modelo o el modeladmin, y usted c una subclase forms.ModelForm para agregar cualquier tipo de campo que desee al formulario de cambio.

Lo que es mucho más difícil/imposible es combinar los dos, es decir, tener una pieza arbitraria de datos en la lista de cambios que puede editar in situ especificando list_editable. Django parece aceptar solo una propiedad de modelo verdadero que corresponde a un campo de base de datos. (incluso utilizando @property en el método en la definición del modelo no es suficiente).

¿Alguien ha encontrado una forma de editar un campo que no está realmente presente en el modelo directamente desde la página de la lista de cambios?

+1

Me encantaría obtener la respuesta para ese – haki

Cuestiones relacionadas