- Author:
- colinkingswood
- Posted:
- December 10, 2014
- Language:
- Python
- Version:
- 1.6
- Score:
- 1 (after 1 ratings)
This is for situations where a ModelForm is needed on an existing object, but we want to disable ForeignKey widgets, and only use them as a display.
Usage: save the code in the top half of the example above into a file somewhere in your django project, in this example we will call it customwidget.py
The second half shows an example usage, but setting the widget and queryset in the init method of the form. If the queryset returned by the ForeignKey model (Example.objects.all() ) is small, you can omit the init code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | from django.forms import Select
from django.utils.html import format_html
from django.utils.safestring import mark_safe
from django.forms.utils import flatatt
from itertools import chain
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)
#-------------------------------------------------------------------------------------------------------------------
Example useage in in forms.py
from sequencing.customwidgets import ReadOnlySelect
class LibraryUploadFormSetForm(ModelForm):
example =forms.ModelChoiceField(queryset=Example.objects.none() , widget=ReadOnlySelect)
def __init__(self, **kwargs):
super(LibraryUploadFormSetForm, self).__init__(**kwargs)
initial = kwargs['initial']
self.fields['example'].queryset = Sample.objects.filter(pk=initial['example])
self.fields['example'].initial = initial['example']
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 10 months, 2 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 3 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
- Help text hyperlinks by sa2812 1 year, 7 months ago
Comments
Right?
#
Tested and this works (considering both corrections already mentioned in comments). I have added to that somewhat:
line 15 in django 3.2 at least now reads (check source code for build_attrs): final_attrs = self.build_attrs(attrs, extra_attrs={"name":name})
line 20 ouput now reads (with the nicer f"...{}.." syntaxe for mixt text/variables) : output = format_html(f'<input {flatatt(self.attrs)} type="text" value="{display}" disabled={True}><input type="hidden" value={value} {flatatt(final_attrs)}>')
Because this allows me the following use case in forms.py:
class WarehouseUpdateForm(ReadOnlyForms): class Meta: widgets = {"fk_terme":ReadOnlySelect(attrs={"class":"readonly"})}
E.g. in my case I'm using a "readonly" class to style form elements the user can't edit differently. In fact this way, basically any attrs you add will be passed on to your displayed input.
#
Please login first before commenting.