Django use of readonly_fields - django

I've been experimenting with the Django admin,
Can someone explain what use readonly_fields have and what difference it makes of just having the field as part of list_display and not on list_editable

The difference is that readonly_fields applies to the edit view for a single object rather than the list view for all objects.
In the list view, list_editable controls what can be edited directly from the list view, and list_display controls what model fields are displayed in the list.
In the individual edit view, readonly_fields controls which fields are displayed but not editable. All other fields will be editable through the ModelForm:
By default the admin shows all fields as editable. Any fields in this option will display its data as-is and non-editable; they are also excluded from the ModelForm used for creating and editing.

Related

Django admin class model issue

class TheList(admin.ModelAdmin):
list_display = ['name', 'age']
actions = None
I want to see a list in admin panel as readonly. If I use the below method it will show a list of objects which then need to be clicked on in order to display the name and age.
readonly_fields = ['name', 'age']
I have tried using the below admin functions which didn’t fix the problem:
has_delete_permission
has_add_permission
The list is still editable
I tried using this with list_display:
has_change_permission
that made the class not viewable in admin panel
I want it to be like list_display but readonly, is that even possible?

How can I change the display name for Django admin filter_horizontal

Assume I have a product object and category object with many-to-many relation. I want to use filter_horizontal to edit them in admin page. How can I change the text display in the form by category object 1 to the text of category except override __str__ in the model? Because I don't want to this change globally.
I try to use customer label_from_instance from ModelMultipleChoiceField class, but this will break filter_horizontal.
class ProductAdmin(admin.ModelAdmin):
filter_horizontal = ['categories']

How to extend Django Admin model readonly_fields without having to specify all model fields (but still see them)

In a Django Admin model, if I don't provide a fields or readonly_fields tuple, it will display the model's default fields.
But if I want to add a calculated field, like:
class SomeModelAdmin(admin.ModelAdmin):
readonly_fields = ('get_calculated_field',)
fields = ('get_calculated_field',)
then it will override all its fields and just display this one.
Is there a way to extend the SomeModel fields and add the calculated field on top of that, so that all of the model's existing fields don't have to be added to the tuples?
Add only the readonly_fields setting (and not the fields setting). That will cause it to include all the default fields plus the calculated one:
class SomeModelAdmin(admin.ModelAdmin):
readonly_fields = ('get_calculated_field',)
# Note: no 'fields = ...' setting here

Django ManytoManyField and widgets

I have two models, Product and Category and ManytoMany field in Product.
The Category appear as key on ProductCreate View.
I need to customize the widget and field for Categories.
I checked in Django source Fields and Widgets but I don't see a reference(class) for ManyToMany.
To what type of Field and Widget ManyToMany relationship corresponds(I presume is Charfield as save or SelectField)? Where I can find the code ? (an example to customize field/widget in this case)
A model ManyToManyField is represented as a MultipleChoiceField and the default widget is SelectMultiple But, we can customise it.
You can find it in below references.
[1]https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#field-types
[2]https://docs.djangoproject.com/en/dev/ref/forms/widgets/#setting-arguments-for-widgets
from django import forms
from . import models
class ProductForm(forms.ModelForm):
class Meta:
model = models.Post
fields = [<fields-for-your-product-form>]
categories = forms.ModelMultipleChoiceField(
queryset=models.Category.objects.all(),
widget=forms.CheckboxSelectMultiple
)
This will render checkboxes in your form but you can substitute it with your preferred widget.
I've done something similiar where I was adding tags to blog posts. I wrote a tutorial for it- goes into more detail: https://ctrlzblog.com/how-to-add-tags-to-your-blog-a-django-manytomanyfield-example/

Replace foreign key dropdown with textbox with add/edit icon - Django

Related to foreign key fields in the Django Admin, the default display
element is a drop down list box containing all of the foreign key
items from the related model. I my app it will contain thousands of items and I am looking to change the admin interface and have it use a text box instead of the populated drop down.
Looking for textbox with add/edit icon next to it, so that we dont get populated values, we just directly add or edit.
Is there any way around to achieve it.
What you are looking for is raw_id_fields
class ArticleAdmin(admin.ModelAdmin):
raw_id_fields = ("newspaper", )
By default, Django’s admin uses a select-box interface (<select>)
for fields that are ForeignKey. Sometimes you don’t want to incur
the overhead of having to select all the related instances to display
in the drop-down.
raw_id_fields is a list of fields you would like to change into an
Input widget for either a ForeignKey or ManyToManyField:
NOTE: The raw_id_fields Input widget should contain a primary key if the field is a ForeignKey or a comma separated list of values if the field is a ManyToManyField. The raw_id_fields widget shows a magnifying glass button next to the field which allows users to search for and select a value:
You can read the docs here
You can try use custom Form and realize custom Widget on this form field. (I use for this desicion 3rd party library django_select2)
from django import forms
from django_select2.forms import ModelSelect2Widget
class KeyWidget(ModelSelect2Widget):
model = ModelToKey
search_fields = ['field__icontains']
def label_from_instance(self, obj):
return u'{}'.format(obj.field)
class CustomForm(forms.ModelForm):
class Meta:
model = ModelWithKey
fields = ('foreign_key_field')
widgets = {
'foreign_key_field': KeyWidget(attrs={'style': 'width:550px'}),
}
In also you can overload Form __init__ for customize queryset of objects for choosing in this field.