2011-11-04 12 views
7

orijinal dosya adıyla karşıya web2py benim Kod şu andaSadece orijinal dosya adını korumak istiyorum ben SQL.factory() ile dosya yüklemek istediğiniz

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) 

sanırım session.filename = request.vars olduğunu .file, dosya adını belirlediğiniz yerdir. i

no_data.smth.23u8o8274823zu4i2.smth autogenerated dosya adını almak Neden size

cevap

6

İlk ederiz, request.vars.file bir Python cgi.FieldStorage nesne, yani session.filename = request.vars.file bir hataya yol olmalıdır. request.vars.file.file gerçek dosya nesnesidir ve request.vars.file.filename yüklenen dosyanın orijinal adıdır.

Bir yükleme alanı aracılığıyla bir dosya yüklediğinizde, web2py otomatik olarak 'table_name.field_name.random_id.b16encoded_original_filename.extension' formunun yeni bir adını oluşturur. Bu, dizin çaprazlama saldırılarını önlemek ve indirme mekanizmasını (tabloyu ve alan adını bilmesi gereken) etkinleştirmek için yapılır. SQLFORM.factory durumunda, veritabanı tablosu adı yoktur, bu nedenle varsayılan olarak 'no_table' tablosunun adıdır. Gösterdiğiniz kod aslında 'no_data.smth.23u8o8274823zu4i2.smth' gibi bir dosya adı oluşturmamalıdır. Bu dosya adı, 'no_data' (table_name argümanı aracılığıyla) 'un bir tablo adını kullanmak için SQLFORM.factory açık bir şekilde söylediğini ve yükleme alanı adının' smth 'olduğunu belirtmektedir. (Yukarıdaki kod, 'no_table.file' ile başlayan bir dosya adı oluşturur.)

Not, web2py otomatik olarak yüklenen dosyanın orijinal adını alır ve yeni dosya adıyla (b16encode kullanarak) kodlar (daha sonra orijinali deşifre eder) Yerleşik indirme mekanizması kullanıldığında dosya adı). Orijinal dosya adı form.vars.file.filename dosyasında da bulunur. Bu nedenle, kullanıcının bir dosya adı girmesine kesinlikle gerek yoktur. Eğer gerçek dosya farklı ve daha sonra kullanıcı tarafından girilen dosya adını kullanabilir bir dosya adı girmesini etkinleştirmek istiyorsanız Ancak, Form oluşturma önce aşağıdaki ekleyebilirsiniz:

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

yeniden edecek That yüklenen dosyanın dosya adını kullanıcı tarafından girilen değere atayın ve web2py, kullanıcı tarafından girilen dosya adını yeni dosya adına kodlayacak. Ancak, web2py'nin, HTTP üstbilgilerini indirme sırasında uygun şekilde ayarlamak için dosya adı uzantısına dayandığını unutmayın, böylece kullanıcının giriş yapmaması durumunda orijinal dosya adı uzantısını elde etmek için bir mantık eklemek isteyebilirsiniz.

+0

i orijinal dosya adını almak ama nasıl: Eğer ızgara tüm fanciness istemiyorsanız

upload = lambda filename: URL("download", args=[filename]) def index(): grid = SQLFORM.grid(db.files, onvalidation=validate, upload=upload) return {"grid":grid} 

, eşdeğer kontrolör kodudur yüklenen adını yeniden adlandır. os.rename ile yapmalı mıyım? Farklı zip dosyalarını yüklüyorum, bu yüzden isim_of_file.zip olması gerekiyor TEŞEKKÜR EDERİM – Yebach

+0

Ayrıca, form.accepts komutunu atlayabilir ve dosyayı kendiniz kaydedebilirsiniz. Dizin traversal saldırılarına açık olacağından, bunu kullanıcı tarafından yüklenen dosyalarla yapmayın. – Anthony

+0

web2py tarafından nasıl dosya kodlaması yapılmaz. Asıl yüklenen dosyanın orijinal dosya ismiyle bir klasörde saklanmasını istiyorum, çünkü daha sonra işlemek için başka bir betik var ve dosya adı dosya işleme için önemli? – Yebach

2

yüzden burada :) Muhtemelen en iyi çözüm olmadığını biliyoruz

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) 

kodum ama çalıştığı için, sana

6
Anthony teşekkür :)

gibi yaptılar

Sadece dosyayı yeniden adlandırırsanız, bu indirme mekanizmasını bozar. Dahası, bazen dosyayı orijinalden farklı bir adla kaydetmek isteyebilirsiniz.

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

Özelleştirilmiş mağaza ile yükleme alanını genişletmek ve fonksiyonlarını almak gerekir: Diyelim ki aşağıdaki modele sahip varsayalım

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

fonksiyonlar sadece yazıyoruz/sabit yükleme dizinden bir dosya okunurken :

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

Şimdi denetleyicisi size veritabanı ekleme/güncelleme yapılmadan önce form.vars değiştirmek ve dosya adını ayarlamanız gerekir. Yüklenen dosyanın orijinal adını tutmak istiyorsanız, bu gerekli değildir.

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 

Ayrıca çalışmaz response.download İçine yerleştirilmiş olarak dosyayı indirmek için bir işlev tanımlamak gerekir:

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) 

noktaları birleştirmek için, formu oluşturmak gerekir. Aşağıdaki örnekte, eski okul formlarından daha iyi olan (ancak henüz kitapta belgelenmemiş) yeni kılavuz mekanizmasını kullanıyorum. request.vars.name_of_file.filename ile

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

Merhaba Yukarıdaki kodları iyi çalışıyor, ancak "autodelete = True" çalışmıyor. Satır veritabanından silinmesine rağmen ... fiziksel dosya kalır. – May

İlgili konular