Adding additional data to the widget output for Foreignkey fields

Let's say I have the following models ...

class Person(models.Model):
   name = models.CharField()
   specialty = models.CharField()

class Team(models.Model):
    captain = models.ForeignKey(Person)
    vice_captain = models.ForeignKey(Person)

      

and I have a form to create a command ...

class TeamForm(ModelForm):
     class Meta:
          model = Team
          widgets['vice_captain'] = MySelectWidget()

      

I also have an additional restriction on the uniform that the vice captain must have the same specialty as the captain. I have implemented validations in form clean, etc., but want the UI to "filter itself". I figured that instead of using ajax to fill / filter the field, I would add html 'data-' tags to the output of the widget, and then hide the options with javascript.

I wrote a widget (and javascript) that works with the Select widget. This is it (note that this is simplified from my actual code, but should work).

class Select_with_Data(forms.Select):
    # Not sure if this is necessary.
    allow_multiple_selected = False

    def render_option(self, selected_choices, option_value, option_label):

        # This paragraph is copied from django Select.
        option_value = force_text(option_value)
        if option_value in selected_choices:
            selected_html = mark_safe(' selected="selected"')
            if not self.allow_multiple_selected:
                # Only allow for a single selection.
                selected_choices.remove(option_value)
        else:
            selected_html = ''

        # My custom code to add data-specialty attributes to <option> tags.
        # Get the object to filter upon.
        obj = self.choices.queryset.get(pk=option_value)
        # Get the data field.
        data_field = getattr(obj, 'specialty', False)
        # If the data field has a value set, add it to the return html.
        # Need to check if the data_field has a pk (ie is a ForeignKey field), and handle it appropriately.
        if data_field:
            selected_html += ' data-{0}={1}'.format( 'specialty', str(getattr(data_field, 'pk', data_field)) )

        # This paragraph is copied from django Select.
        return format_html('<option value="{0}" {1}>{2}</option>',
                           option_value,
                           selected_html,
                           force_text(option_label))

      

But now I decided that I wanted radio buttons, not a selection list. My problem is trying to use code like the one above in the radio widget renderer fails because self.choices.queryset is not set, so I cannot access the information I need. How can I get the information I need and is this the best way to do what I want?

I even changed the main django files to see where the request disappeared. Subclass RadSelect RendererMixin. self.choices.queryset is available during init, render and get_renderer sub-functions? (is a function of the word?). The renderer for RadioSelect is RadioFieldRenderer, which subclasses ChoiceFieldRenderer. Inside its initialization and rendering, however, the queryset is gone (it sets its own self.choices, but even before that step in init, self.choices is not set).

+3


source to share


1 answer


I have discovered several different ways to achieve what I want.

1: Write your own widget that subclasses. Widget. This gives you complete control without trying to "work with" the main classes. I used this link for inspiration, https://djangosnippets.org/snippets/2589/



2: Change the selection tuple that is (value,label)

, and change it to (value,label,object)

(for example). The following link gives the code for this: http://srcmvn.com/blog/2013/01/15/django-advanced-model-choice-field/

+3


source







All Articles