Here's a piece of Django admin interface's instance edition form:
How should I change the underlying admin.ModelAdmin instance to make it contain an URL, like this?
Django makes this easy. Subclass ModelAdmin, add a custom method and then tell the Admin how to use it. Here's a sample admin.py:
from django.contrib import admin
from .models import Vendor
class VendorAdmin(admin.ModelAdmin):
readonly_fields = ['example_link']
def example_link(self, obj):
return 'link text'.format(obj.get_link()) # however you generate the link
example_link.allow_tags = True
admin.site.register(Vendor, VendorAdmin)
Here's the documentation that furthers explains readonly_fields, customizing the form label text with short_description, ordering, and how you can put this custom url method on the Model or ModelAdmin.
Related
Here, by dynamic I mean, I wouldn't want to update my template in order for me to update changes. I'd want them to edit in the admin page on my production site. At first, I thought I'd create a model for "About Me" itself, but then I'd need to create a model for just one instance.
I need help with this, better ways to edit my pages dynamically on the admin site.
Perhaps you could create a model for About Me as you mentioned. Since you've highlighted that you would want to work with the django admin site, then what you could do is to set the permission for only one object to be created for that model which can be updated whenever.
For example:
models.py file.
class AboutMe(models.Model):
# With the desired fields of your choice
Now you can set the permission within the admin.py file to only allow one instance from the model to be created.
from django.contrib import admin
from .models import AboutMe
MAX_OBJECTS = 1
# Using decorator here
#admin.register(AboutMe)
class AboutMeAdmin(admin.ModelAdmin):
fields = ['..', '..', '..'] # fields you want to display on the forms
list_display = ['..', '..', '..'] # fields you want to display on the page for list on objects
# Allowing the user to only add one object for this model...
def has_add_permission(self, request):
if self.model.objects.count() >= MAX_OBJECTS:
return False
return super().has_add_permission(request)
That should be a nice fit for your situation. Also, you can read the docs to learn more about customizing django admin site.
I have a model with fields name, roll_no, birth_date
I am using the django admin's list display and list editable to have these fields displayed and edited in a list format in a single page. However, to add a new entry I have to go to the create_form page.
Is it possible to simply add new objects from the list_display page itself?
Unfortunately this feature is not available out-of-the box in the Django admin like the ModelAdmin.list_editable feature.
I'm curious to see if there are other shortcuts, but at the moment the only way I see is to customize the formset like descibed in the official Docs:
from django import forms
class MyForm(forms.ModelForm):
# customize your 'extra' forms here
class MyModelAdmin(admin.ModelAdmin):
def get_changelist_form(self, request, **kwargs):
return MyForm
And finally manually extend the changelist form template of the admin. To override a Django admin template, please follow the intructions in the Official Docs here. The template to be customized is the following folder:
.../django/contrib/admin/templates/admin/change_list.html
and you probably need to override the {% block result_list %} in that file.
NB: the customization of an admin template can be very tricky. Consider to use a CMS (like DjangoCMS) if you need to extend the user experience. The idea behind the Django admin is to make your life easier with an out-of-the-box interface for CRUDs on your DB. IMHO try to avoid complex customizations of the Django Admin if not strictly needed.
My usecase: I want to use a different DateInput. But I want to reduce code duplication. I want all forms, which don't explicitly want a different DateInput widget, to use my custom widget.
Any change to solve this without monkey patching?
Example
models.py:
class MyModel(models.Model):
date=models.DateField()
forms.py:
class MyForm(forms.ModelForm):
class Meta:
model=MyModel
The above code should use my custom widget. I don't want to change the above models.py and forms.py, since there are many.
Unfortunately, I don't think you can get this working with your exact code listed above.
Without hacking django, essentially there are 2 parts to this. The first is creating a custom form field, and the second is defaulting your custom model field to your newly created form field.
To create your custom Form Field, you could override the existing django forms.DateField and update the widget.
# form_fields.py
from django.forms import DateField
from myapp.widgets import MyWidget
class MyDateFormField(DateField):
widget = MyWidget
And then after you have your form field created, you're going to have to override the django model field to default to your new form field
# fields.py
from django.db.models import DateField
from myapp.form_fields import MyDateFormField
class MyDateField(MyDateFormField):
def formfield(self, **kwargs):
defaults = {'form_class': MyDateFormField}
defaults.update(kwargs)
return super(DateField, self).formfield(**defaults)
You would then have your custom model field, which you would need to slightly change your code to use.
from myapp.fields import MyDateField
class MyModel(models.Model):
date=MyDateField()
It's not exactly what you were asking for (have to change the model field), but hopefully this gets you in the right direction.
Create your field
Create form that will use this field by default
import this form instead of default form, when you use it
If you're using it in admin:
create your own ModelAdmin that will use your form by default
use that instead of default ModelAdmin.
I've two simple Django model classes,
models.py
from django.db import models
class ParentModel(models.Model):
small_text = models.CharField(max_length=20)
big_text = models.CharField(max_length=500)
def __str__(self):
return self.small_text
class ChildModel(models.Model):
parent = models.ForeignKey(ParentModel)
def __str__(self):
return '%s is my parent' % self.parent
admin.py
from django.contrib import admin
import models
admin.site.register(models.ChildModel)
admin.site.register(models.ParentModel)
So the default view is you see the 'small_text' in a select element in the admin section. What I'd love to be able to do is extend that so that there's another TextArea, or something else I can , underneath the select which changes as you choose a different Daddy.
I've looked into a few different ways to do this, but they all seem hella complicated for what with Django, I'd have thought should be an easy task. Any ideas?
If you're looking to be able to change ChildModel's properties while viewing the ParentModel in the admin, you should look into using an inline in the admin
If you're looking to have additional fields appear when viewing the index page in the admin for a model, then you'll want to add additional properties to the list_display property on the model's admin class.
In my flatpage admin change list page, mysite.com/admin/flatpages/flatpage/, I can see the fields:
URL
Title
Is there a way to also show the field Site? I associate my flatpages to specific sites. The bad way to do it is by going to the actual Flatpage admin source django/contrib/flatpages/admin.py and create a method which will display sites for a Flatpage on the change list page.
I am basically looking for a way to overwrite a django.contrib application on the admin side.
You don't need to edit flatpages/admin.py. Instead, create a CustomFlatPageAdmin that inherits from the default FlatPageAdmin.
You might want to create a customflatpage app for the following admin.py file, or perhaps you already have a utilities app that you can add it to.
#admin.py
from django.contrib import admin
from django.contrib.flatpages.models import FlatPage
from django.contrib.flatpages.admin import FlatPageAdmin
def get_sites(obj):
'returns a list of site names for a FlatPage object'
return ", ".join((site.name for site in obj.sites.all()))
get_sites.short_description = 'Sites'
class CustomFlatPageAdmin(FlatPageAdmin):
list_display = ('title', 'url', get_sites)
#unregister the default FlatPage admin and register CustomFlatPageAdmin.
admin.site.unregister(FlatPage)
admin.site.register(FlatPage, CustomFlatPageAdmin)