What is the correct way to pass context to a playwright function when using python django as the basis for a webapp?
I've got a web app that I built first with Flask, then totally rebuilt with Django, to get advantage of the admin interface. It builds a flyer for a kids football match, using the context to overlay on a background image via css absolute position. Once the coach is happy with the image, a button calls a Generate function, which opens a browser with playwright and passes the session data to recreate the image and allow the coach to download it.
When the coach is viewing the image the text fields are populated from the context. this all works fine.
def image(request):
... some other bits ...
for key in request.session.keys():
context[key] = request.session[key]
return render(request, 'coaches/image.html', context)
this is an example from the template that shows how the text is added from context. I'm using Django Template engine.
{% for player in squad %}
<td>
<span class="playernumber">{{ player.number }}</span>
<span class="playerfirstname">{{ player.first }}</span>
<span class="playerlastname">{{ player.last }}</span>
</td>
{% if forloop.counter|divisibleby:2 %}
</tr>
<tr>
{% endif %}
{% endfor %}
the same template code doesnt work when the playwright browser view is invoked. the view is fine, the template is fine, but calling the variables from context doesnt work.
This is down to the different way it works. With the playwright function, you pass the whole session.
def generate(request):
session_data = {
"name": "mysite",
"value": request.COOKIES.get("mysite"),
"url": request.META['HTTP_HOST']
}
target_url = request.META['HTTP_HOST'] + "/coaches/image"
image_bytes = take_screenshot_from_url(target_url, session_data)
with the playwright function looking like this. (I followed this article real python building the code formatter, to work out if this pattern does what I want).
def take_screenshot_from_url(url, session_data):
with sync_playwright() as playwright:
webkit = playwright.webkit
browser = webkit.launch()
browser_context = browser.new_context(device_scale_factor=2)
browser_context.add_cookies([session_data])
page = browser_context.new_page()
page.goto(url)
screenshot_bytes = page.locator("#squad-image").screenshot()
browser.close()
return screenshot_bytes
Inside the template, the variables just arent populated. I've worked out that the session_data variable contains a key value, which is where my session variables actually live. but I'm unsure of the correct way to address them.
I've tried all sorts of things, including serializing/deserializing, creating a dict and passing that, even just passing one variable.
I'm aware ive probably got a fundamental mistake in how i understand whats going on here, would appreciates suggestions on what to read. I've tried taking this back to basics and it works, i think the flaw is in how i understand the difference between Django session storing it in cookies and Flask not doing. Then how to build the call to the playwright view with the actual cookie.
Fixed in the end very simply by correcting an error with the url. I'd been massively overthinking this, but it was down to not having checked if the url was correct. i had two issues with it as initially I adjusted it to https. but of course running the development server, you're running http.
so this was the only real change needed.
...
"url": f"http://{request.META['HTTP_HOST']}/"
}
I now need to find a session/request variable whoch contains the full url, as HTTP_HOST doesnt include the protocol and obviously this is important in the dev env.