4

I have a simple Django App, that is hosted behind Nginx. I'm using weasyprint to produce PDF reports. weasyprint requires a base_url property to access static files.

While the below django code works fine on local machine (under dev server), I get 502 Bad Gateway error when publish it behind Nginx.

View.py

html = render_to_string('admin/enquiry/quoterequest/generate.html', {'enquiry': enquiry})

response = HttpResponse(content_type='application/pdf')

response['Content-Disposition'] = 'filename=\"Enquiry_{}.pdf'.format(enquiry.reference)
weasyprint.HTML(string=html,base_url=request.build_absolute_uri()).write_pdf(response, stylesheets=[
    weasyprint.CSS(settings.STATICFILES_DIRS[0] + '/css/print.css')])

The above code works fine (without printing images), if I remove the base_url attribute. Would appreciate your input - either how to setup nginx or retrive the base_url from Django

Nginx Config

# configuration of the server
server {
    listen      80;
    server_name 192.168.33.10;  # Vagrant IP
    root        /home/www/my_project;
    charset     utf-8;

    client_max_body_size 75M;   # max upload size

    location /media  {
        alias /home/www/my_project/assets/uploads;
    }

    location /static {
        alias /home/www/my_project/assets/static;
    }

    location / {
        proxy_pass http://localhost:8001;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }

}

print.css

@page {
  size: letter;
  margin: 1.5in .25in 1.9in .5in;

  @top-center {
    content: url("/uploads/header_footer/header.jpg");
    height: 100%;
    width: 100%;
  }

  @bottom-center {
    background-image: url("/uploads/header_footer/footer.jpg");
    background-repeat: no-repeat;
    background-position: center;
    content: "Page " counter(page);
    height: 100%;
    width: 100%;
    vertical-align: bottom;;
  }
}

This is the error message from nginx log.

upstream prematurely closed connection while reading response header from upstream, client: 192.168.33.1, server: 192.168.33.10, request: "GET /enquiry/admin/enquiry/quoterequest/view/1/ HTTP/1.1", upstream: "http://127.0.0.1:8001/enquiry/admin/enquiry/quoterequest/view/1/", host: "192.168.33.10", referrer: "http://192.168.33.10/admin/enquiry/quoterequest/"
Da CodeKid
  • 723
  • 10
  • 12

2 Answers2

1

Answering my own - but this is sort of workaround'. For so ip 192.168.33.10, and for it's base address http://192.168.33.10/media/'base_urlparameter forweasyprint` still has issues - even manually inputing the base address didn't do the trick.

This still doesn't work and return with 502 Bad Gateway

weasyprint.HTML(string=html, base_url='http://192.168.33.10/media/').write_pdf(response)

So I decided to change the template. So wherever I've an URL defined, I changed them to...

<img src="http://{{ request.META.HTTP_HOST }}{{ MEDIA_URL }}{{ myapp.mymodel.my_image }}">

and added context_instance in my View.py to get MEDIA_URL. Hopefully someone will come up with an answer for weasyprint's base_url issue.

html = render_to_string('admin/enquiry/quoterequest/generate.html', {'enquiry': enquiry}, context_instance=RequestContext(request))

response = HttpResponse(content_type='application/pdf')

response['Content-Disposition'] = 'filename=\"Enquiry_{}.pdf'.format(enquiry.reference)

weasyprint.HTML(string=html,base_url=request.build_absolute_uri()).write_pdf(response, stylesheets=[
    weasyprint.CSS(settings.STATICFILES_DIRS[0] + '/css/print.css')])
Da CodeKid
  • 723
  • 10
  • 12
0

I had a similar issue with WeasyPrint, and what I found is that base_url is only taken into account if URLs are not absolute.

My workaround was to make a custom Django template tag to translate them to file system absolute path if a truthy absolute_paths is present in the context. In the meanwhile I posted a question about my own problem scenario.

Hope this helps!

Tadeo
  • 431
  • 7
  • 11