Display custom message from signal in the admin - django

I have a pre-save signal listener that updates a second model. The same as this example:
Django Signals to update a different model
I'd like to let the user know that the listener succeeded in updating the model and provide some information. Normally, I would think I could use the built in messages functionality that django has. The problem is that the signal doesn't have access to 'request'. So I can't see how to use the built in Django Messages Framework.
https://docs.djangoproject.com/en/dev/ref/contrib/messages/
Is there a known method for sending a message to the user in the admin? Maybe by overriding the save() method for one of the models? (the one sending the signal, or receiving), but I don't think the save() method has access to 'request' either?
This must be something others want to do as well?

You can override save_model method in ModelAdmin. Something like this:
from django.contrib import messages
# your imports
...
# your code
def save_model(self, request, obj, form, change):
obj.user = request.user
obj.save()
# you can just call super(YourModelAdminName, self).save_model(request, obj, form, change)
messages.add_message(request, messages.INFO, 'Text of message')

Related

Django admin save() doesn't get data from ManyToManyField

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)

Django Integrity Error when adding post in a form that excludes a foreign key

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()

django post_save signal and ManyToManyField (and Django Admin)

I have a problem with a post_save function. The function is correctly triggered but the instance doesn't contains the value insereted. I checked the function using ipdb and there is nothing wrong. Simply the ManyToManyField is empty.
The code:
#receiver(post_save, sender=Supplier)
def set_generic_locations(sender, instance, **kwargs):
""" Set the generic locations for the NEW created supplier.
"""
created = kwargs.get('created')
if created:
glocations = LocationAddress.get_generic_locations()
for location in glocations:
instance.locations.add(location)
instance.save()
The field used in the instance:
locations = models.ManyToManyField(LocationAddress, blank=True)​
I don't understand why, but the locations is always empty.
I use django 1.8.8
UPDATE
The problem is the django admin. I found an explanation here: http://timonweb.com/posts/many-to-many-field-save-method-and-the-django-admin/
The code that solve the problem in the django admin
def save_related(self, request, form, formsets, change):
super(SupplierAdmin, self).save_related(request, form, formsets, change)
form.instance.set_generic_locations()
ManyToManyFields work a little bit differently with signals because of the difference in database structures. Instead of using the post_save signal, you need to use the m2m_changed signal
For manytomanyfield, you have to save first your parent object () and then add your

In Django, how to override the 'Save and continue' feature?

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)

Django: customizing the message after a successful form save

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/