2017-07-27 121 views
0

我想創建一個文件夾的每個用戶把他們的項目將文件保存到一個模型。因此,他們的文件將具有路徑..\project\id\filenameid是用戶idfilename是文件的名稱。現在使用Filefield中的upload_toinstancefilename)所允許的參數,我意識到instance.id將是None,文件的路徑將是..\project\None\filename而不是..\project\id\filename如何使用upload_to動態路徑

現在讀Django documentation upload_to我看到了這一點:

在大多數情況下,這個對象將不會被保存到數據庫 還,所以如果使用默認的下拉列表AutoField,它可能還沒有一個 它的主鍵字段的值。

我的解釋是,創建一個新的記錄,並user_directory_path不是在同一時間實例,那就是,當我打電話createProject模型,instance.idNone。我的問題是,現在有沒有辦法解決這個問題?雖然我看到upload_to很方便,但對於動態路徑(如我正在做的那樣)來說,這並不一定很方便。我正在考慮創建記錄,然後在更新中添加文件路徑,但我正在尋找一種可以一步保存所有內容的方法。

models.py 
def user_directory_path(instance, filename): 
    # file will be uploaded to MEDIA_ROOT/user_<id>/<filename> 
    return 'project/{0}/{1}'.format(instance.user.id, filename) 


class Project(models.Model): 

    email = models.ForeignKey(User, 
          to_field="email", 
          max_length=50 
    ) 
    title = models.CharField(max_length=100) 
    date_created = models.DateTimeField(auto_now_add=True) 
    updated = models.DateTimeField(auto_now=True) 
    file = models.FileField(upload_to=user_directory_path, validators=[validate_file_type], null=True) 

當表格通過驗證時,這是views.py。在create之前調用user_directory_path

email = request.user.email 
title = request.POST.get('title', '') 
file = request.FILES['file'] 
filename = file.name 
instance = Usermie.objects.get(email=request.user.email) 

# Save to model 
user_directory_path(instance=instance, filename=filename) 
Project.objects.create(
    title=title, file=file, 
) 

回答

2

如果像你說的,要在文件路徑使用的ID是的id用戶,而不是項目的ID ..那麼沒有問題,因爲用戶在保存項目時已經存在。由於email是一個外鍵User,你只是做:

def user_directory_path(instance, filename): 
    # file will be uploaded to MEDIA_ROOT/user_<id>/<filename> 
    return 'project/{0}/{1}'.format(instance.email.id, filename) 

但我要指出的是,在做的事情,做一個場稱爲email這是Django的方式外鍵User實際上是很混亂。數據庫中的字段將被稱爲email_id ..並且模型字段的值將返回User ..的實例,而不是實際的電子郵件地址,即使電子郵件地址是存儲在列中的。要獲得電子郵件地址,您需要執行以下操作之一:

myproject.email.email  
myproject.email_id 

兩者都不是很清楚。所以,除非你有這樣的理由,否則你應該打電話給user,並取消to_field='email'。允許Django通過id加入表格,這是默認行爲。

然後,如果你需要的用戶電子郵件地址,你可以通過

myproject.user.email 

得到它的任何時間和好處是,如果用戶更改他們的電子郵件地址,它會無處不在改變,你不必依賴在級聯更新來修復所有外鍵。

信任我,使用Django,當你想通過id(默認),除非有一個理由這樣做ForeignKey的...

+0

'而且獎金是,如果用戶更改他們的電子郵件地址,它將在任何地方都會發生變化,您不必依賴級聯更新來修復所有外鍵。「在ForeignKey中使用id的非常好的理由。 –

+0

謝謝!這實際上給了我更好的視力。我將返回並將所有其他模型中的電子郵件字段更改爲用戶標識。直到現在,我還沒有意識到用戶更改電子郵件的問題。謝謝@Massan。我一直知道這一點,但沒有意識到我在做這件事。 – Jam1

+0

不客氣,我很高興我可以提供幫助。我應該提到的另一件事是,一旦創建了項目,就不能允許用戶更改,因爲這會改變目錄路徑,並且django不會再找到這些文件。 –

1

一個簡單的解決方案,可以節省不使用文件對象,然後保存文件中像這樣

email = request.user.email 
title = request.POST.get('title', '') 
file = request.FILES['file'] 
filename = file.name 
instance = Usermie.objects.get(email=request.user.email) 

# Save to model 
user_directory_path(instance=instance, filename=filename) 
project = Project.objects.create(title=title) 
project.file = file 
project.save() 
+0

這是看它一個很好的方式,但這樣做這樣我就不會得到用戶的主鍵,但將使用項目模型的主鍵。 – Jam1

+1

在這種情況下,你應該寫''project/{0}/{1}'.format(instance.email_id,filename)'作爲'email'字段是'User'模型的外鍵。 –

+0

哦,我看到你在說什麼,但因爲我的電子郵件字段的屬性爲'to_field =「email」',它將返回一個路徑'project/user_email/filename'。我可能不得不改變一些事情來實現它。謝謝! – Jam1