Question: I have a foreign key field in my form, initialized with:

```
form=myform(intial= {'val':abc.objects.get(pk=id)})

```

I have tried the following set of codes individually to make the field "val" as a read only value.

```
form.fields['val'].widget = forms.HiddenInput()
form.fields['val'].widget.attrs['readonly'] = True
form.fields['val'].widget.attrs['disabled'] = True
form.fields['val'].widget.attrs['disabled'] = 'disabled'
form.fields['val'].widget.attrs['disabled'] = False
form.fields['val'].widget.attrs['display_only'] = True
form.fields['val'].widget.attrs['editable'] = False

```

Only `HiddenInput` worked but it didn't show the field in the form, while `disabled` showed an error. `readonly` worked on all fields except the foreign key field.

Answer: 
I did this by overriding the Select widgets render method, and changing its output. 

```
class ReadOnlySelect(Select):
    """
    This should replace the Select widget with a disabled text widget displaying the value, 
    and hidden field with the actual id
    """
    def render(self, name, value, attrs=None, choices=()):
        final_attrs = self.build_attrs(attrs, name=name)
        display = "None"
        for option_value, option_label in chain(self.choices, choices):
            if str(option_value) == (value) : 
                display = option_label 
        output = format_html('<input type=text value="%s" disabled="disabled" ><input type="hidden" value="%s"  %s> ' % (display, value, flatatt(final_attrs)))

        return mark_safe(output)

```

fuller example on Django snippets. 
<https://djangosnippets.org/snippets/10436/>
I have similar problem and I decided to use different approach. Firstly I define my own class for form, for example this way:

```
class MyForm(ModelForm):

def __init__(self, *args, **kwargs):
    super(MyForm, self).__init__(*args, **kwargs)

class Meta:
    model = YourModel
    exclude = ('foreign_key_field')

```

And then in models myModel did sth like this:

```
foreign_key_field = models.ForeignKey(KeyField)

def set_values(self, *args, **kwargs):
    foreign_key_field = kwargs.pop('foreign_key_field')

```

I define function to set fields values that are read only. I call this method
after creating form object in views.py. (after submiting form)

And at last views.py:

```
if form.is_valid():
        new_instance = form.save(commit=False)
        new_instance.set_values(
              foreign_key_field='YOUR VALUE',
              )
        new_instance.save()

```

I exclude this fields from form but after creating instance I am setting values. After setting values I save to db.