2

So I am implementing this answer: Country/State/City dropdown menus inside the Django admin inline, but the def render piece of code needs to be redone.... I have managed to redo it, but I am struggling to find a replacement (or the correct code) for the self.render_options method (which was deprecated on 1.11) of the Widget class.

I am on Django 2.1. What should I change? Here is my code:

class StateChoiceWidget(widgets.Select):
    def render(self, name, value, attrs=None, renderer=None):
        self.choices = [(u"", u"---------")]
        if value is None:
            value = ''
            model_obj = self.form_instance.instance
            if model_obj and model_obj.country:
                for m in model_obj.country.state_set.all():
                    self.choices.append((m.id, smart_text(m)))
        else: 
            obj = State.objects.get(id=value)
            for m in State.objects.filter(country=obj.country):
                self.choices.append((m.id, smart_text(m)))

        final_attrs = self.build_attrs(attrs)
        output = ['<select%s>' % flatatt(final_attrs)]
        for option in self.choices:
            output.append('<option value="%s">%s</option>' % (option[0], option[1]))
        output.append('</select>')
        return mark_safe(''.join(output))

Original poster updated the sample code, so now it doesn't show the code in the question: see previous revision https://stackoverflow.com/revisions/52174508/1

Community
  • 1
  • 1
Walucas
  • 2,549
  • 1
  • 21
  • 44
  • 1
    For Django 2.x maybe you can use `self.options(self, name, value, attrs=None)` or you might be able to use `self.create_option(self, name, value, label, selected, index, subindex=None, attrs=None)` directly, which gets called eventually when you use the former. Check out the actualy widget code in django github repo here https://github.com/django/django/blob/master/django/forms/widgets.py#L606 – devdob Sep 04 '18 at 22:34
  • @devdob so I tried the self.options, but when I assign self.choices its not the same thing. How should I do it? – Walucas Sep 04 '18 at 22:35
  • 1
    I might have mistaken on this. The only thing I can see in django 2.x is the `self.choices` attribute which is a list, maybe you can try to append to that to add your desired options and remove the whole `self.render_options` logic? – devdob Sep 04 '18 at 23:07
  • You got me on the right path! I am updating the question. Now the problem is that when I got in, I dont know which option was previously selected, and so the result is not being stored on the DB – Walucas Sep 04 '18 at 23:34
  • 1
    Do the choices have a value attr in html set to them? If there isnt, maybe this is why its not being saved? Also, are you sure they are not being saved, or are they just not rendered as the selected option? – devdob Sep 04 '18 at 23:39
  • the issue was with the attrs variable, I was ignoring it. Tks for pointing the right direction! – Walucas Sep 05 '18 at 01:28

1 Answers1

1

So I figured out the answer. Will post it here in case someone runs into the same issue.

class StateChoiceWidget(widgets.Select):
    def render(self, name, value, attrs=None, renderer=None):
        self.choices = [(u"", u"---------")]
        if value is None or value == '':
            value = ''
            model_obj = self.form_instance.instance
            if model_obj and model_obj.country:
                for m in model_obj.country.state_set.all():
                    self.choices.append((m.id, smart_text(m)))
        else: 
            obj = State.objects.get(id=value)
            for m in State.objects.filter(country=obj.country):
                self.choices.append((m.id, smart_text(m)))

        final_attrs = self.build_attrs(attrs) 

        s = widgets.Select(choices=self.choices)
        select_html = s.render(name=name,value=value,attrs=attrs)

        return mark_safe(''.join(select_html))
Walucas
  • 2,549
  • 1
  • 21
  • 44