Closing a django admin add related object popup window on save - django

In the django admin, when a user successfully saves (after my clean method) a new or changed related object which was edited in a popup, I'd like the popup to close instead of going to a different view.
I believe I could use response_change or response_add to get it to go to a different view, but is there a way I can get the window to close?

Look at what the original response_change or response_add methods do: they return a piece of javascript that calls a JS method in the parent window, which closes the popup.
return HttpResponse('''
<script type="text/javascript">
opener.dismissAddAnotherPopup(window);
</script>'''
and in the parent window, have a script that has the relevant method:
function dismissAddAnotherPopup(win) {
win.close();
}
(The original version passes more parameters, so it updates the parent window with the new object, but you don't need that if you just want to close the window.)

There is a potential bug with the solution Daniel provided, see this Django ticket. That is, if you are using application/xhtml, then the window won't close if you return just the script. This bug has since been fixed though in Django.
The better way would be to add <!DOCTYPE html> tags like the current Django source:
'<!DOCTYPE html><html><head><title></title></head><body>'
'<script type="text/javascript">opener.dismissAddAnotherPopup(window, "%s", "%s");</script></body></html>' % \
# escape() calls force_unicode.
(escape(pk_value), escapejs(obj)))

Related

Show preview of image in form

I want to achieve the following in a django form, for a models.ImageField:
do not show the standard <input type="file"> button ("choose file" button)
show a preview of the current image, for already populated models
for empty (new) models, show a custom button
clicking on the image preview or the custom button will open a file dialog to select the image from the user's file system
selecting a new image replaces the custom button or the old image preview with the preview of the new image
This seems to me like a normal workflow to select images in a form, but I do not seem to find any fully working solution. All I can find involves hacking around several parts:
styling the label and hiding the standard "choose file" button: https://www.youtube.com/watch?v=4p2gTDZKS9Y
use a widget instead of the standard for forms.FileField.
I have tried to use:
class ImagePreviewWidget(Widget):
def render(self, name, value, attrs=None):
return mark_safe('<img src="/media/%s" width="100px"/>' % escape(value))
For the widget, and I am using this in the form like this:
class DesignCampaignForm(ModelForm):
brand_logo = FileField(widget=ImagePreviewWidget)
This is properly showing the preview of the existing image, but I am unable to click on it to select another file, and even if I was that would not update the preview.
Is there an already available solution for this simple use case?
I haven't been able to find a complete solution, so I have done the following:
use a widget to render a modified ClearableFileInput, rendering an image and an <input> element
style the <input> in the element with CSS, to hide it
make sure that clicking in the image triggers the hidden <input> element, wrapping the <img> in a <label> and using the for attribute
add some javascript to replace the image preview whenever the selection in the <input> element changes
whenever the selection is cleared, show the original preview
A gist can be found here.
In my final solution (not yet in the gist), I have added a button for when the image is not yet selected.
edit: Gist only works for Django before version 1.11.x.
class ClearableFileInput has since been gutted and changed

Displaying a temporary page while processing a GET request

I have a view that can take several seconds to process a GET request and render the results. I'd like to put up a temporary page that says "Processing..." while the view is doing its stuff. How can I do this?
UPDATE
I don't have any control over the link to my page. It is a link to me a third party has on their page. When they click it I run some stuff and display the results. I don't want them to have to click anything on the pages I display.
Ideally, I would like the following:
A user clicks a link to my website that is on a 3rd party website
My websites displays a "processing request" message - the user doesn't have to click anything, just wait.
After a few seconds the results are displayed.
All the user had to do was click a link once and wait for the results.
Some example code would be greatly appreciated as I am quite new to things like jQuery - if that's what I need.
Use jQuery to display the message while waiting for the view to return the result.
Place a hidden div-tag in the page containing the processing message/image.
If you submit the GET request by clicking a button you put an onclick event on the button to display the div-tag. When the view is done processing, the page will be reloaded and the target page will be displayed.
If the view is called using AJAX you can place the show/hide of the div in the ajaxStart and ajaxComplete events.
EDIT: OK since the page will be called from by a 3rd party it will complicate things a bit. I would suggest that you load the page without the data and once the page is loaded you do an AJAX GET request to retrieve the data.
You could do as follows:
Add a hidden div-tag to the page with the Progress message/image.
<div id="progress">Please wait while the page is loading.</div>
Then add the ajax GET call to the page:
$(document).ready(function () {
//Attach the ajaxStart and ajaxComplete event to the div
$('#progress').ajaxStart(function() {
$(this).show();
});
$('#progress').ajaxComplete(function() {
$(this).hide();
});
//Perform the AJAX get
$.get('/your_view/', function(data) {
//Do whatever you want with the data here
});
});
The above code has not been tested but it will give you an idea.
UPDATE
I would suggest that you return a JSON object or similar from your view:
companies = Company.objects.filter(name__istartswith=companyname)
results = [{'value': company.name, 'id':company.id} for company in companies ]
json = simplejson.dumps(results)
return HttpResponse(json, mimetype='application/json')
You can also use the getJSON() method instead of get() in jQuery.
very simple example:
<script>
showProcessingMessage = function() {
$("body").append('<div id="style_me_as_message">processing request</div>');
}
$("body").on('click', "a.slow", showProcessingMessage);
</script>
<a class="slow" href="/slow-response-page/">show slow page</a>

JQuery - DatePicker not working in popup forms

DatePicker is not working in a popup form, what could I've done wrong?
The form is in a .php format and is triggered by this javascript function below:
function popitup_request(url, ar){
var f = document.forms[0];
if(ar==""){
alert("Please choose at least one record.");
return false;
}
newwindow=window.open(url, 'name', 'toolbar=0,location=0,directories=0,status=1,menubar=0,scrollbars=1,resizable=0,
width=570,height=280');
if (window.focus) {
newwindow.focus()
}
newwindow.moveTo(screen.availWidth/2-(500/2),screen.availHeight/2-(300/2));
}
the form loads but when you click on the icon-trigger nothing happens.
I already tested including the jquery-1.7.1.js on both main.php and popup.php.
I assume you bind the Datepicker widget to the form elements in your main view. Since popup is loaded later (on popitup_request), the date fields on that form will not be bound to datepicker.
Include the datepicker js and css only once, in your main view. Add a small javascript to the bottom of your popup form, something along the lines of
<script type="text/javascript">
$("input.date").datepicker();
</script>
Btw, your code does not reflect best practices in a number of ways (pixel based layout, magic numbers, mixing native Javascript and jQuery though it's not needed). I'd suggest you go through both a Javascript and a jQuery tutorial to see suggested patterns and good examples for enhancing web pages with Javascript.

Django Flowplayer overlay does not submit form

I am trying to use flowplayer's overlay to load an external page that has a django form built in.
However the overlay loads the page but the submit button simply refreshes the page.
How do i actually submit the values entered in the form?
<script src="http://cdn.jquerytools.org/1.2.5/full/jquery.tools.min.js"></script>
<script>
$(function() {
// if the function argument is given to overlay,
// it is assumed to be the onBeforeLoad event listener
$("a[rel]").overlay({
mask: {
color: '#ebecff',
loadSpeed: 200,
opacity: 0.9
},
effect: 'apple',
closeOnClick: false,
onBeforeLoad: function() {
// grab wrapper element inside content
var wrap = this.getOverlay().find(".contentWrap");
// load the page specified in the trigger
wrap.load(this.getTrigger().attr("href"));
}
});
});
</script>
<div class="bananas">launch</div>
my view boom has a model form.
Without seeing the actual view code, it's hard to give a helpful answer. In the future, please be sure to do so...
If you don't have the overlay programmed to redirect to the page, then submitting it to that same url might process/save the data without you noticing. Is the data being saved, or does absolutely nothing happen when you click 'submit'?
Generally, this is how it works: you need to be posting to a url, defined in urls.py, that points to a view function in your views.py. (These names are merely convention, and can be called whatever you like) You mentioned that you have a view named 'boom': is it defined in your urls.py like this?
url(r'^path/to/boom/$', 'model.views.boom',),
Check that this is defined and that your form is posting to it.
The view must then contain logic to process the request and return a response. Posting to that url will transfer a cleaned_data dictionary of form variables that can be accessed over the field names defined in the form. It looks like this: x = form.cleaned_data[x]. Check the form for its validity with form.is_valid(), and then do your processing. This can involve saving objects, running arbitrary code, whatever you wish.
To find out more, be sure to read the excellent documentation.

Adding an extra button to one object in django admin

I hope this hasn't been asked and I just missed it, but I searched a bunch and couldn't find anything.
I'm adding an extra save button to the django admin when adding or changing an object. Doing that is fairly easy. I just overrode the submit_line.html to add the extra button and then overrode the save_model function to check for the name of that button. It works great.
My problem is that I only need this button to appear for one particular object... not all of them. I looked in change_form.html to see how it knows what object it is dealing with and found {{ opts.module_name }}, but it doesn't seem to be accessible in submit_line.html. I tried printing it out and nothing showed up.
I also thought about hacking save_as (not very graceful, but I don't really care for this particular project), but that button only shows up on change.. not on add, so that won't work.
Does anyone know how to detect what object I'm working with in submit_line.html? Or any other way of doing this?
Thanks!
You can do it using javascript like this:
/static/js/useful.js
$(document).ready(function ($) {
$('input[name="_addanother"]').before('<input type="submit" name="_use" value="Useful functionality"/>');
});
and in your ModelAdmin add:
class MyModelAdmin(admin.ModelAdmin):
class Media:
js = ('/static/js/useful.js',)
You should be able to access the original object in change_view's context through original. For example {{ original.id }} should print its id!