Ajax form handling in django admin - python

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.

Related

Wagtail: Redirect after saving Django model

I'm trying to redirect the user to a custom HTML page after saving a BaseSiteSetting model in Wagtail 4.1.1
I'm not sure how to accomplish this, the BaseSiteSetting inherits from Django models.Model which means it's possible to override the save() function but how would I do the actual redirect without having access to the request?
Another acceptable solution would be to add an extra button in the CMS by overriding the default BaseSiteSetting HTML template but I can't seem to get that working either, except for ModelAdmin templates. I've opened a StackOverflow question about that here.
My view of the custom HTML page:
def sync(request):
return render(request, "import.html", {"WS_PROTOCOL": settings.WS_PROTOCOL})
My BaseSiteSetting model:
#register_setting
class AnonymousSuccessStoryImportSetting(BaseSiteSetting):
"""
Setting for importing anonymous success stories.
"""
file = models.FileField(
upload_to="success_story_imports/%Y/%m/%d/",
validators=[validate_file_extension],
help_text="Upload a CSV file, then click 'Save' afterwards",
blank=True,
null=True,
)
date = models.DateTimeField(auto_now_add=True)
class Meta:
verbose_name = "Importer"
I've looked around for possible solutions and found some wagtail hooks but these only apply to the Wagtail Page model, for example, after_publish_page.
It's unfortunate that there's no hook for standard Django models.
It looks to me like BaseSiteSettings is one of the models that has not been converted to use class-based views. So I think you need to monkey patch this edit method to change the 'after save' redirect here: https://github.com/wagtail/wagtail/blob/main/wagtail/contrib/settings/views.py#L121

How to use Django's DetailView (or some built-in view class) for a home page?

I'm building an app in Django and I would like to set up a home page for authenticated users.
I thought it was best to use de built-in generic.DetailView for this, given that the details I want to show in the page are those of the identified user. The thing is, this class needs to receive the id of the target entity through the URL as a decimal pk argument. However, the information about the entity, is in request.user, and I would like to avoid repeating that information so as not to show my user ids in the urls.
I would imagine that getting the request within the get_object method would do the trick, but it does not take arguments.
Is this possible? Is this a good idea? Are there any alternatives that I may be missing?
The DetailView only needs the pk or slug to fetch the object. If you override get_object then it is not required. In the get_object method, you can access the user with self.request.user.
Finally, if your view uses the logged in user, then you can use the LoginRequiredMixin to ensure that only logged in users can access the view.
from django.contrib.auth.mixins import LoginRequiredMixin
class MyDetailView(LoginRequiredMixin, DetailView):
...
def get_object(self):
return self.request.user

How to render an html template with data from view?

I am new to django. I made a form. I want that if the form is filled successfully then django should redirect to a success page showing the name entered in the form but no parameters should be present in the url itself.
I searched on the internet and the solution I got was to redirect to url with pk as a get parameter which fetches the data and shows in the view. But I don't want to pass any thing in the url itself. and some websites say that http can't redirect with post data.
Here's my views.py
class UserRegistrationView(CreateView):
model = UserForm
template_name = 'userregistration.html'
form_class = UserForm
success_url = 'success'
def get_success_url(self):
return reverse('success',kwargs = {'name' : self.object.firstName})
and here's the template to which I want to redirect:
<h2>Congratualations for registering {{name}} </h2>
Basically what I want is that if the person fill form mentioning his/her firstName as "xyz" then the redirected success page should say that "Congratulations for registering xyz"
You can use django sessions, which I believe installed by default in 1.8
Look here
# Set a session value:
request.session["fav_color"] = "blue"
# Get a session value -- this could be called in a different view,
# or many requests later (or both):
fav_color = request.session["fav_color"]
# Clear an item from the session:
del request.session["fav_color"]
You can pass your pk via session and extract your object in another view without affecting your url.
Make sure you clean up after yourself.
Let me know if more help needed.
One of the possible ways of passing data between views is via sessions. So, in your UserRegistrationView you need to override the form_valid method as shown below.
class UserRegsitrationView(CreateView):
def form_valid(self,form):
self.request.session['name'] = self.object.firstName
return super(UserRegistrationView,self).form_valid(form)
class SuccessView(TemplateView):
template_name = "success_template.html"
def get_context_data(self,**kwargs):
context = super(SuccessView,self).get_context_data(**kwargs)
context['name'] = self.request.session.get('name')
del self.request.session['name']
return context
One more thing that you can modify in your code is that you need not declare success_url if you are overriding get_success_url

django admin forms. how to skip validation?

I have some form:
class Node(Object):
title = CharField(max_length=255)
body = TextField()
in admin form there is file field (which is a dump,for example csv dump of Nodes)
and what i want to do:
if user fills "data_file" i want to skip all form validation, and create Nodes from data_file content. Otherwise i'll create Node based on "title" and "body fields"
I need help because can not find anything about my problem in django docs
There is method to create a url view, but i want to do it by django standart admin tools

Django Admin Customizing

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.

Categories

Resources