I have created an override of changelist_view so that after the save button is hit on an editable list in the admin, the editable list is turned off as follows:
def changelist_view(self,request,extra_context=None):
if request.POST.has_key("_save"):
self.list_editable = []
return super(InventoryAdmin, self).changelist_view(request, extra_context=None)
Everything is working except the data is not being saved. I am fairly new to Django, but I assume the:
super(InventoryAdmin, self).changelist_view(request, extra_context=None)
is supposed to call the original changelist_view function so that the data still gets saved, but it's not working. How do I properly call the original changelist_view function so that it saves the changes to the data?
Because you are essentially disabling list_editable before you call the admin's own changelist_view, it is skipping the saving of any changes.
See the appropriate code here in the Django docs:
https://github.com/django/django/blob/master/django/contrib/admin/options.py#L1270
You will see that when self.editable is empty, it doesn't do the bulk update.
Add 'action_checkbox' in the list_display as the first parameter. For
example:
self.list_display = ('action_checkbox', ...)
Related
I have a formset (more specifically a generic inline formset) whose forms have an ImageField. After working around what seems to be a few Django bugs, everything is working fine, except that when I fill the blank form with a new image and click save, the page refreshes after the POST request and the new image is not there. The other fields of the form I just saved are there and are properly filled, but the image URL doesn't show up. The database record is saved correctly and if I simply refresh the page, the image shows up correctly. But I can't figure out how to return from the POST with all the newly saved information without having to refresh the page an extra time.
In case it's relevant, for this ImageField I am using a custom Storage class which handles saving the image in a remote server through an API.
A workaround that solves the problem but which in my opinion shouldn't be necessary:
class ProductImagesView(View):
...
def post(self, request, id):
product = get_object_or_404(Product.objects.by_id(id))
image_formset = ProductImageInlineFormset(
request.POST, request.FILES, instance=product)
if image_formset.is_valid():
image_formset.save()
image_formset = ProductImageInlineFormset(instance=product) # Workaround
return render(...)
You can find more details about my code in this other question:
Django BaseGenericInlineFormSet forms not inheriting FormSet instance as form instance related_object
Any idea why this is happening? Am I doing something wrong or is this a Django bug? Thanks.
UPDATE
One thing I forgot to say: the formset that shows up after saving not only has a blank Image field for the newly created Image object, it also doesn't have the extra blank form for new records that should be there. It also only appears after a refresh.
(I pass extra=1 to the generic_inlineformset_factory):
ProductImageInlineFormset = generic_inlineformset_factory(
Image, form=ProductImageForm, extra=1)
I am working with a SessionWizardView which is managing two forms. When I reload the page at the last step for instance I am back at the first step and have to type in all the fields again.
Is this the intended behaviour? If so, is it possible to get back to step I was at before I reloaded the page? Of course all the fields should be filled out accordingly.
class ManufacturingCalculatorWizard(SessionWizardView):
def get_template_names(self):
TEMPLATES = {
"blueprint": "manufacturing/forms/select_blueprint.haml",
"calculator": "manufacturing/forms/calculator.haml"
}
return [TEMPLATES[self.steps.current]]
def done(self, form_list, **kwargs):
form_data = [form.cleaned_data for form in form_list]
rcontext = RequestContext(self.request, { 'data' : calculate_manufacturing_job(form_data) })
return render_to_response('manufacturing/forms/result.haml', rcontext)
Page rendered after done method is not part of wizard, so when you reload it, django will try to redirect to first page as new session of wizard.
If you want to add last step as something like preview and confirmation page, you can add a new step with dummy form and show appropriate data using the template. To get data from previous steps you can make use of get_context_data method of view, to build context with cleaned data of previous forms.
I am writing code to open a new window inside the django admin to add a model instance and to close on save. This is very similar to the behaviour of ForeignKey field add (green plus sign) does, but without selecting the newly created model instance (because its not a foreign key field).
The code I add to make the pop-up link is:
link = '<a id="add_id_event" class="add-another" onclick="return showAddAnotherPopup(this);" href="%s?date=%s">add</a>' % ( addurl,currentdate)
where my model is called Event. I correctly add RelatedObjectLookups.js
When I try to save this model, django applies the same code it would use on a ForeignKey field and tries to activate a SelectBox which I don't have. This causes the javascript to fail before it gets to the window.close()
I've tried overriding the save_model function with
def save_model(self, request, obj, form, change):
if request.GET.get('_popup') == '1':
obj.save()
return HttpResponse('<script type="text/javascript">window.close()</script>')
This code is used but the HttpResponse call is ignored and django renders the default. e.g.
<script type="text/javascript">opener.dismissAddAnotherPopup(window, "14382", "TMC 2012\u002D02\u002D02 10:00:00 DDT2010B\u002D028");</script>
which fails because there is no destination SelectBox object.
Thanks for your help.
You'll need to override ModelAdmin.response_add. That's where the redirect is happening.
In my case, I needed to override the dismissAddAnotherPopup method, so I created a new one called dismissAddAnotherPopupWithUpdate to handle my fancy M2M widgets. Here's the code i used:
def response_add(self, request, obj, post_url_continue='../%s/'):
"""
Overriding to force the widget to update
"""
resp = super(ModelAdmin, self).response_add(request, obj, post_url_continue)
if request.POST.has_key("_popup"):
return HttpResponse('<script type="text/javascript">opener.dismissAddAnotherPopupWithUpdate(window, "%s", "%s");</script>' % \
# escape() calls force_unicode.
(escape(obj._get_pk_val()), escape(obj)))
return resp
While Cari's solution certainly works, a simple solution to this would be to specify a valid id in your <a> tag. The id is used so dismissAddAnotherPopup() can select the appropriate field after closing the window. It doesn't matter which id you specify for window.close() to work, as long as it exists.
I've posted about this problem before, but I still haven't found a solution so I'm hoping I'll have better luck this time.
I have a form that takes inputted data by the user. In another page, I am creating the identical form that the user has populated (pre-filled with that information) for editing purposes. Users will come to this page to EDIT the information they have already put in. My problem is that it isn't overwriting the instance.
def edit(request):
a = request.session.get('a', None)
if a is None:
raise Http404('a was not found')
if request.method == 'POST':
form = Name_Form(request.POST, instance=a)
if form.is_valid():
j = form.save( commit=False )
j.save()
else:
form = Name_Form( instance = a )
For this form, I'm using "unique_together" for some of the values. I'm also calling on `{{ form.non_field_errors }} in the template.
What is happening is when I make changes in the editing view, if the fields changes involves those defined in "unique_together" then an error is returned telling me that the instance already exists. Otherwise it saves a new instance. It isn't OVERWRITING.
Note that the reason i am using unique_together is that I want to prevent users from initially inputting the same form twice (before the editing stage, in the initial inputting view).
Any ideas?
EDIT: note that "a" refers to a session that includes a drop down box of all the available instances. This carried forward will indicate which instance the user wants to edit.
`
Why not do a database lookup of the model your trying to save and pull the fields from the form to the model then save the model?
Instead to store model a in session you should store it on database. Then edit it:
def edit(request, pk):
a = A.objects.get( pk = pk)
...
pk it the a identifier, you can send it to view via urls.py. I encourage to you to use POST/Redirect/GET pattern.
You can add a 'state' field on your model to control workflow (draft, valid)
You should not save objects in the session. If you really need to use a session - save a PK there and retrieve object right before giving it to Form. But the better solution is to send it in GET or POST parameters or included in url. Sessions are unreliable, data inside it can be destroyed between user's requests.
And you can retrieve value from a session in a more pythonic way:
try:
a = request.session['a']
except KeyError:
raise Http404('a was not found')
I'm wondering if the queryset manager in django-nonrel is broken, but I may just be missing something about how to use it. Here's my issue:
I've put together a simple blog using Django, but using djangoappengine. The model I use for the blog entries is called an Entry.
I have a view for deleting entries. Once an entry is deleted, it redirects to the home page, which lists all the remaining entries. The trouble is, the first time the redirect happens the entry which I just deleted remains there. If I refresh the page, it disappears from the list. The issue seems to be that even though I call Entry.objects.all() after deleting the entry, it is caching the values from earlier.
I moved the code over to a normal Django project and this bug didn't manifest, so I think it's to do with the queryset manager in django-nonrel.
I've tried doing lots of different things but I can't work out how requery the database. Here's some code for the view - I've simplified it so it doesn't even redirect, it just renders to response the entry_list with a call to Entry.objects.all(). Still the same problem.
def update_or_delete_object(request, *args, **kwargs):
"A wrapper around the generic update_object view which allows a delete button too."
if request.method == 'POST' and 'delete' in request.POST:
#If they've just clicked the delete button
object = get_object_or_404(Entry, pk=kwargs['object_id'])
object.delete()
return render_to_response('entry_list.html', {'object_list':Entry.objects.all()})
return update_object(request, *args, **kwargs)
Any ideas?