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