I have a Django application where a user enters an e-mail address in a form, amongst the other fields that they have to fill in. In my Django admin, it displays the typed results from all these fields. What I'd like to add is a button beside the e-mail field in the admin view to send an e-mail to the entered address. How would I go about this? Would I need to edit the admin page template or model, perhaps?
You could add an boolean field "email_on_save" and a text field for the "message". When the record gets saved in the admin it calls the Model.save() method.
You extend the model.save() this way:
def save(self, *args, **kwargs):
if self.email_on_save:
send_email(self.email, self.message)
self.email_on_save = False
self.message = ""
# Call super save method
return super(MyModel, self).save(*args, **kwargs)
Related
I want to encrypt the username data before save in django auth User model, and decrypt the username data. we are using model like this
class Profile(models.Model):
user = models.OneToOneField(User,related_name='profile_data',on_delete=models.PROTECT)
Regarding this Any solution reference pls.
You can override the save method, and do the encryption logic in there. It would be executed just before saving anything in Profile Modal. Like this:
class Profile(models.Model):
user = models.OneToOneField(User,related_name='profile_data',on_delete=models.PROTECT)
def encrypt(self, to_be_encrypted_value):
# Here, you would do the logic of encrypting, and return the encrypted value.
# To be used in save method.
...
return encrypted_value
def save(self, *args, **kwargs):
self.user = self.encrypt(self.user)
super().save(*args, **kwargs)
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)
In django I have superuser and group of content editors.
When I edit model as superuser I want be able to edit all fields. And if someone logged in as editor I want to allow him to edit only specific fields.
I have done that with get_form method:
class VideoAdmin(admin.ModelAdmin):
editor_fields = ('description','description_rewrited')
def get_form(self, request, obj=None, **kwargs):
if not hasattr(request.user, 'perms_list'):
request.user.perms_list = request.user.groups.values_list('name',flat=True)
if 'video_description_rewriter' in request.user.perms_list:
print('rewrite fields to normal')
self.fields = self.normaluser_fields
return super(VideoAdmin, self).get_form(request, obj, **kwargs)
It works for me. But when I open video for editing as regular editor it changes superuser fields set to editors fields set.
Open admin model as superuser - http://joxi.ru/zAN5wWMIVjz429
Open admin model as editor - http://joxi.ru/p27LJPZiDNgeA7
Now superuser has the same fields set as editor - http://joxi.ru/L21jko5TW0ydAX
I assume that there is some kind of template caching?
You're setting self.fields to self.normaluser_fields when user is editor, but you aren't setting self.fields back to default value when user is admin. ModelAdmin objects are created on application load and they're shared between all users!
Changing fields back to default value when admin enters page won't solve problem in 100% percent. When admin and non-admin user will try to enter edit page in same time, race condition might occur. Both of them can get same fields.
Instead of rewritting get_form, you can do it simpler by rewritting get_fields method:
def get_fields(self, request):
if not hasattr(request.user, 'perms_list'):
request.user.perms_list = request.user.groups.values_list('name',flat=True)
if 'video_description_rewriter' in request.user.perms_list:
print('rewrite fields to normal')
return self.normaluser_fields
return self.fields
That method won't overwrite any values in ModelAdmin object, so change will be only visible for one user.
I'm new to django.
I'm creating simple app in which I have users enter some data and view it later. I need to make django admin show to the user only the data she enter and non of the other users data.
Is it possible to change it to multiple admin pages?
Thank you
Store a reference to a user in your model.
models.py:
from django.db import models
from django.contrib.auth.models import User
class MyModel(models.Model):
user = models.ForeignKey(User)
... (your fields) ...
Force the current user to be stored in that field (when using admin)
Force any list of these objects to be (additionally) filtered by the current user (when using admin)
Prevent other users from editing (even though they can't see the object in the list they could access its change_form directly)
admin.py:
from django.contrib import admin
from models import MyModel
class FilterUserAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
obj.user = request.user
obj.save()
def get_queryset(self, request):
# For Django < 1.6, override queryset instead of get_queryset
qs = super(FilterUserAdmin, self).get_queryset(request)
return qs.filter(created_by=request.user)
def has_change_permission(self, request, obj=None):
if not obj:
# the changelist itself
return True
return obj.user === request.user
class MyModelAdmin(FilterUserAdmin):
pass # (replace this with anything else you need)
admin.site.register(MyModel, MyModelAdmin)
If you have MyOtherModel with a foreign key "user" just subclass MyOtherModelAdmin from FilterUserAdmin in the same manner.
If you want certain superusers to be able to see anything, adjust queryset() and has_change_permission() accordingly with your own requirements (e.g. don't filter/forbid editing if request.user.username=='me').
In that case you should also adjust save_model() so that your editing doesn't set the user and thus "take away" the object from the previous user (e.g. only set user if self.user is None (a new instance)).
You'll have to save in the user to every item and query each item with that user as search criteria. You'll probably build a base model which all your other models will inherit from. To get you started take a look at row-level permissions in the admin.
I've looked at several questions here that looked similar, but none of them discussed the problem from the perspective of admin panel.
I need to check if user has permission to leave a field empty. I wanted to use request.user but I don't knot how to pass request from EntryAdmin to ModelForm. I wanted to do something like this:
class EntryAdminForm(ModelForm):
class Meta:
model = Entry
def clean_category(self):
if not self.request.user.has_perm('blog.can_leave_empty_category') and not bool(self.category):
raise ValidationError(u'You need to choose a Category!')
else:
return self.cleaned_data['category']
You could override the ModelAdmin.get_form, by adding the request as an attribute of the newly created form class (should be thread-safe).
Something along these lines:
class EntryAdmin(admin.ModelAdmin):
form = EntryAdminForm
def get_form(self, request, *args, **kwargs):
form = super(EntryAdmin, self).get_form(request, *args, **kwargs)
form.request = request
return form
Then the code in your question should work.