34👍
What I usually do is set the field in the model as editable=False
and then in the admin.py set the field as read-only like this,
class PersonData(BaseModel):
person = models.ForeignKey(Person, editable=False)
data = models.TextField()
Then in admin.py
class PersonDataAdmin(admin.ModelAdmin):
readonly_fields=('person',)
Hope this works!
4👍
I hit the same problem. A workaround is to define a method in the Admin class that returns the value of the readonly field that you want to display. Then use the name of the method where you would previously have used the name of the field.
e.g. rather than:
class PersonDataAdmin(admin.ModelAdmin):
readonly_fields=('person',)
use:
class PersonDataAdmin(admin.ModelAdmin):
readonly_fields=('person_method',)
def person_method(self, obj):
return obj.person
person_method.short_description = 'Person'
The short_description sets the label for the field. If you don’t set it then the field will be labelled as “Person method”
Presumably in the OPs case get_readonly_fields becomes:
def get_readonly_fields(self, request, obj=None):
if obj:
return self.readonly_fields + ('person_method',)
return self.readonly_fields
- [Django]-How to query abstract-class-based objects in Django?
- [Django]-Creating and saving foreign key objects using a SlugRelatedField
- [Django]-How to run this code in django template
3👍
You could extend ModelAdmin.get_form()
and use Field.disabled to disable the person
field, as follows:
def get_form(self, request, obj=None, change=False, **kwargs):
form = super().get_form(request, obj, change, **kwargs)
if obj:
form.base_fields['person'].disabled = True
return form
This will prevent the person
field from being modified.
However, it will still be styled as a select box, and it may still have the "change" and "add another" buttons next to it.
These buttons are added by the RelatedFieldWidgetWrapper. One way to remove them is by removing the wrapper:
...
field = form.base_fields['person']
field.disabled = True
if isinstance(field.widget, RelatedFieldWidgetWrapper):
# unwrap the widget
field.widget = field.widget.widget
Another way is to set the following widget attributes:
...
if isinstance(field.widget, RelatedFieldWidgetWrapper):
field.widget.can_add_related = False
field.widget.can_change_related = False
If you want the field to be styled as a readonly
field, you’ll need some extra work. Also see the fieldset.html template and AdminReadonlyField to understand how django admin displays foreign-key readonly_fields
.
Another approach altogether would be to implement your own ReadOnlyWidget
, similar to this, and just set form.base_fields['person'].widget = ReadOnlyWidget()
- [Django]-How can I call a custom Django manage.py command directly from a test driver?
- [Django]-How do I convert datetime.timedelta to minutes, hours in Python?
- [Django]-How to convert JSON data into a Python object?
2👍
field1 is a required field here and it is made as read only in admin screen
model.py
class ModelName(models.Model):
field1 = models.ForeignKey(
ModelA,
on_delete=models.CASCADE,
db_column='col1',
related_name='col1',
verbose_name='col1'
)
field2 = models.ForeignKey(
ModelB,
on_delete=models.CASCADE,
db_column='col2',
related_name='col2',
verbose_name='col2'
)
admin.py
@admin.register(ModelName)
class AdminClassName(admin.ModelAdmin):
fields = ('field1', 'field2')
readonly_fields = ('field1')
- [Django]-In Django, what is the most efficient way to check for an empty query set?
- [Django]-Is save() called implicitly when calling create in django?
- [Django]-Get the type of field in django template
- [Django]-Django url pattern for %20
- [Django]-Django query case-insensitive list match
- [Django]-Running "unique" tasks with celery
1👍
In Django – 4.1.3
from django.contrib import admin
from app.models import User
class UserAdmin(admin.ModelAdmin):
readonly_fields = ['last_login']
admin.site.register(User, UserAdmin)
- [Django]-Tutorial about how to write custom form fields in django?
- [Django]-Django/DRF – 405 Method not allowed on DELETE operation
- [Django]-Additional field while serializing django rest framework
0👍
I had the exact same problem of yours. Check if you are using get_form on your admin class. Somehow this was the cause of my problem.
- [Django]-Django: Display Choice Value
- [Django]-Python Requests POST doing a GET?
- [Django]-Django equivalent of PHP's form value array/associative array