Search code examples
djangodjango-adminpreview

Django admin preview


I need to have "Preview" button in admin create/edit page. When user clicks on this button, form should be saved and redirects to specific url where user can see information about object he just added or edited.

So I have custom ModelAdmin class with needed for me inline formsets:

class InboundAdmin(admin.ModelAdmin, ListView):
    model = Inbound
    form = InboundForm
    change_form_template = 'admin/tour/inbound_form.html'
    inlines = [InboundTourDatesInline, InboundProgramInline, InboundFeedbackInline, InboundMedia,
               InboundTourSliderPhotoInline, InboundPriceDynamicsInline]

Template extends admin/change_form.html. This template has custom button:

<input type="submit" value="{% trans 'Preview' %}" class="default draft-submit" name="_save_as_draft" />

And this script which:

$('.draft-submit').on('click', function(){
                $.ajax({
                    type: "POST",
                    url: "{% url 'tours:inbound_draft' %}",
                    data: $("#{{ opts.model_name }}_form").serialize()
                });
            });

This is inbound_draft view:

def draft_inbounds(request):
    print('inbounds')
    form = InboundForm(request.POST or None, request.FILES or None)
    if form.is_valid():
        print('is_valid')
        form.save()
        # Here I should return specific url with pk as an attribute.
    print('not_valid')

Problem is that when I click on Preview button it saves changes but redirects me back to the list_view in admin. What is the right way to solve my problem?


Solution

  • I have found a nice solution that completely solves my problem. All you need is to override save_model(), response_change() and response_add() methods of ModelAdmin class. Here is my class in admin.py file:

    class InboundAdmin(admin.ModelAdmin, ListView):
        model = Inbound
        form = InboundForm
        change_form_template = 'admin/tour/inbound_form.html'
        inlines = [InboundTourDatesInline, InboundProgramInline, InboundFeedbackInline, InboundMedia,
                   InboundTourSliderPhotoInline, InboundPriceDynamicsInline]
    
    def save_model(self, request, obj, form, change):
        if "_draft" in request.POST:
            obj.published = False  # If it is a draft, then post should not be published
        else:
            obj.published = True
        super(InboundAdmin, self).save_model(request, obj, form, change)
    
    def response_change(self, request, obj):
        if "_draft" in request.POST:
            return HttpResponseRedirect(reverse_lazy("tours:inbound_detail", kwargs={'pk': obj.pk}))
        else:
            return super(InboundAdmin, self).response_change(request, obj)
    
    def response_add(self, request, obj, post_url_continue=None):
        if "_draft" in request.POST:
            return HttpResponseRedirect(reverse_lazy("tours:inbound_detail", kwargs={'pk': obj.pk}))
        else:
            return super(InboundAdmin, self).response_add(request, obj, post_url_continue=None)
    

    If request contains "_draft" then I redirect to needed url, else It uses default method.

    In your template you should add button for savins as a draft:

    <input type="submit" value="{% trans 'Save as a draft' %}" class="default draft-submit" name="_draft" />
    

    That's all)