Sql 使用原始文件名上传web2py

Sql 使用原始文件名上传web2py,sql,factory,web2py,Sql,Factory,Web2py,我想用SQL.factory()上传文件 我只想保留原始文件名 我的代码目前是 form = SQLFORM.factory( Field('file_name', requires=IS_NOT_EMPTY()), Field('file', 'upload',uploadfolder=upload_folder)) if form.accepts(request.vars, session): #.process().accepted: response.flash

我想用SQL.factory()上传文件 我只想保留原始文件名 我的代码目前是

form = SQLFORM.factory(
    Field('file_name', requires=IS_NOT_EMPTY()),
    Field('file', 'upload',uploadfolder=upload_folder))
if form.accepts(request.vars, session):  #.process().accepted:
    response.flash = u'File uploaded'
    session.your_name = form.vars.file_name
    session.filename = request.vars.file 
elif form.errors:
    response.flash = 'form has errors'
return dict(form=form)
我猜session.filename=request.vars.file就是您设置文件名的地方。为什么要获取自动生成的文件名no_data.smth.23u8o8274823zu4i2.smth


谢谢

首先,
request.vars.file
是一个Python
cgi.FieldStorage
对象,因此
session.filename=request.vars.file
应该会导致错误
request.vars.file.file
是实际的文件对象,
request.vars.file.filename
是上载文件的原始名称

当您通过上载字段上载文件时,web2py会自动生成一个新名称,格式为“table_name.field_name.random_id.b16encoded_original_filename.extension”。这样做是为了防止目录遍历攻击并启用下载机制(需要知道表名和字段名)。对于SQLFORM.factory,没有数据库表名,因此它默认为“no_table”表名

您显示的代码实际上不应生成类似“no_data.smth.23u8o8274823zu4i2.smth”的文件名。该文件名意味着您已明确告知
SQLFORM.factory
使用“no_data”(通过其
table_name
参数)的表名,并且上载字段名为“smth”。(上面的代码将生成一个以“no_table.file”开头的文件名。)

注意,web2py会自动获取上传文件的原始名称,并将其编码(使用b16encode)为新文件名(然后在使用内置下载机制时对原始文件名进行解码)。原始文件名的格式为.vars.file.filename。因此,您根本不需要用户输入文件名。但是,如果要使用户输入可能与实际文件名不同的文件名,然后使用用户输入的文件名,则可以在创建表单之前添加以下内容:

if 'file' in request.vars and request.vars.file_name:
    request.vars.file.filename = request.vars.file_name
这将把上传文件的文件名重新分配给用户输入的值,然后web2py将用户输入的文件名编码为新文件名。但是,请注意,web2py依赖文件扩展名在下载时适当地设置HTTP头,因此您可能需要添加一些逻辑以获得原始文件扩展名,以防用户无法输入。

所以我这样做了:) 这是我的密码

import os
upload_folder ='C:\\Python27\\web2py'
sl = "\\"
path = upload_folder + sl

def display_form():

     form = SQLFORM.factory(
        Field('file_name', requires=IS_NOT_EMPTY()),
        Field('file', 'upload',uploadfolder=upload_folder))


     if form.accepts(request.vars, session):  #.process().accepted:
        session.file_name= form.vars.file_name
        coded_name = form.vars.file 
        orig_name = request.vars.file.filename
        os.rename(path + coded_name, path + orig_name)
        response.flash = u'datoteka naložena'

    elif form.errors:
        response.flash = 'form has errors'
    return dict(form=form)
我知道这可能不是最好的解决方案,但因为它有效,我喜欢:)


谢谢Anthony

如果您只是重命名文件,这将破坏下载机制。此外,有时您可能希望使用与原始文件不同的名称保存文件。假设您有以下模型:

db.define_table("files",
Field("name", unique=True),
Field("file", "upload"))
您需要使用自定义存储和检索功能扩展上载字段:

Field("file", "upload", custom_store=store_file, custom_retrieve=retrieve_file)
这些功能只是从固定上传目录写入/读取文件:

import os
import shutil

def store_file(file, filename=None, path=None):
    path = "applications/app_name/uploads"
    if not os.path.exists(path):
         os.makedirs(path)
    pathfilename = os.path.join(path, filename)
    dest_file = open(pathfilename, 'wb')
    try:
            shutil.copyfileobj(file, dest_file)
    finally:
            dest_file.close()
    return filename

def retrieve_file(filename, path=None):
    path = "applications/app_name/uploads"
    return (filename, open(os.path.join(path, filename), 'rb'))
现在,在控制器中,您需要在数据库插入/更新完成之前修改form.vars并设置文件名。如果要保留上载文件的原始名称,则无需这样做

def validate(form):
    # set the uploaded file name equal to a name given in the form
    if form.vars.file is not None:
        form.vars.file.filename = form.vars.name
您还需要定义一个函数来下载文件,作为内置响应。下载将不起作用:

import contenttype as c

def download():
    if not request.args:
        raise HTTP(404)
    name = request.args[-1]
    field = db["files"]["file"]
    try:
        (filename, file) = field.retrieve(name)
    except IOError:
        raise HTTP(404)
    response.headers["Content-Type"] = c.contenttype(name)
    response.headers["Content-Disposition"] = "attachment; filename=%s" % name
    stream = response.stream(file, chunk_size=64*1024, request=request)
    raise HTTP(200, stream, **response.headers)
要连接这些点,您需要构建表单。在下面的示例中,我使用的是新的网格机制,它比旧的学校表单要好得多(但尚未在书中记录)

如果您不想要电网的所有幻想,等效控制器代码为:

def index():
    if len(request.args):
        form=SQLFORM(db.files, request.args[0], upload=URL("download"))
    else:
        form=SQLFORM(db.files, upload=URL("download"))

    if form.process(onvalidation=validate).accepted:
        response.flash = "files updated"

    return {"form":form}

使用request.vars.name_of_file.filename可以获得原始文件名,但如何重命名上载的文件。我应该使用os.rename吗?我正在上载不同的zip文件,因此它们必须是文件的名称。谢谢您也可以跳过
表单。接受
并自行保存文件。但是,不要对用户上传的文件执行此操作,因为您将受到目录遍历攻击。如何通过web2py设置无文件编码。问题是,我希望上传的文件以原始文件名存储在一个文件夹中,因为我有另一个脚本来处理它,文件名对文件处理很重要??正如我所说的,然后不要使用form.accepts。file对象将位于request.vars.file.file中——只需使用常规Python代码将其保存在任何地方,并以您喜欢的方式保存即可。您好,我实现了上面的代码,该代码工作正常,但“autodelete=True”不起作用。虽然该行已从数据库中删除…但物理文件仍保留。
def index():
    if len(request.args):
        form=SQLFORM(db.files, request.args[0], upload=URL("download"))
    else:
        form=SQLFORM(db.files, upload=URL("download"))

    if form.process(onvalidation=validate).accepted:
        response.flash = "files updated"

    return {"form":form}