tutorial how examples ejemplos create charfield and django django-models django-admin

django - how - models charfield



django admin muchos-a-muchos modelos intermedios usando a través de=y filter_horizontal (3)

Así es como se ven mis modelos:

class QuestionTagM2M(models.Model): tag = models.ForeignKey(''Tag'') question = models.ForeignKey(''Question'') date_added = models.DateTimeField(auto_now_add=True) class Tag(models.Model): description = models.CharField(max_length=100, unique=True) class Question(models.Model): tags = models.ManyToManyField(Tag, through=QuestionTagM2M, related_name=''questions'')

Todo lo que realmente quería hacer era agregar una marca de tiempo cuando se creaba una determinada relación con muchas personas. Tiene sentido, pero también agrega un poco de complejidad. Además de eliminar la funcionalidad .add () [a pesar del hecho de que el único campo que estoy agregando se crea automáticamente, por lo que técnicamente no debería interferir más con esto]. Pero puedo vivir con eso, ya que no me importa hacer el QuestionTagM2M.objects.create(question=,tag=) extra si eso significa obtener la funcionalidad de marca de tiempo adicional. Mi problema es que realmente me gustaría poder conservar mi widget de javascript filter_horizontal en el administrador. Sé que los documentos dicen que puedo usar un inline en su lugar, pero esto es demasiado difícil de manejar porque de todos modos no hay campos adicionales que estén en el inline, aparte de la clave externa de la Tag . Además, en el esquema más amplio de mi esquema de base de datos, mis objetos de Question ya se muestran como en línea en mi página de administración, y dado que Django no admite inlines anidados en la administración [todavía], no tengo forma de seleccionar etiquetas para un pregunta dada ¿Hay alguna forma de anular formfield_for_manytomany(self, db_field, request=None, **kwargs) o algo similar para permitir mi uso del widget nifty filter_horizontal y la creación automática de la columna date_added a la base de datos? Esto parece algo que django debería poder hacer de forma nativa siempre que especifique que todas las columnas en el intermedio se crean automáticamente (aparte de las claves externas) tal vez con auto_created=True ? o algo parecido


Desde https://docs.djangoproject.com/en/dev/ref/contrib/admin/#working-with-many-to-many-intermediary-models

Cuando especifica un modelo intermediario usando el argumento a través de ManyToManyField, el administrador no mostrará un widget de forma predeterminada. Esto se debe a que cada instancia de ese modelo intermediario requiere más información de la que podría mostrarse en un solo widget, y el diseño requerido para múltiples widgets variará dependiendo del modelo intermedio.

Sin embargo, puede intentar incluir explícitamente el campo de etiquetas usando fields = (''tags'',) en admin. Esto causará esta excepción de validación

''QuestionAdmin.fields'' no puede incluir las ''etiquetas'' del campo ManyToManyField porque las ''etiquetas'' especifican manualmente un modelo ''directo''.

Esta validación se implementa en https://github.com/django/django/blob/master/django/contrib/admin/validation.py#L256

if isinstance(f, models.ManyToManyField) and not f.rel.through._meta.auto_created: raise ImproperlyConfigured("''%s.%s'' " "can''t include the ManyToManyField field ''%s'' because " "''%s'' manually specifies a ''through'' model." % ( cls.__name__, label, field, field))

No creo que pueda omitir esta validación a menos que implemente su propio campo personalizado para usarlo como ManyToManyField.


Hay maneras de hacer esto

  • Según lo proporcionado por @obsoleter en el comentario a continuación : establezca QuestionTagM2M._meta.auto_created = True y lidie w / syncdb asuntos.
  • Agregue date_added campo date_added al modelo M2M del modelo de Question en models.py

    class Question(models.Model): # use auto-created M2M model tags = models.ManyToMany(Tag, related_name=''questions'') # add date_added field to the M2M model models.DateTimeField(auto_now_add=True).contribute_to_class( Question.tags.through, ''date_added'')

    Entonces podrías usarlo en el administrador de manera normal en ManyToManyField .
    En el shell de Python, use Question.tags.through para consultar el modelo M2M.

    Tenga en cuenta que si no usa South , entonces syncdb es suficiente; Si lo hace, a South no le gusta de esta manera y no congelará el campo date_added , debe escribir manualmente la migración para agregar / eliminar la columna correspondiente.

  • Personaliza ModelAdmin:

    1. No defina fields dentro de ModelAdmin personalizado, solo defina filter_horizontal . Esto evitará la validación de campo mencionada en la respuesta de Irfan.
    2. Personalice formfield_for_dbfield() o formfield_for_manytomany() para hacer que Django admin use widgets.FilteredSelectMultiple para el campo de tags .
    3. Personalice el método save_related() dentro de su clase ModelAdmin, como

def save_related(self, request, form, *args, **kwargs): tags = form.cleaned_data.pop(''tags'', ()) question = form.instance for tag in tags: QuestionTagM2M.objects.create(tag=tag, question=question) super(QuestionAdmin, self).save_related(request, form, *args, **kwargs)

  • Además, puede parchear __set__() del descriptor de campo ReverseManyRelatedObjectsDescriptor de ManyToManyField para date_added para guardar la instancia de M2M sin excepción.

Los documentos pueden haber cambiado desde que se publicaron las respuestas anteriores. Eché un vistazo al enlace django docs que mencionó @Irfan y parece ser más sencillo de lo que solía ser.

Agregue una clase en línea a su admin.py y configure el modelo a su modelo M2M

class QuestionTagM2MInline(admin.TabularInline): model = QuestionTagM2M extra = 1

configure inlines en su clase de administrador para que contenga el Inline que acaba de definir

class QuestionAdmin(admin.ModelAdmin): #...other stuff here inlines = (QuestionTagM2MInline,)

No te olvides de registrar esta clase de administrador

admin.site.register(Question, QuestionAdmin)

Después de hacer lo anterior, cuando hago clic en una pregunta, tengo el formulario para hacer todas las ediciones normales y debajo, una lista de los elementos en mi relación de m2m donde puedo agregar entradas o editar las existentes.