I'm trying to add a custom action to the save button in the admin interface. Basically, when the user changes the form and hits the save button, I don't want to change the default save action but I want to add custom functionality. Like; getting some or all data from the form and calling an endpoint or calling an other function.
User saves -> Default save action happens -> *Custom action happens
I'm aware that I can overwrite save_model of ModelAdmin with:
class MyAdminView(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
super().save_model(request, obj, form, change)
# add custom feature <--
but I'm not really sure if this is the appropriate way to do this
Related
I'm trying to get chosen objects from affiliate_networks in Django admin when the user clicks the submit button.
When I choose one from affiliate_networks and submit it, the console prints an empty of affiliate_networks, and then I come back to the page and the chosen object is stored properly. So, I submit it again, then the console prints the chosen object. save() only receives objects that are already stored, not objects that I choose before saving.
Is there a way, that I can have save() to notice affiliate_networks to have any object chosen?
class Store(models.Model):
...
affiliate_networks = models.ManyToManyField(AffiliateNetwork, blank=True)
def save(self, *args, **kwargs):
print(self.affiliate_networks.all())
You can't do it in save() - as you have discovered, Django admin doesn't save ManyToMany objects until afterwards. You need to do it in the save_related method of ModelAdmin. See https://timonweb.com/posts/many-to-many-field-save-method-and-the-django-admin/
In admin.py:
...
class StoreAdmin(admin.ModelAdmin):
def save_related(self, request, form, formsets, change):
super(StoreAdmin, self).save_related(request, form, formsets, change)
print(form.instance.affiliate_networks.all())
...
admin.site.register(Store, StoreAdmin)
the cause of the error is simple. The admin site asks me to select or browse user when I am logged in. So, I excluded the field to hide it in the admin form. It generates the integrity error.
How do I tell django to attach the currently logged in user (in the admin area) as the creator of the object?
I have seen a few posts that require me to make use of forms.py but I want to use the default admin template. Where do I make the edits at least?
Like that:
class ObjectAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
obj.user = request.user
obj.save()
I need to add some pre- and post-save logic to my ModelAdmin, but only when the user submitted the form via the 'Save and continue editing' button and not the 'Save' button. How can I do this?
Just like overriding the normal save method, you need to override the save_model() function in your ModelAdmin, which includes the request object. From the request object you can get the POST object, which will include a '_continue' key if the user clicked the 'Save and continue button'. Example:
class MyAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, changed):
if '_continue' in request.POST:
# add your code here
return super(ServerAdmin, self).change_view(request, obj, form, changed)
As we know, After we add a new user in django admin site, page is redirected to editing profile, not user list page like other models. How to implement this in a normal model? For example I defined a model called Image and wanted to edit the image after the image had been uploaded.
Put the following function into your admin class.
django/contrib/auth/admin.py:L139
def response_add(self, request, obj, post_url_continue='../%s/'):
"""
Determines the HttpResponse for the add_view stage. It mostly defers to
its superclass implementation but is customized because the User model
has a slightly different workflow.
"""
# We should allow further modification of the user just added i.e. the
# 'Save' button should behave like the 'Save and continue editing'
# button except in two scenarios:
# * The user has pressed the 'Save and add another' button
# * We are adding a user in a popup
if '_addanother' not in request.POST and '_popup' not in request.POST:
request.POST['_continue'] = 1
return super(UserAdmin, self).response_add(request, obj, post_url_continue)
whenever I save a model in my Admin interface, it displays the usual "successfully saved message."
However, I want to know if it's possible to customize this message because I have a situation where I want to warn the user about what he just saved and the implications of these actions.
class PlanInlineFormset(forms.models.BaseInlineFormset):
def clean(self):
### How can I detect the changes?
### (self.changed_data doesn't work because it's an inline)
### and display what he/she just changed at the top AFTER the successful save?
class PlanInline(admin.TabularInline):
model = Plan
formset = PlanInlineFormset
Django (> version 1.2) uses the messages framework for admin messages. You can add additional messages using that interface. Here's an example:
from django.contrib import messages
class SomeModelAdmin(admin.ModelAdmin):
# your normal ModelAdmin stuff goes here
def save_model(self, request, obj, form, change):
# add an additional message
messages.info(request, "Extra message here.")
super(SomeModelAdmin, self).save_model(request, obj, form, change)
To detect changes to the object being saved, you should be to override the save_model method of ModelAdmin, and compare the object the method is passed to the version currently in the database. To do this in the case of inlines, you can override the save_formset method. A possible approach might look like (untested code):
class SomeModelAdmin(admin.ModelAdmin):
# your normal ModelAdmin stuff goes here
def save_formset(self, request, form, formset, change):
if not change:
formset.save()
else:
instances = formset.save(commit=False)
for instance in instances:
try:
# if you've got multiple types of inlines
# make sure your fetching from the
# appropriate model type here
old_object = SomeOtherModel.get(id=instance.id)
except SomeOtherModel.DoesNotExist:
continue
if instance.field_x != old_object.field_x:
messages.info(request, "Something Changed")
instance.save()
formset.save_m2m()
If you're using Django 1.2 or newer, the messages framework may hold the answer.
http://docs.djangoproject.com/en/dev/ref/contrib/messages/