Digamos que tengo lo siguiente en mi models.py
:
class Company(models.Model):
name = ...
class Rate(models.Model):
company = models.ForeignKey(Company)
name = ...
class Client(models.Model):
name = ...
company = models.ForeignKey(Company)
base_rate = models.ForeignKey(Rate)
Es decir, hay múltiples Companies
, cada uno con un rango de Rates
y Clients
. Cada uno Client
debe tener una base Rate
elegida de su padre Company's Rates
, no otro Company's Rates
.
Al crear un formulario para agregar un Client
, me gustaría eliminar las Company
opciones (ya que eso ya se ha seleccionado a través de un botón "Agregar cliente" en la Company
página) y limitar las Rate
opciones a eso Company
también.
¿Cómo hago esto en Django 1.0?
Mi forms.py
archivo actual es solo repetitivo en este momento:
from models import *
from django.forms import ModelForm
class ClientForm(ModelForm):
class Meta:
model = Client
Y el views.py
también es básico:
from django.shortcuts import render_to_response, get_object_or_404
from models import *
from forms import *
def addclient(request, company_id):
the_company = get_object_or_404(Company, id=company_id)
if request.POST:
form = ClientForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(the_company.get_clients_url())
else:
form = ClientForm()
return render_to_response('addclient.html', {'form': form, 'the_company':the_company})
En Django 0.96 pude hackear esto haciendo algo como lo siguiente antes de renderizar la plantilla:
manipulator.fields[0].choices = [(r.id,r.name) for r in Rate.objects.filter(company_id=the_company.id)]
ForeignKey.limit_choices_to
parece prometedor, pero no sé cómo pasar the_company.id
y no estoy claro si eso funcionará fuera de la interfaz de administrador de todos modos.
Gracias. (Esto parece una solicitud bastante básica, pero si debo rediseñar algo estoy abierto a sugerencias)
Respuestas:
ForeignKey está representada por django.forms.ModelChoiceField, que es un ChoiceField cuyas opciones son un modelo QuerySet. Consulte la referencia de ModelChoiceField .
Por lo tanto, proporcione un QuerySet al
queryset
atributo del campo . Depende de cómo se construya su formulario. Si crea un formulario explícito, tendrá campos nombrados directamente.Si toma el objeto ModelForm predeterminado,
form.fields["rate"].queryset = ...
Esto se hace explícitamente en la vista. No hackear.
fuente
__init__
método del formulario ?Además de la respuesta de S.Lott y como se está convirtiendo en Guru mencionado en los comentarios, es posible agregar los filtros del conjunto de consultas anulando la
ModelForm.__init__
función. (Esto podría aplicarse fácilmente a los formularios normales) puede ayudar con la reutilización y mantiene ordenada la función de visualización.Esto puede ser útil para reutilizar, por ejemplo, si necesita filtros comunes en muchos modelos (normalmente declaro una clase de formulario abstracto). P.ej
Aparte de eso, solo estoy reafirmando el material del blog de Django del cual hay muchos buenos por ahí.
fuente
Esto es simple y funciona con Django 1.4:
No necesita especificar esto en una clase de formulario, pero puede hacerlo directamente en ModelAdmin, ya que Django ya incluye este método incorporado en ModelAdmin (de los documentos):
Una forma aún más ágil de hacer esto (por ejemplo, al crear una interfaz de administración front-end a la que los usuarios pueden acceder) es subclasificar ModelAdmin y luego alterar los métodos a continuación. El resultado neto es una interfaz de usuario que SOLAMENTE les muestra contenido relacionado con ellos, mientras le permite a usted (un superusuario) ver todo.
He anulado cuatro métodos, los dos primeros hacen imposible que un usuario elimine algo, y también elimina los botones de eliminación del sitio de administración.
La tercera anulación filtra cualquier consulta que contenga una referencia a (en el ejemplo 'usuario' o 'puercoespín' (solo como ilustración).
La última anulación filtra cualquier campo de clave externa en el modelo para filtrar las opciones disponibles al igual que el conjunto de consultas básico.
De esta manera, puede presentar un sitio de administración frontal fácil de administrar que permita a los usuarios meterse con sus propios objetos, y no tiene que acordarse de escribir los filtros específicos de ModelAdmin que mencionamos anteriormente.
eliminar botones 'borrar':
evita el permiso de eliminación
filtra los objetos que se pueden ver en el sitio de administración:
filtra las opciones para todos los campos de clave externa en el sitio de administración:
fuente
Para hacer esto con una vista genérica, como CreateView ...
la parte más importante de eso ...
, lee mi post aquí
fuente
Si no ha creado el formulario y desea cambiar el conjunto de consultas, puede hacer lo siguiente:
¡Esto es bastante útil cuando usa vistas genéricas!
fuente
Entonces, realmente he tratado de entender esto, pero parece que Django todavía no lo hace muy sencillo. No soy tan tonto, pero no puedo ver ninguna solución (algo) simple.
En general, me parece bastante feo tener que anular las vistas de administrador para este tipo de cosas, y cada ejemplo que encuentro nunca se aplica por completo a las vistas de administrador.
Esta es una circunstancia tan común con los modelos que hago que me parece terrible que no haya una solución obvia para esto ...
Tengo estas clases:
Esto crea un problema al configurar el administrador para la empresa, ya que tiene líneas en línea tanto para el contrato como para la ubicación, y las opciones de m2m del contrato para la ubicación no se filtran adecuadamente según la empresa que está editando actualmente.
En resumen, necesitaría alguna opción de administrador para hacer algo como esto:
En última instancia, no me importaría si el proceso de filtrado se colocó en la base CompanyAdmin, o si se colocó en ContractInline. (Colocarlo en línea tiene más sentido, pero hace que sea difícil hacer referencia al Contrato base como 'auto').
¿Hay alguien por ahí que sepa algo tan sencillo como este atajo tan necesario? Cuando creé administradores de PHP para este tipo de cosas, ¡esto se consideraba una funcionalidad básica! De hecho, siempre fue automático, ¡y tenía que ser desactivado si realmente no lo deseaba!
fuente
Una forma más pública es llamando a get_form en las clases de administrador. También funciona para campos que no son de base de datos. Por ejemplo, aquí tengo un campo llamado '_terminal_list' en el formulario que se puede usar en casos especiales para elegir varios elementos de terminal de get_list (request), y luego filtrar según request.user:
fuente