生成一个文件并在页面加载时删除它,退出时。

huangapple go评论63阅读模式
英文:

Django: Generating a file on page load and deleting it upon exit

问题

在我的Django应用中,我想要做的事情是:每当用户查看页面A时,从我的数据库中获取信息,基于这些信息生成一个图像,并将其显示给用户。由于每次查看页面时都会重新生成图像,我希望它对每个用户都是唯一的,并且在他们离开页面A转到任意页面B时删除(最好也在他们在浏览器上单击"x"时删除,但如果不行也可以)。

到目前为止,我可以生成并保存图像文件,一切都正常。我尝试了一些方法,但没有成功,无法继续前进。

我尝试过的方法:

  1. @receiver(request_finished)
@receiver(request_finished)
def handle_request_finished(sender, **kwargs):
    ... 在这里清理文件 ...

我对这个方法的问题是它发生得太快,不会在页面A上加载图片,因为图片已经被删除了。

  1. 使用一个JavaScript函数,在离开页面时触发,与我的views.py中的一个函数配对使用

template.html中:

<script>
  $(window).on('beforeunload', function () {
    $.ajax({
      url: pageLeaveUrl,  // 链接到views.py中的page_leave函数
      type: 'GET',
      async: false  // 确保请求在页面卸载之前完成
    });
  });
</script>

views.py中:

def page_leave(request):
    referer = request.META.get('HTTP_REFERER')
    
    ... 清理文件 ...

    if referer:
        return redirect(referer)
    else:
        return redirect('home')

我对这个方法的问题是referer总是首先重定向到页面A,然后再重定向到他们要去的页面B,这意味着我成功删除了生成的图像,但然后又生成了另一个图像。

  1. 我还尝试使用import django.http.FileResponse,但无法使其正常工作。

先感谢任何帮助。

编辑:

我通过在我的views.py中添加以下检查,除了方法2之外取得了进展:

def get(self, request):
    ... 初始化一些内容 ...

    if str(request.META.get('HTTP_REFERER')).__contains__("page_A"):
        ... 清理文件 ...
    else:
        ... 查看页面A时的正常操作 ...

这几乎起作用,因为在离开页面时会有另一个请求。这检查了您是否离开的页面是页面A,如果是,则会进行清理操作。我还检查了这个方法,它适用于刷新页面和退出浏览器。然而,如果我在边栏上点击一个按钮,从页面A跳转到页面A,它就不起作用。它会检测到我离开了页面A,但由于我设置的方式,不会检测到我回来了。

英文:

Something I would like to do in my Django app is: every time a user views page A, grab information from my database, generate an image based off this and display it to the user. Since I am regenerating an image each time I view the page, I would like it to be unique to each user and deleted when they leave page A to go to any arbitrary page B (and ideally when they simply click x on the browser too, but if not that's okay).

So far I can generate the image file and save it just fine. I have tried a few things unsuccessfully and can't figure out how to go forward.

Things I have tried:

  1. @receiver(request_finished)
@receiver(request_finished)
def handle_request_finished(sender, **kwargs):
    ... clean up files here ...

My issue with this one is that it happens too quickly and won't load the picture on page A because it will be deleted already.

  1. Using a JavaScript function that activates when leaving the page paired with a function in my views.py

In template.html:

&lt;script&gt;
  $(window).on(&#39;beforeunload&#39;, function () {
    $.ajax({
      url: pageLeaveUrl,  // links to page_leave function in views.py
      type: &#39;GET&#39;,
      async: false  // Ensure the request completes before page unloads
    });
  });
&lt;/script&gt;

In views.py:

def page_leave(request):
    referer = request.META.get(&#39;HTTP_REFERER&#39;)
    
    ... clean up files ...

    if referer:
        return redirect(referer)
    else:
        return redirect(&#39;home&#39;)

My issue with this one is that referer always redirects to page A first and then page B (where they are trying to go) which means I succesfully deleted the generated image, but then another is generated in its place.

  1. I also toyed around with import django.http.FileResponse but couldn't get anything working.

Thanks in advance for any help.

EDIT:

I made progress doing the following.
By adding the following check in my views.py in addition to approach 2:

def get(self, request):
    ... initialize stuff ...

    if str(request.META.get(&#39;HTTP_REFERER&#39;)).__contains__(&quot;page_A&quot;):
        ... clean up files ...
    else:
        ... normal actions upon viewing page A ...

this almost works because there is another request when leaving the page. This checks if the page that you are leaving is page A, and if it is then clean up happens. I also checked and this works for both refreshing and exiting the browser. However, it doesn't work if I click a button on my sidebar to take me to page A from page A. It detects that I'm leaving page A but because of the way I set it up, doesn't detect that I'm coming back.

答案1

得分: 0

这不是直接回答楼主的问题"如何存储和删除文件",但在我看来,这是一个更可取的替代方法。使用临时缓冲区从不真正将文件存储在磁盘上。因此,在视图函数运行后,缓冲区被简单地丢弃并消失。

由于楼主在评论中提到他正在使用matplotlib,这个matplotlib文档 将帮助你找到正确的方法。

记住:你想要利用 fig.Figure。使用 matplotlib.pyplot 会导致内存泄漏。不用担心,几乎没有什么区别。

import base64
from io import BytesIO
from matplotlib.figure import Figure

def give_plot():
    # 生成图形 **不使用pyplot**。
    fig = Figure()
    ax = fig.subplots()
    ax.plot([1, 2]) # &lt;-- 用你的绘图逻辑替换这一行
    # 将其保存到临时缓冲区。
    buf = BytesIO()
    fig.savefig(buf, format="png")
    # 将结果嵌入到HTML输出中。
    data = base64.b64encode(buf.getbuffer()).decode("ascii")
    return f"<img src='data:image/png;base64,{data}' />"
# views.py
def yourview(request):
    # [...]
    context = {}
    context["plot_div"] = give_plot()  # 这里你可以传递数据给这个函数
    return render(request, 'app/my_template.html', context=context)
<!--my_template.html-->
{% autoescape off %}
  {{ plot_div }}
{% endautoescape %}
英文:

This is not the direct answer to OP's question "how to store and delete files", but is a in my opinion even preferable alternative. Using a temporary buffer never "really" stores the file on disk. So after the view function ran, the buffer is simply dropped and gone.

Since OP said in the comments that he is using matplotlib this piece of matplotlib documentation will bring you on track.

Remember: You want to utilize fig.Figure. The use of matplotlib.pyplot results in memory leaks. Don't worry, there is almost no difference.

import base64
from io import BytesIO
from matplotlib.figure import Figure

def give_plot():
    # Generate the figure **without using pyplot**.
    fig = Figure()
    ax = fig.subplots()
    ax.plot([1, 2]) # &lt;-- replace this line for your plotting logic
    # Save it to a temporary buffer.
    buf = BytesIO()
    fig.savefig(buf, format=&quot;png&quot;)
    # Embed the result in the html output.
    data = base64.b64encode(buf.getbuffer()).decode(&quot;ascii&quot;)
    return f&quot;&lt;img src=&#39;data:image/png;base64,{data}&#39;/&gt;&quot;
# views.py
def yourview(request):
    # [...]
    context = {}
    context[&quot;plot_div&quot;] = give_plot()  # here you could pass data to the fuction
    return render(request, &#39;app/my_template.html&#39;, context=context)
&lt;!--my_template.html--&gt;
{% autoescape off %}
  {{ plot_div }}
{% endautoescape %}

huangapple
  • 本文由 发表于 2023年6月13日 01:08:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/76458886.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定