Jeśli zmienisz nazwę pliku, spowoduje to przerwanie mechanizmu pobierania. Co więcej, czasami możesz chcieć zapisać plik pod inną nazwą niż oryginał.Załóżmy, że masz następujący model:
db.define_table("files",
Field("name", unique=True),
Field("file", "upload"))
należy rozszerzyć pole wysyłania doda sklepu i odzyskać funkcje:
Field("file", "upload", custom_store=store_file, custom_retrieve=retrieve_file)
Funkcje te są po prostu pisanie/czytanie pliku z ustalonym katalogu przesyłania :
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'))
Teraz w kontrolerze należy zmodyfikować plik form.vars przed włożeniem/aktualizacją bazy danych i ustawić nazwę pliku. Jeśli chcesz zachować oryginalną nazwę przesłanego pliku, nie jest to konieczne.
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
Należy również zdefiniować funkcję, aby pobrać plik kompilacji w response.download nie będzie działać:
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)
Aby połączyć kropki, trzeba zbudować formę. W poniższym przykładzie używam nowego mechanizmu siatki, który jest lepszy niż formularze starej szkoły (ale jeszcze nie udokumentowane w książce).
upload = lambda filename: URL("download", args=[filename])
def index():
grid = SQLFORM.grid(db.files, onvalidation=validate, upload=upload)
return {"grid":grid}
Jeśli nie chcesz cały fanciness siatki, odpowiednik kod kontrolera to:
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}
z request.vars.name_of_file.filename ja dostać oryginalną nazwę pliku, ale jak zmień nazwę przesłanego. powinienem zrobić z os.rename? Przesyłam różne pliki zip, więc muszą to być name_of_file.zip DZIĘKUJĘ – Yebach
Można również pominąć 'form.accepts' i obsługiwać zapisywanie plików. Nie rób tego z plikami przesłanymi przez użytkownika, ponieważ będziesz otwarty na ataki przemierzania katalogów. – Anthony
jak ustawić kodowanie plików przez web2py. Chodzi o to, że przesłany plik powinien być przechowywany w jednym folderze z oryginalną nazwą pliku, czy mam inny skrypt, aby go przetworzyć, a nazwa pliku jest ważna dla przetwarzania plików? – Yebach