Eduardo
Eduardo

Reputation: 167

How to change the ManyToManyField widget?

I'm trying to change the default ManyToManyField widget into a TextInput and make it readonly. At the same time I'm trying to display the value(s) that the ManyToManyField used to have within the TextInput, but I can't seem to manage...these are my models:

Form

class ParticipantInlineForm(forms.ModelForm):

    class Meta:
        model = Participant
        widgets = {
            'persons': forms.TextInput
        }

    def __init__(self, *args, **kwargs):
        super(ParticipantInlineForm, self).__init__(*args,**kwargs)
        instance = kwargs.get('instance')
        string = ''
        if instance:
            for person in instance.persons.all():
                string = string + str(person)
            self.fields['persons'].initial = string

Inline

class SimpleParticipantInline(admin.TabularInline):
    model = Participant
    extra = 0
    fields = ( 'persons',)
    form = ParticipantInlineForm

    def has_delete_permission(self, request, obj=None):
        return False

    def has_add_permission(self, request, obj=None):
        return False

Models

class Person(models.Model):
        name = models.CharField(max_length=25, default='',  verbose_name='Nombre')
        lastname = models.CharField(max_length=25, default='',  verbose_name='Apellido')
        phone = models.CharField(max_length=30, default='',  verbose_name='Telefono')
        email = models.CharField(max_length=30, default='',  verbose_name='Email')


        def __str__(self):            
            return self.name + ' ' + self.lastname

        class Meta:
            verbose_name = "Persona"
            verbose_name_plural = "Personas"

class Participant(models.Model):
        persons = models.ManyToManyField(Person)
        tournament = models.ForeignKey(Tournament, default='', verbose_name='Torneo')
        TEAM_NUMBER_CHOICES = (
            ('1', 'Equipo 1'),
            ('2', 'Equipo 2'),
            ('3', 'Equipo 3'),
            ('4', 'Equipo 4'),
            ('5', 'Equipo 5'),
            ('6', 'Equipo 6'),
            ('7', 'Equipo 7'),
            ('8', 'Equipo 8'),
            ('9', 'Equipo 9'),
        )
        team_number = models.CharField(max_length=2, verbose_name='Numero de Equipo', choices=TEAM_NUMBER_CHOICES, default='', blank=True)
        TEAM_FORMAT_CHOICES = (
            ('Singles 1', 'Singles 1'),
            ('Doubles 1', 'Doubles 1'),
            ('Singles 2', 'Singles 2'),
            ('Doubles 2', 'Doubles 2'),
            ('Singles 3', 'Singles 3'),
            ('Doubles 3', 'Doubles 3'),
            ('Singles 4', 'Singles 4'),
            ('Doubles 4', 'Doubles 4'),
            ('Singles 5', 'Singles 5'),
            ('Doubles 5', 'Doubles 5'),
            ('Singles 6', 'Singles 6'),
            ('Doubles 6', 'Doubles 6'),
        )
        team_format = models.CharField(max_length=9, verbose_name='Formato de Equipo', choices=TEAM_FORMAT_CHOICES, default='', blank=True)

        def __str__(self):
            string = ''
            if self.team_number and self.team_format:
                string = 'Equipo ' + self.team_number + ' ' + self.team_format
            else:
                for person in self.persons.all():
                    string = string + person.__str__() + ' '
            return string


        class Meta:
            verbose_name = "Participante"
            verbose_name_plural = "Participantes"

I changed the widget using this code, but the values are wrong. It's showing integers like 1L, 2L, 3L. I think they might be the id's...

I have also tried redefining the widget, but old ManyToManyField objects won't get there and I can't set the initial values, any help?

I just want to show the string representation of each object in the ManyToManyField as a readonly field within the Inline.

Thanks in advance!

Upvotes: 0

Views: 2275

Answers (1)

savp
savp

Reputation: 349

I know the question is 2 years old but trying to answer for others who are looking for something similar.

You can use a widget similar to ManyToManyField, SelectMultiple but just mark it as readonly and disabled. Marking these as disabled or readonly within __init__ in forms may not work. It should be done as part of Meta widgets sections.

class ParticipantInlineForm(forms.ModelForm):
    class Meta:
        model = Participant
        widgets = {
            'persons': forms.SelectMultiple(attrs={'readonly': 'True', 'disabled': 'True'})
        }

Make sure __str__ has been implemented to a meaningful text in Persons class

Since it is disabled and marked as readonly, the value cannot be changed but it displays proper string values.

Upvotes: 1

Related Questions