with tutorial the para latest framework español desde cero applications django django-admin modeladmin

tutorial - the django project



Django: ¿accediendo a la instancia del modelo desde ModelAdmin? (3)

Creo que es posible que deba abordar esto de una manera ligeramente diferente, modificando el ModelForm, en lugar de la clase de administración. Algo como esto:

class OrderForm(forms.ModelForm): def __init__(self, *args, **kwargs): super(OrderForm, self).__init__(*args, **kwargs) self.fields[''parent_order''].queryset = Order.objects.filter( child_orders__ordernumber__exact=self.instance.pk) class OrderAdmin(admin.ModelAdmin): form = OrderForm

Tengo un modelo para pedidos en una aplicación de tienda en línea, con una clave principal autoincrementada y una clave externa, ya que las órdenes se pueden dividir en varias órdenes, pero se debe mantener la relación con la orden original.

class Order(models.Model): ordernumber = models.AutoField(primary_key=True) parent_order = models.ForeignKey(''self'', null=True, blank=True, related_name=''child_orders'') # .. other fields not relevant here

He registrado una clase OrderAdmin para el sitio de administración. Para la vista detallada, he incluido parent_order en el atributo fieldsets . Por supuesto, por defecto esto enumera todos los pedidos en un cuadro de selección, pero este no es el comportamiento deseado. En cambio, para pedidos que no tienen una orden principal (es decir, no se han dividido de otra orden; parent_order es NULL / None), no se deben mostrar pedidos. Para los pedidos que se han dividido, esto solo debe mostrar el orden principal único.

Hay un método más nuevo de ModelAdmin disponible, formfield_for_foreignkey , que parece perfecto para esto, ya que el conjunto de consulta se puede filtrar dentro de él. Imagine que estamos viendo la vista detallada de la orden # 11234, que se ha dividido de la orden # 11208. El código está debajo

def formfield_for_foreignkey(self, db_field, request, **kwargs): if db_field.name == ''parent_order'': # kwargs["queryset"] = Order.objects.filter(child_orders__ordernumber__exact=11234) return db_field.formfield(**kwargs) return super(OrderAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)

La fila comentada funciona cuando se ejecuta en un shell de Python, y devuelve un conjunto de preguntas de un solo elemento que contiene el pedido n.º 11208 para el n.º 11234 y todas las demás órdenes que pueden haberse dividido desde él.

Por supuesto, no podemos codificar el número de orden allí. Necesitamos una referencia al campo ordernumber de la instancia de pedido cuya página de detalles estamos viendo. Me gusta esto:

kwargs["queryset"] = Order.objects.filter(child_orders__ordernumber__exact=?????)

No he encontrado una manera de reemplazarlo? ????? con una referencia a la instancia de pedido "actual", y he cavado bastante profundo. self dentro de formfield_for_foreignkey hace referencia a la instancia de ModelAdmin, y aunque tiene un atributo de model , no es la instancia del modelo de orden (es una referencia de ModelBase; self.model () devuelve una instancia, pero su número de orden es Ninguno).

Una solución podría ser extraer el número de orden de request.path (/ admin / orders / order / 11234 /), pero eso es realmente feo. Realmente deseo que haya una mejor manera.


He modelado mi clase en línea de esta manera. Es un poco feo cómo se obtiene el ID de formulario padre para filtrar los datos en línea, pero funciona. Filtra las unidades por empresa desde el formulario principal.

El concepto original se explica aquí http://www.stereoplex.com/blog/filtering-dropdown-lists-in-the-django-admin

class CompanyOccupationInline(admin.TabularInline): model = Occupation # max_num = 1 extra = 0 can_delete = False formset = RequiredInlineFormSet def formfield_for_dbfield(self, field, **kwargs): if field.name == ''unit'': parent_company = self.get_object(kwargs[''request''], Company) units = Unit.objects.filter(company=parent_company) return forms.ModelChoiceField(queryset=units) return super(CompanyOccupationInline, self).formfield_for_dbfield(field, **kwargs) def get_object(self, request, model): object_id = resolve(request.path).args[0] try: object_id = int(object_id) except ValueError: return None return model.objects.get(pk=object_id)


La respuesta anterior de Erwin Julius funcionó para mí, excepto que encontré que el nombre "get_object" entra en conflicto con una función de Django, así que nombre la función "my_get_object".

class CompanyOccupationInline(admin.TabularInline): model = Occupation # max_num = 1 extra = 0 can_delete = False formset = RequiredInlineFormSet def formfield_for_dbfield(self, field, **kwargs): if field.name == ''unit'': parent_company = self.my_get_object(kwargs[''request''], Company) units = Unit.objects.filter(company=parent_company) return forms.ModelChoiceField(queryset=units) return super(CompanyOccupationInline, self).formfield_for_dbfield(field, **kwargs) def my_get_object(self, request, model): object_id = request.META[''PATH_INFO''].strip(''/'').split(''/'')[-1] try: object_id = int(object_id) except ValueError: return None return model.objects.get(pk=object_id)

Me dijo que no debía "responder" a las respuestas de los demás, pero todavía no puedo "responder", y he estado buscando esto por un tiempo, así que espero que esto sea útil para los demás. ¡Tampoco puedo votar aún o lo haré totalmente!