在Django中编写自定义重定向装饰器

时间:2020-11-04 23:34:31

标签: python django

我正在尝试编写以下重定向装饰器的变体:

def permanent_redirect(url):
  
  
    def outer(f):
        @wraps(f)
        def inner(request, *args, **kwargs):
            
            f(request, *args, **kwargs)
            return HttpResponseRedirect(url if not callable(url) else url())
        return inner
    return outer

我的目标是这样使用它:

#@permanent_redirect('/dash2.html')
def generate_pdf_assembly(request):
    data = request.session['sale']
    invoice_number = data[0]['invoice_number']
    print("this is data from generate pdf assembly", data)
    #total_ht = request.session['sale'].get('NetAmount')
    rate_list = []
    for index in range(len(data)):
        rate_list.append(round(data[index]['NetAmount']/data[index]['Quantity'],1))
   
    total_ht = []
    for index in range(len(data)):
        total_ht.append(data[index]['NetAmount'])
        
    print('total_ht', total_ht)
    total_ht = sum(total_ht)
    my_company = MyCompany.objects.get(id = 1)
    
    tva = MyCompany.objects.aggregate(Sum('TVA'))['TVA__sum']
    tva_value = round(total_ht * tva,1)
    total_ttc = total_ht + tva_value
    tableau = zip(rate_list, data)
    
    context = {'data' : data, 
               'my_company' : my_company, 
               'total_ht':total_ht, 
               'tva_value':tva_value, 
               'total_ttc':total_ttc, 
               'rate_list':rate_list, 
               'tableau':tableau,
               'invoice_number':invoice_number,
               
            
             }
    print("context",context)
    
pdf = render_to_pdf(url, context)
    if pdf:
        response = HttpResponse(pdf, content_type='application/pdf')
        print("response ok")
        filename = "Melt_Invoice_{}.pdf".format(data[0]['customer_name'])
        print("filename ok")
        
        content = "inline; filename={}".format(filename)
        print("content ok")
        content = "attachment; filename={}".format(filename)
        print("content 2 ok")
        response['Content-Disposition'] = content
        print("response ok")
        return response
    else:
        print("fuck this shit")
    return HttpResponse("Not found")

尽管这种重定向很好,但是它的问题是它忽略了呈现的值或放置在视图上的通用文件。

说实话,我有点不喜欢我的游戏,我将如何修改此装饰器,使其将视图输出的内容考虑在内?

更新:我设法编写了两个版本的装饰器,但是我仍然很努力,其中一个可以很好地重定向,另一个可以很好地下载但不能重定向

重定向并下载装饰器版本1: 该用户可以毫无问题地重定向用户,但不会下载文件。

def download_and_redirect(url, view):
    def outer(f):
        @wraps(view)
        def inner(request, *args, **kwargs):
            def inner_inner(request, *args, **kwargs):
                data = request.session['sale']
                print(data)
                context = request.session['context']
                print(context)
                pdf = render_to_pdf('pdf/invoice_generator_assembly.html', context)
                if pdf:
                   response = HttpResponse(pdf, content_type='application/pdf')
                   print("response ok")
                #filename = "Melt_Invoice_{}.pdf".format(data[0]['customer_name'])
                   filename = "Melt_Invoice_{}.pdf"
                   print("filename ok")
        
                   content = "inline; filename={}".format(filename)
                   print("content ok")
                   content = "attachment; filename={}".format(filename)
                   print("content 2 ok")
                   response['Content-Disposition'] = content
                   print("response ok")
                   return response
                else:
                   print("fuck this shit")
                return HttpResponse("Not found")
         
            f(request, *args, **kwargs)
            
            return HttpResponseRedirect(url if not callable(url) else url())
        return inner
    return outer 

下载并重定向装饰器版本2: 这个下载文件很好,但是无法进行重定向:

def download_and_redirect(url, view):
    def outer(f):
        @wraps(view)
        def inner(request, *args, **kwargs):
            
                data = request.session['sale']
                print(data)
                context = request.session['context']
                print(context)
                pdf = render_to_pdf('pdf/invoice_generator_assembly.html', context)
                if pdf:
                   response = HttpResponse(pdf, content_type='application/pdf')
                   print("response ok")
                #filename = "Melt_Invoice_{}.pdf".format(data[0]['customer_name'])
                   filename = "Melt_Invoice_{}.pdf"
                   print("filename ok")
        
                   content = "inline; filename={}".format(filename)
                   print("content ok")
                   content = "attachment; filename={}".format(filename)
                   print("content 2 ok")
                   response['Content-Disposition'] = content
                   print("response ok")
                   return response
                else:
                   print("fuck this shit")
                return HttpResponse("Not found")
         
                f(request, *args, **kwargs)
            
                return HttpResponseRedirect(url if not callable(url) else url())
        return inner
    return outer


1 个答案:

答案 0 :(得分:1)

为什么不起作用?

让我们简化您的功能:

def generate_pdf_assembly(request):
    pdf = maybe_generate_a_pdf(request)
    if pdf:
        response = HttpResponse(pdf, content_type='application/pdf')
        response['Content-Disposition'] = get_content(request)
        return response
    else:
        return HttpResponse("Not found")

请注意,此函数没有副作用,生成的pdf通过返回值返回。现在看看您的装饰器。

def permanent_redirect(url):
    def outer(f):
        @wraps(f)
        def inner(request, *args, **kwargs):    
            f(request, *args, **kwargs)         # This line is the problem
            return HttpResponseRedirect(url if not callable(url) else url())
        return inner
    return outer

看看这里f(request, *args, **kwargs)会发生什么。那就是您的视图被调用的地方,并且返回的值未分配给任何东西(您不执行x = f(request, *args, **kwargs)。因此带有pdf附件的HttpResponse消失了,永远丢失了。然后您将相应地重定向

如何解决?

这不是那么直接。说实话,这取决于您要执行的操作,但看起来您要执行的操作是下载文件,然后在下载文件后将用户重定向到新页面。

如果是这种情况,那么您就无法在后端上实现此目的,并且您将需要执行一些巧妙的JavaScript来处理此问题。最好提出一个单独的问题专门解决该问题,因为它超出了此问题的范围。