Django Admin Customizing - python

I am designing an admin interface where invite mails will be sent to users. My Invitation model is ready & in my invitation admin interface I am able to see my added users for which the admin can send email invites.
now I want to customize this a bit. I want to add for each row a SEND button which will actually send an email to that user. Sending email function etc. are all ready. I am not getting as to how I can customize this admin template to add a send button. Can someone help ?? or atleast point me in the right direction...
P.S: it need not be a send button, it could be part of "action" dropdown where for the selected users I can jointly send emails.

Regarding the send button for each row, you can give your model (or ModelAdmin) a new function which returns the corresponding HTML pointing to your views (or calling corresponding AJAX functions). Just add your function to the ModelAdmin's "list_display" and make sure that HTML tags don't get escaped:
class MyModelAdmin(admin.ModelAdmin):
...
list_display = ('name', 'email', 'sender', 'send_email_html')
def send_email_html(self, obj):
# example using a javascript function send_email()
return 'Send Now' % obj.id
send_email_html.short_description = 'Send Email'
send_email_html.allow_tags = True
Regarding the use of an action, define "actions" in your ModelAdmin as a list containing your function which takes modeladmin, request, queryset as parameters:
def send_email_action(modeladmin, request, queryset):
whatever_you_want_to_do_with_request_and_queryset
send_email.short_description = 'Send email'
class MyModelAdmin(admin.ModelAdmin):
...
actions = [
send_email_action
]

My solution below is for adding the "send invite" action in admin interface
"Send Invite" action
You can refer to the django admin-actions documentation here.
Here is what your admin.py should look like:
from django.contrib import admin
from myapp.models import MyModel
from django.core.mail import send_mail
class MyModelAdmin(admin.ModelAdmin):
actions = ['send_invite']
def send_invite(self, request, queryset):
# the below can be modified according to your application.
# queryset will hold the instances of your model
for profile in queryset:
send_email(subject="Invite", message="Hello", from_eamil='myemail#mydomain.com', recipient_list=[profile.email]) # use your email function here
send_invite.short_description = "Send invitation"
admin.site.register(MyModel, MyModelAdmin)
I have not tested this code, but it is pretty much what you need. Hope this helps.

Related

Django Display latest emails to certain user in Template

My django app I have created relies heavily on emails that are sent like this:
from django.core.mail import send_mail
send_mail(
'Subject here',
'Here is the message.',
'from#example.com',
['to#example.com'],
fail_silently=False,
)
Lets say that I keep sending an email to an user's email like this:
post = get_object_or_404(Post, pk=pk)
post_title = post.title
author_of_post = post.author
post_email = author_of_post.email
send_mail(
'An User Comment on Your Post',
'''Dear User, ''' '''
Your post, ''' + post_title + ''' was comment on by an user. Want to reply and check it out?
--From the People at Site'''
,
'randomemailuser#domain.com',
[post_email],
)
Now I want to add a notifications area, where it will display all the latest emails sent to the user, in the example of above post_email. So how would I do this. To sum up, I want to have a template where an user can see the latest emails sent to their account, sort of like a notification area. Thanks.
If you want to keep track of the emails that you are sending, you will need to save this information in your database, which means introducing a model. Something like this should do the trick:
#models.py
class SentEmail(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
email_subject = models.CharField(max_length=255)
...
You can obviously attach any additional info onto this model that you want (time sent, email body etc.). Then when you send an email, you'll also want to save a model instance, e.g:
from .models import SentEmail
...
send_mail( ... ) # all the stuff you had before
SentEmail.objects.create(
email_subject="An User Comment on Your Post"
user=whoever_the_user_is
)
Then you just create a view and template to display this information the same way you would any other view.
An alternative approach
Some third party services allow you to manage all transactional emails (sendgrid, mailgun etc.), and they may provide an API for you to fetch all emails sent to a particular user. This would allow you to achieve the kind of thing you described above, but to be honest, I think the approach I suggested above would be alot simpler.

How to prevent authenticated users from making direct API request (Django rest framework)

When a Django Rest Framework Site is hosted, can authenticated users make direct request to the api .. or does CORS prevent them?
CORS states that every request that is not made from from the same origin will be blocked
provided that it is not in the "allowed hosts". (it concerns requests made from other domains and can be overcome by making the request on the server-side)
CORS will not handle requests made individually by someone if they are from their machine directly
It depends on what you mean by
can authenticated users make direct request to the api
You can always prevent someone from accessing something in the view
from django.http import HttpResponseForbidden
# But this will block them no matter wheter thy are accessing directly or not
if request.user.is_authenticated:
return HttpResponseForbidden()
But in short, yes everyone can make a request to the API directly and there is nothing wrong about it really.
EDIT : What you were really asking had nothing to do withs CORS but with DRM
What you want to do is use custom methods for certain types of requests e.g GET or POST Or more specifically have users only access specific information.
Here is a very simple way to do that
views.py (Writting your fully custom views)
#Mixins allow you to access only specific Methods like create,delete,list etc...
# mixins.CreateModelMixin and mixins.ListModelMixin will almost do for everything
from rest_framework import mixins, viewsets
#Take here as an example an API endpoint for creating users
class userCreation(mixins.ListModelMixin, mixins.CreateModelMixin, viewsets.GenericViewSet):
serializer_class = UserSerializer #Here the serializers does not event matter you can choose something random
queryset = User.objects.all()
def create(self, request, *args, **kwargs):
#Here you handle user creations
#Access POST data, validations etc
Or if you don't want to write everything by your self
Serializers.py (Just limiting the fields)
#Here is an example where you only want to check if a username or an email exists
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['username','email']
views.py
class UserUsernameView(mixins.ListModelMixin,viewsets.GenericViewSet):
serializer_class = UserSerializer
queryset = User.objects.all()

Django Allauth Signup Prevent Login

Is there anyway to prevent the Allauth Signup form from automatically logging in the User?
I found a similar post here with no answers:
prevent user login after registration using django-allauth
You get logged in because this behavior is baked into the signup view of the allauth. When the form is valid, the view calls the function called complete_signup that does two things:
Emits the user_signed_up signal
Logs a user in
To solve this, we need to leave the step 1 and replace the step 2 with a simple redirect.
Here's how this can be done:
Extend the SignupView from allauth/account/views.py and override its form_valid method like this:
class CustomSignupView(SignupView):
def form_valid(self, form):
# By assigning the User to a property on the view, we allow subclasses
# of SignupView to access the newly created User instance
self.user = form.save(self.request)
try:
signals.user_signed_up.send(
sender=self.user.__class__,
request=self.request,
user=self.user,
**{}
)
return HttpResponseRedirect(self.get_success_url())
except ImmediateHttpResponse as e:
return e.response
Haven't tested the code, but it should be working.
Wire your new view up in urls.py, so it replaces the old Signup view url.
I am using django-allauth 0.42.0
There is no need to extend the SignUp view, it can be achieved by the setting:
ACCOUNT_EMAIL_VERIFICATION = 'mandatory'
in your project settings.py file.

Ajax form handling in django admin

I have two models:
class Customer(models.Model):
(...)
class CustomerMemo(models.Model):
(...)
customer = models.ForeignKey(Customer)
text = models.TextField()
And in my admin.py
class MemoInline(admin.StackedInline):
model = CustomerMemo
class Customer(admin.ModelAdmin):
(...)
inlines = (MemoInline,)
I want to make autosave for these inline fields.
I think there should be ajax request every 30 seconds.
But now there two questons:
How to make ajax request which gets requred data from admin page?
How would be better to add admin custom view which handle this ajax request?
I've read about dajax, but I can't get how it could help me with my task.
Thanks
Redefine admin template and add a JS with some function which will gather form data with $(form).serialize() and make an ajax POST to the server. URL for POST can be admin page itself (if you don't mind overwriting the object) or you can write your own view with necesssary form and formsets. Maybe you'll also need to add value of the "Save" button to POST load.

Django admin, custom error message?

I would like to know how to show an error message in the Django admin.
I have a private user section on my site where the user can create requests using "points". A request takes 1 or 2 points from the user's account (depending on the two type of request), so if the account has 0 points the user cant make any requests... in the private user section all this is fine, but the user can also call the company and make a request by phone, and in this case I need the admin to show a custom error message in the case of the user points being 0.
Any help will be nice :)
Thanks guys
One way to do that is by overriding the ModelForm for the admin page. That allows you to write custom validation methods and return errors of your choosing very cleanly. Like this in admin.py:
from django.contrib import admin
from models import *
from django import forms
class MyForm(forms.ModelForm):
class Meta:
model = MyModel
def clean_points(self):
points = self.cleaned_data['points']
if points.isdigit() and points < 1:
raise forms.ValidationError("You have no points!")
return points
class MyModelAdmin(admin.ModelAdmin):
form = MyForm
admin.site.register(MyModel, MyModelAdmin)
Hope that helps!
I've used the built-in Message system for this sort of thing. This is the feature that prints the yellow bars at the top of the screen when you've added/changed an object. You can easily use it yourself:
request.user.message_set.create(message='Message text here')
See the documentation.
Django versions < 1.2 https://docs.djangoproject.com/en/1.4/ref/contrib/messages/
from django.contrib import messages
messages.add_message(request, messages.INFO, 'Hello world.')

Categories

Resources