django set ModelChoiceField "to_field_name" a múltiples columnas

Quiero proporcionar varios nombres de campo en el modelo de Django Elección de Field to_field_name

algo como

field1  = forms.ModelChoiceField(queryset=myModel.objects.all(), required=False,
                   empty_label="--------",
                   
                  to_field_name=["col1, col2"],
                 
                  widget=forms.Select(attrs={'class':'form-control'}),
        )

Tengo un modelo como

class Codes(models.Model):
     item_code    = models.CharField(max_length=50)
     item_name    = models.CharField(max_length=50)
    
    def __str__(self):
        return self.item_code + self.item_name

Ahora puedo queryset como

field1  = forms.ModelChoiceField(queryset=Codes.objects.all(), required=False,
                   empty_label="--------",
                                    
                  widget=forms.Select(attrs={'class':'form-control'}),
        )

Y conseguiré la combinación de dos campos en mi select Opciones de etiqueta

todo funciona pero cuando abro la página de edición, el cuadro selecto no muestra el valor seleccionado predeterminado

También quiero una combinación de campos porque cuando item_code repite en la base de datos, to_field_name da un error.

Pregunta hecha hace 3 años, 5 meses, 0 días - Por byteninja8245


3 Respuestas:

  • Creo que estás interpretando to_field_name mal:

    Según el sitio web de Django (Django to_field_name explicado):

    Este argumento opcional se utiliza para especificar el campo para utilizar como el valor de las opciones en el widget del campo. Asegúrese de que es un campo único para el modelo, de lo contrario el valor seleccionado podría coincidir con más de un objeto. Por defecto se establece en Ninguno, en cuyo caso se utilizará la clave principal de cada objeto...

    Lo que significa que puedes usar to_field_name para abordar el objeto del formulario en HTML. Pero no dice nada sobre múltiples to_field_name valores. Normalmente la clave principal se utiliza para abordar el objeto. Si fijas el to_field_name entonces ese campo será usado.

    Para realmente agregar datos en modelChoiceField Tienes que hacer algo así.

    class CustomForm(ModelForm):
        muscles = forms.ModelMultipleChoiceField(
                            queryset=None,
                            to_field_name='name',
                            required=False,)
    
        def __init__(self, *args, **kwargs):
            super(CustomForm, self).__init__(*args, **kwargs)
            self.fields['name'].queryset = Users.objects.all()
    

    Respondida el Dec 17, 2020 a las 08:18 - por scriptsorcerer

    Votos positivos: 0 | Votos negativos: 0

  • Para lograr lo que deseas, puedes crear un método personalizado en tu formulario que maneje la lógica de combinación de los campos item_code e item_name y use este método en el widget. Esto te permitirá mostrar la opción seleccionada correctamente en el formulario de edición.

    Aquí te dejo un ejemplo de cómo podrías hacerlo:

    python
    from django import forms
    from .models import Codes
    
    class CustomModelChoiceField(forms.ModelChoiceField):
        def label_from_instance(self, obj):
            return f"{obj.item_code} - {obj.item_name}"
    
    class CustomForm(forms.Form):
        field1 = CustomModelChoiceField(queryset=Codes.objects.all(), required=False,
                                        empty_label="--------",
                                        widget=forms.Select(attrs={'class':'form-control'}),
        )
    

    En este caso, CustomModelChoiceField hereda de ModelChoiceField y sobrescribe el método label_from_instance para combinar los campos item_code e item_name. Luego, en el formulario CustomForm, se utiliza este campo personalizado field1.

    Ahora, en tu template donde renderizas el formulario, asegúrate de pasar la instancia del objeto correspondiente al campo field1 para que el valor seleccionado se muestre correctamente al abrir la página de edición.

    Espero que esta solución sea de ayuda. ¡Déjame saber si tienes alguna otra pregunta!

    Respondida el Dec 18, 2020 a las 08:21 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • Para especificar múltiples columnas en el parámetro to_field_name de ModelChoiceField en Django, utiliza el siguiente formato:

    
    to_field_name=',,...'
    

    En tu caso, para utilizar las columnas item_code e item_name como nombres de visualización, puedes usar el siguiente código:

    python
    field1 = forms.ModelChoiceField(
        queryset=Codes.objects.all(),
        required=False,
        empty_label="--------",
        to_field_name='item_code,item_name',
        widget=forms.Select(attrs={'class': 'form-control'}),
    )
    

    Solución al problema de edición:

    El problema con el valor predeterminado que no se muestra en la página de edición se debe a que Django no puede identificar de forma única el objeto seleccionado cuando utilizas múltiples columnas en to_field_name. Para solucionar esto, puedes anular el método get_initial_for_field en tu formulario de la siguiente manera:

    python
    class MyForm(forms.ModelForm):
        field1 = forms.ModelChoiceField(
            queryset=Codes.objects.all(),
            required=False,
            empty_label="--------",
            to_field_name='item_code,item_name',
            widget=forms.Select(attrs={'class': 'form-control'}),
        )
    
        def get_initial_for_field(self, field, field_name):
            if field_name == 'field1' and self.instance.pk:
                return self.instance.item_code, self.instance.item_name
            return super().get_initial_for_field(field, field_name)
    

    Prevención de duplicados:

    Para evitar errores cuando item_code se repite en la base de datos, puedes utilizar un campo único en tu modelo Codes, como uuid, y luego utilizar ese campo como to_field_name:

    
    class Codes(models.Model):
        uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
        item_code = models.CharField(max_length=50, unique=True)
        item_name = models.CharField(max_length=50)
    
        def __str__(self):
            return self.item_code + self.item_name
    
    python
    field1 = forms.ModelChoiceField(
        queryset=Codes.objects.all(),
        required=False,
        empty_label="--------",
        to_field_name='uuid',
        widget=forms.Select(attrs={'class': 'form-control'}),
    )
    

    Respondida el Dec 18, 2020 a las 08:29 - por Gemini

    Votos positivos: 0 | Votos negativos: 0