python - 在 django 模板中,如何显示存储为 BinaryField 模型字段的图像?

标签 python django

在我的 django 项目中,我使用 python 脚本抓取数据。我将所有字段临时存储在 pandas 数据框中,然后对其进行迭代以将所有信息保存在 django 模型中。我能够让它工作的唯一方法是将模型中的 png 保存为 models.BinaryField。我使用 html 模板在报告中显示模型的字段,但图像显示为“内存位于 <>”,而不是显示图像。如何显示图像?

爬行.py

# Import Libraries
import requests
from selenium import webdriver
from lxml import html
import pandas as pd
import numpy as np
from datetime import datetime
import pytz
from selenium.webdriver.chrome.options import Options

def crawl_website(product, xpath_dict):
    # Set up parameters
    base_url = 'https://www.website.com/product/{sku}/sellers'
header = {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 \
        (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36'}

product = product
product_name = product.title
map_price = product.map_price
asin = product.asin
sku = product.sku

# Retrieve Webpage
full_url = base_url.format(sku = sku)
time_stamp = pytz.utc.localize(datetime.utcnow())
page = requests.get(full_url,
                   headers = headers)
doc = html.fromstring(page.content)

# Extract Price Field
original_price = doc.xpath(xpath_dict['original_price'])

# Discount
discount = [str(100 * max(0.0, round(1-float(i) / float(map_price),2))) + '%' for i in original_price]

# MAP Violation Field
map_violation = [float(i) < float(map_price) for i in original_price]

# Extract Seller Names
seller_name = doc.xpath(xpath_dict['seller_name'])

# If a violation is found, take a screenshot
screenshot = None
if True in map_violation:
    # Screenshot of Current URL
    from selenium import webdriver
    from selenium.webdriver.chrome.options import Options

    chrome_options = Options()
    chrome_options.add_argument("--headless")
    chrome_options.add_argument("--window-size=1920,1080")

    DRIVER = 'chromedriver'
    driver = webdriver.Chrome(DRIVER, chrome_options=chrome_options)
    driver.get(full_url)
    screenshot = driver.get_screenshot_as_png()
    driver.quit()

# Extract Seller Links
seller_link = doc.xpath(xpath_dict['seller_link'])

# Create DataFrame
total_rows = len(seller_name)
if True in map_violation:
    df = pd.DataFrame({
                    'Product_Name' : np.repeat(product_name, total_rows),
                    'ASIN' : np.repeat(asin, total_rows),
                    'SKU': np.repeat(sku, total_rows),
                    'Time_Stamp': np.repeat(time_stamp, total_rows),
                    'Seller_Name': seller_name,
                    'Seller_URL': seller_link,
                    'MAP_Price' : np.repeat(map_price, total_rows),
                    'Current_Price': original_price,
                    'Discount' : discount,
                    'MAP_Violation' : map_violation,
                    'Screenshot' : np.repeat(screenshot, total_rows)
    })
else:
        df = pd.DataFrame({
                'Product_Name' : np.repeat(product_name, total_rows),
                'ASIN' : np.repeat(asin, total_rows),
                'SKU': np.repeat(sku, total_rows),
                'Time_Stamp': np.repeat(time_stamp, total_rows),
                'Seller_Name': seller_name,
                'Seller_URL': seller_link,
                'MAP_Price' : np.repeat(map_price, total_rows),
                'Current_Price': original_price,
                'Discount' : discount,
                'MAP_Violation' : map_violation
})

return(df)

View .py

import pandas as pd
from datetime import datetime
from django.shortcuts import render, redirect
from products.models import Product
from sellers.models import Seller
from sellers.models import Seller_Price
from .crawl_website import crawl_website


def crawl_prices(request):
    if request.user.is_superuser:
        products = Product.objects.order_by('-date_added')
    else: 
        products = Product.objects.order_by('-date_added').filter(client_id=request.user)

    for product in products:     

        # Crawl Website
        if product.sku:
            df = crawl_website(product, xpath_dict)
            for i in range(len(df)):
                row = df.iloc[i]

                # Create Seller Object if it doesn't exist
                seller_obj, created = Seller.objects.get_or_create(name=row['Seller_Name'])
                # Update Previous Seller_Product records 'current' to False
                Seller_Price.objects.all().filter(seller_id=seller_obj, product_id=product).update(latest_update=False)

                # Record screenshot if there is a violation
                if row['MAP_Violation']:
                    seller_price_obj = Seller_Price.objects.create(
                        seller_id=seller_obj,
                        product_id=product,
                        date_reported=row['Time_Stamp'],
                        url=row['Seller_URL'],
                        seller_price=row['Current_Price'],
                        discount=row['Discount'],
                        violation=row['MAP_Violation'],
                        violation_snapshot=row['Screenshot']
                    )  
                else:
                    seller_price_obj = Seller_Price.objects.create(
                        seller_id=seller_obj,
                        product_id=product,
                        date_reported=row['Time_Stamp'],
                        url=row['Seller_URL'],
                        seller_price=row['Current_Price'],
                        discount=row['Discount'],
                        violation=row['MAP_Violation']
                    )        
    return redirect('/admin')


from django.views.generic import View
from django.utils import timezone
from .models import *

# This passes database objects to html template for reports
class Pdf(View):
def get(self, request):
    seller_price = Seller_Price.objects.order_by('-date_reported').filter(product_id__client_id=request.user, latest_update=True)
    today = timezone.now()
    params = {
        'today': today,
        'seller_price': seller_price,
        'request': request
    }

报告.html

<!doctype html>
<html>
<head>
{% load staticfiles %}
<meta charset="utf-8">
<title>Sales Report</title>

</head>
<body>

{% for sp in seller_price %}
Seller Name: {{ sp.seller_id }}
Image: {{ sp.violation_snapshot }}      
{% endfor %}

</body>
</html>

最佳答案

我强烈建议不要使用二进制字段来保存实际文件,但如果您有有效的用途,这是我能想到的最好的办法。

假设您知道 django 模板过滤器是什么,

@register.filter(name='binary_to_image')
def encode_binary_data_to_image(binary):
    return # return your encoded binary, I would suggest base64.encode which is pretty simple

在你的模板内

<img src = "data:image/png;base64,{{objects.binary_field|binary_to_image}}">

现在您在浏览器上渲染了图像。

但我还是忍不住再说一遍,如果没有有效的真正有效理由,请不要坚持使用图像数据库。


编辑问题后,您要做什么

screenshot = driver.get_screenshot_as_png()

您可以添加或重构代码以将屏幕截图保存到媒体文件夹,例如

screenshot = driver.save_screenshot('/path/to/image/dir/file.name')

因此它会将其保存到您的图像目录中,就像 django.db.models.ImageField 一样,因此您可以从模型中读取它,例如

<img src="{{object.image_field.url}}"></img>

关于python - 在 django 模板中,如何显示存储为 BinaryField 模型字段的图像?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55886078/

相关文章:

Django 根据模型查询填充选择字段

django - View 集或序列化程序中的 DRF 创建方法

python - 要列出的 Unicode 字符串

javascript - 使用 Django 作为后端,将所选选项从一个表单传递到同一 html 页面中的另一个表单

python - 重新执行Python中for循环的当前迭代

python - dtype 对象不支持 unique 的 axis 参数

java - 有没有相当于 Python 的 Easy String Splicing 的 Java?

python - 从数据流运行 tensorflow 模型训练

python - 元类上的拦截运算符查找

python - 可以在创建时将字典传递给 django 模型吗?