2

Django 1.9.7

class PlaceName(models.Model):
    one = ForeignKey(Place, on_delete=models.CASCADE)
    ...

class PlaceNameCreate(CreateView):
    model = PlaceName
    fields = ['one', 'name', 'since', ]    

@register.filter
def disable_one(value):
    """
    Disable selection of "one" field in case of one-to-many relations.
    """
    value = value.replace('name="one"', 'name="one" disabled')
    value = mark_safe(value)
    return value

<form method="post" action="">
    {% csrf_token %} 
    <table>
    {{ form.as_table|disable_one }}
    </table>
    <input type="submit" value="Сохранить"/>
</form>

This PlaceName is a subordinate reference book, main one is Place. From PlaceView(DetailView) I call PlaceNameCreate, transfer a signed value of Place and would not like to allow users to change it.

Well, this doesn't work. On the page for this ForeignKey there is a message "This field is required".

If I remove the disable_one filter from the template, everything works: saves the model instance successfully.

If I dig to FormMixin and there in the method get_form I can see that

dict: {'instance': None, 'data': <QueryDict: {'since': ['2'], 'csrfmiddlewaretoken': ['6NPIva2Z7XEZzuG2xgWB3sAz0N1SPqZc'], 'name': ['2']}>, 'files': <MultiValueDict: {}>, 'prefix': None, 'initial': {}}

This means that one field is empty. Not surprising that the form is not valid.

Without the filter:

dict: {'instance': None, 'data': <QueryDict: {'one': ['3'], 'since': ['3'], 'csrfmiddlewaretoken': ['6NPIva2Z7XEZzuG2xgWB3sAz0N1SPqZc'], 'name': ['2']}>, 'files': <MultiValueDict: {}>, 'prefix': None, 'initial': {}}

I checked the rendered html. The only difference - as expected - is that attribute "disabled".

Any variant would be acceptable, my way with the filter is not a dogma. I just thought it to be the easiest one.

Could you give me a hint how to achieve my current goal: the value shold be shown to the user, whereas selection of other variants is impossible.

Added later:

I tried readonly as suggested. Not working. This is the rendered html.

<!DOCTYPE html>
...
<select id="id_one" name="one" readonly>
<option value="">---------</option>
<option value="3" selected="selected">664011</option>
</select>

Well, in the browser a user can still select between two values ("---------" and "664011".

Added again

This question was considered as duplicate. But this is not. This is a pure Django question. What was suggested for me as a solution was like this: disable element, but keep the value in a hidden input. Then use JQuery. This is not what I'd like to do.

Possible solution

I just decided to deprive the user of any other choices. If there will be no better solution, this is acceptable.

def get_form(self, form_class):
    form = super(PlaceNameCreate, self).get_form(form_class)
    one = self.initial.get('one')
    choices = ((one.id, one),)
    form.fields['one'].widget = forms.Select(choices=choices)
    return form
Michael
  • 4,273
  • 3
  • 40
  • 69
  • Why not make the field readonly instead of disabled? – rnevius Jul 02 '16 at 20:40
  • Could you have a look at the "Added later" section in the question. I tried without success. – Michael Jul 02 '16 at 21:25
  • Possible duplicate of [HTML form readonly SELECT tag/input](http://stackoverflow.com/questions/368813/html-form-readonly-select-tag-input) – rnevius Jul 02 '16 at 21:36
  • Thank you for the comment. But I don't like the answer you suggested to me. I edited the question and explained why. I should either rely on widgets or discard CreateView and make my own view inheriting from View. – Michael Jul 02 '16 at 21:48
  • Try setting `blank=True, null=True` in your `ForeignKey` so when you disable the input the error "This field is required" will not show, thought enforcing on the user the completion of that field when it is enable is kinda hard... – shackra Jul 03 '16 at 02:22

2 Answers2

2

disabled input values aren't submitted with the form. From MDN:

disabled

This Boolean attribute indicates that the form control is not available for interaction. In particular, the click event will not be dispatched on disabled controls. Also, a disabled control's value isn't submitted with the form.

Instead, you should consider using readonly:

readonly

This Boolean attribute indicates that the user cannot modify the value of the control.

value = value.replace('name="one"', 'name="one" readonly')
rnevius
  • 26,578
  • 10
  • 58
  • 86
0
def get_form(self, form_class):
    """
    For one-to-many relationships.
    Deprive user of any choice. 
    """
    form = super(CreateSubordinate, self).get_form(form_class)
    one = self.initial.get('one')
    if one:
        choices = ((one.id, one),)
        form.fields['one'].widget = forms.Select(choices=choices)
    return form
Michael
  • 4,273
  • 3
  • 40
  • 69