2010-05-11 26 views
5

Tengo una aplicación que usa raw_id en ForeignKeyField y ManyToManyField. El administrador muestra el valor de la clave externa a la derecha del cuadro de edición.¿Cómo se muestra el valor raw_id de una relación ManyToMany en el administrador de Django?

Desafortunadamente, no funciona con ManyToMany. Revisé el código y creo que es el comportamiento normal. Sin embargo, me gustaría saber si alguien tiene un consejo fácil para cambiar este comportamiento.

Gracias de antemano

Actualización: He tratado de subclase el ManyToManyRawIdWidget pero no sé cómo decir que los raw_id_fields deben usar mi widget personalizado. formfield_overrides no parece funcionar con los campos raw_id

Respuesta

8

Finalmente, logro hacerlo funcionar.

from django.contrib.admin.widgets import ManyToManyRawIdWidget 

class VerboseManyToManyRawIdWidget(ManyToManyRawIdWidget): 
    def __init__(self, rel, attrs=None): 
     super(VerboseManyToManyRawIdWidget, self).__init__(rel, attrs) 

    def label_for_value(self, value): 
     values = value.split(',') 
     str_values = [] 
     key = self.rel.get_related_field().name 
     for v in values: 
      try: 
       obj = self.rel.to._default_manager.using(self.db).get(**{key: v}) 
       str_values += [escape(u'%s' % obj)] 
      except self.rel.to.DoesNotExist: 
       str_values += [u'???'] 
     return u'&nbsp;<strong>%s</strong>' % (u',&nbsp;'.join(str_values)) 


class MyAdmin(admin.ModelAdmin): 
    def formfield_for_dbfield(self, db_field, **kwargs): 
     if db_field.name in ('foo', 'bar'): 
      try: 
       del kwargs['request'] 
      except KeyError: 
       pass 
      kwargs['widget'] = VerboseManyToManyRawIdWidget(db_field.rel) 
      return db_field.formfield(**kwargs) 
     return super(MyAdmin,self).formfield_for_dbfield(db_field,**kwargs) 

Por desgracia, no tengo pasar una recompensa a cambio de nada ;-)

ACTUALIZACIÓN: He creado un fragmento de Django para esto: http://djangosnippets.org/snippets/2108/

0

Esto funciona para Django 1.11

from django.contrib.admin.sites import site 
from django.contrib.admin.widgets import ManyToManyRawIdWidget 
from django.core.urlresolvers import reverse, NoReverseMatch 
from django.utils.safestring import mark_safe 


class VerboseManyToManyRawIdWidget(ManyToManyRawIdWidget): 

    def label_and_url_for_value(self, value): 
     result = [] 
     for v in value: 
      key = self.rel.get_related_field().name 
      try: 
       obj = self.rel.model._default_manager.using(self.db).get(**{key: v}) 
      except (ValueError, self.rel.model.DoesNotExist): 
       return '', '' 

      try: 
       url = reverse(
        '{}:{}_{}_change'.format(self.admin_site.name, obj._meta.app_label, 
              obj._meta.object_name.lower()), 
        args=(obj.pk,)) 
      except NoReverseMatch: 
       url = '' # Admin not registered for target model. 

      result.append('<strong><a href="{}">{}</a></strong>'.format(url, str(obj))) 

     return mark_safe('; '.join(result)), '' 


class VerboseRawIdManyToManyAdminMixin: 
    def formfield_for_dbfield(self, db_field, **kwargs): 
     if db_field.name in self.raw_id_fields: 
      kwargs.pop('request', None) 
      if db_field.rel.__class__.__name__ == 'ManyToManyRel': 
       kwargs['widget'] = VerboseManyToManyRawIdWidget(db_field.rel, site) 
      return db_field.formfield(**kwargs) 
     return super().formfield_for_dbfield(db_field, **kwargs) 

También existe la aplicación Django para ese propósitodjango-salmonella

Cuestiones relacionadas