2011-11-04 34 views
7

tôi muốn tải lên tập tin với SQL.factory() Tôi chỉ muốn duy trì tên tập tin gốc mã của tôi hiện đangweb2py tải lên với tên tập tin gốc

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) 

Tôi đoán session.filename = request.vars .file là nơi bạn đặt tên tệp. Tại sao tôi nhận được tên tập tin được tạo tự động no_data.smth.23u8o8274823zu4i2.smth

Cảm ơn bạn

Trả lời

6

Thứ nhất, request.vars.file là một đối tượng Python cgi.FieldStorage, vì vậy session.filename = request.vars.file nên kết quả trong một lỗi. request.vars.file.file là đối tượng tệp thực tế và request.vars.file.filename là tên gốc của tệp được tải lên.

Khi bạn tải tệp lên qua trường tải lên, web2py sẽ tự động tạo tên mới của biểu mẫu 'table_name.field_name.random_id.b16encoded_original_filename.extension'. Điều này được thực hiện để ngăn chặn các cuộc tấn công traversal thư mục và để cho phép cơ chế tải xuống (cần phải biết tên bảng và trường). Trong trường hợp của SQLFORM.factory, không có tên bảng cơ sở dữ liệu, vì vậy nó mặc định là tên bảng là 'no_table'.

Mã bạn đã hiển thị không nên tạo tên tệp như 'no_data.smth.23u8o8274823zu4i2.smth'. Tên tệp đó ngụ ý bạn đã nói rõ ràng SQLFORM.factory để sử dụng tên bảng 'no_data' (thông qua đối số table_name) và tên trường tải lên là 'smth'. (Mã trên sẽ tạo tên tệp bắt đầu bằng 'no_table.file'.)

Lưu ý, web2py tự động lấy tên gốc của tệp được tải lên và mã hóa nó (sử dụng b16encode) vào tên tệp mới (sau đó giải mã gốc tên tệp khi sử dụng cơ chế tải xuống được tích hợp sẵn). Tên tệp gốc cũng có sẵn trong form.vars.file.filename. Vì vậy, bạn không nhất thiết cần người dùng nhập tên tệp. Tuy nhiên, nếu bạn muốn kích hoạt người dùng nhập vào một tên tập tin đó có thể khác với tên tập tin thực tế và sau đó sử dụng tên tập tin do người dùng nhập vào, bạn có thể thêm những điều sau đây trước khi việc tạo ra hình thức:

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

Điều đó sẽ tái gán tên tệp của tệp được tải lên với giá trị được người dùng nhập và sau đó web2py sẽ mã hóa tên tệp do người dùng nhập đó vào tên tệp mới. Tuy nhiên, lưu ý rằng web2py dựa vào đuôi tệp để đặt tiêu đề HTTP một cách thích hợp khi tải xuống, vì vậy, bạn có thể muốn thêm một số logic để lấy đuôi tệp gốc trong trường hợp người dùng không nhập được.

+0

với request.vars.name_of_file.filename tôi nhận được tên tập tin ban đầu, nhưng làm thế nào để đổi tên đã tải lên. tôi nên làm gì với os.rename? Tôi đang tải lên các tệp zip khác nhau, vì vậy chúng cần phải là name_of_file.zip THANK YOU – Yebach

+0

Bạn cũng có thể bỏ qua 'form.accepts' và xử lý tệp lưu. Tuy nhiên, đừng làm điều này với các tệp do người dùng tải lên vì bạn sẽ mở các cuộc tấn công traversal thư mục. – Anthony

+0

cách đặt không mã hóa tệp bằng web2py. Vấn đề là tôi muốn các tập tin được tải lên được lưu trữ trong một thư mục với tên tập tin ban đầu, cos tôi có một kịch bản sau đó để xử lý nó và tên tập tin là quan trọng để xử lý tập tin ?? – Yebach

2

vì vậy tôi đã làm điều đó :) đây là mã của tôi

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) 

Tôi biết nó có lẽ không phải là giải pháp tốt nhất nhưng vì nó hoạt động, tôi thích :)

cảm ơn bạn Anthony

6

Nếu bạn chỉ cần đổi tên tệp, điều này sẽ phá vỡ cơ chế tải xuống. Hơn nữa, đôi khi bạn có thể muốn lưu tệp dưới một tên khác với tên gốc.Giả sử bạn có mô hình sau:

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

Bạn cần phải mở rộng lĩnh vực tải lên với cửa hàng tùy chỉnh và lấy chức năng:

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

Các chức năng đơn giản là đang viết/đọc một tập tin từ một thư mục upload cố định :

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

Bây giờ trong bộ điều khiển, bạn cần sửa đổi form.vars trước khi chèn/cập nhật cơ sở dữ liệu và đặt tên tệp. Nếu bạn muốn giữ tên gốc của tệp được tải lên, điều này là không cần thiết.

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 

Bạn cũng cần phải xác định một chức năng để tải về các tập tin như xây dựng trong response.download sẽ không làm việc:

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) 

Để kết nối các dấu chấm, bạn cần xây dựng biểu mẫu. Trong ví dụ dưới đây tôi đang sử dụng cơ chế lưới mới tốt hơn các dạng cũ của trường (nhưng chưa được ghi trong sách).

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

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

Nếu bạn không muốn tất cả các fanciness của lưới điện, các mã điều khiển tương đương là:

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

Xin chào, tôi đã triển khai mã ở trên hoạt động tốt nhưng "autodelete = True" không hoạt động. Mặc dù hàng bị xóa khỏi cơ sở dữ liệu ... tệp vật lý vẫn còn. – May

Các vấn đề liên quan