2011-11-04 14 views
7

quiero cargar el archivo con SQL.factory() Me gustaría simplemente para mantener el nombre de archivo original mi código es actualmenteWeb2py cargar con el nombre de archivo original

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) 

supongo session.filename = request.vars .file es donde configura el nombre del archivo. ¿Por qué aparece el nombre del archivo autogenerado no_data.smth.23u8o8274823zu4i2.smth

Gracias

Respuesta

6

En primer lugar, request.vars.file es un objeto de Python cgi.FieldStorage, por lo session.filename = request.vars.file debería dar como resultado un error. request.vars.file.file es el objeto de archivo real, y request.vars.file.filename es el nombre original del archivo cargado.

Cuando carga un archivo a través de un campo de carga, web2py genera automáticamente un nuevo nombre del formulario 'nombre_tabla.nombre_campo.número_aleatorio.b16nombre_archivo_original.extensión'. Esto se hace para evitar ataques de cruce de directorio y para habilitar el mecanismo de descarga (que necesita conocer la tabla y el nombre del campo). En el caso de SQLFORM.factory, no hay un nombre de tabla de base de datos, por lo que se establece de forma predeterminada en un nombre de tabla de 'no_table'.

El código que ha mostrado no debería generar un nombre de archivo como 'no_data.smth.23u8o8274823zu4i2.smth'. Ese nombre de archivo implica que ha indicado explícitamente SQLFORM.factory que use un nombre de tabla de 'no_data' (a través de su argumento table_name) y que el nombre del campo de carga sea 'smth'. (El código anterior generará un nombre de archivo que comience con 'no_table.file').

Nota, web2py obtiene automáticamente el nombre original del archivo cargado y lo codifica (usando b16encode) en el nuevo nombre de archivo (luego decodifica el original nombre de archivo cuando se usa el mecanismo de descarga incorporado). El nombre de archivo original también está disponible en form.vars.file.filename. Por lo tanto, no necesariamente necesita que el usuario ingrese un nombre de archivo. Sin embargo, si desea habilitar al usuario que introduzca un nombre de archivo que puede diferir de la nombre de archivo real y luego usar el nombre del archivo introducido por el usuario, se puede añadir lo siguiente antes de la creación de formularios:

if 'file' in request.vars and request.vars.file_name: 
    request.vars.file.filename = request.vars.file_name 

que se re- asigne el nombre de archivo del archivo cargado al valor ingresado por el usuario, y web2py codificará ese nombre de archivo ingresado por el usuario en el nuevo nombre de archivo. Sin embargo, tenga en cuenta que web2py depende de la extensión de nombre de archivo para configurar los encabezados HTTP de manera adecuada al momento de la descarga, por lo que es posible que desee agregar un poco de lógica para obtener la extensión de nombre de archivo original en caso de que el usuario no pueda ingresarla.

+0

con request.vars.name_of_file.filename me sale el nombre del archivo original, pero la forma de renombrar el cargado ¿Debo hacerlo con os.rename? Estoy cargando diferentes archivos zip, por lo que necesitan ser name_of_file.zip GRACIAS – Yebach

+0

También puede omitir 'form.accepts' y manejar el archivo, y se guarda. No hagas esto con los archivos subidos por el usuario, ya que estarás abierto a ataques cruzados de directorio. – Anthony

+0

cómo configurar la codificación de archivos por web2py. Lo que quiero es que el archivo cargado se almacene en una carpeta con el nombre original del archivo, porque tengo otro script para procesarlo y el nombre del archivo es importante para el procesamiento de archivos. – Yebach

2

así que lo hice :) aquí es mi código

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) 

Sé que probablemente no es la mejor solución, pero ya que funciona, me gusta :)

gracias Anthony

6

Si simplemente cambia el nombre del archivo, se romperá el mecanismo de descarga. Además, a veces es posible que desee guardar el archivo con un nombre diferente al original.Supongamos que usted tiene el siguiente modelo:

db.define_table("files", 
Field("name", unique=True), 
Field("file", "upload")) 

necesita extender el campo de carga con la tienda personalizada y recuperar funciones:

Field("file", "upload", custom_store=store_file, custom_retrieve=retrieve_file) 

Las funciones son simplemente escribir/leer un archivo de un directorio de carga fija :

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')) 

Ahora en el controlador que tenga que modificar el form.vars antes de la inserción de la base de datos/actualización se realiza y establecer el nombre del archivo. Si desea mantener el nombre original del archivo cargado, esto no es necesario.

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 

También es necesario definir una función para descargar el archivo como la estructura en response.download no funcionará:

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) 

para conectar los puntos, que necesita para construir el formulario. En el siguiente ejemplo, estoy usando el nuevo mecanismo de cuadrícula, que es mucho mejor que los formularios de la vieja escuela (pero aún no está documentado en el libro).

upload = lambda filename: URL("download", args=[filename]) 

def index(): 
    grid = SQLFORM.grid(db.files, onvalidation=validate, upload=upload) 
    return {"grid":grid} 

Si no quiere que todo el fanciness de la red, el código del controlador equivalente es:

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} 
+0

Hola, implementé el código anterior que está funcionando bien, pero "autodelete = True" no está funcionando. Aunque la fila se elimina de la base de datos ... el archivo físico permanece. – May

Cuestiones relacionadas