2009-07-27 9 views
121

J'essaie de configurer mes téléchargements de sorte que si l'utilisateur joe télécharge un fichier, il passe à MEDIA_ROOT/joe au lieu que les fichiers de tout le monde passent à MEDIA_ROOT. Le problème est que je ne sais pas comment le définir dans le modèle. Voici à quoi il ressemble actuellement:Django FileField avec upload_to déterminé à l'exécution

class Content(models.Model): 
    name = models.CharField(max_length=200) 
    user = models.ForeignKey(User) 
    file = models.FileField(upload_to='.') 

Donc ce que je veux, c'est '.' en tant que upload_to, que ce soit le nom de l'utilisateur.

Je comprends que depuis Django 1.0 vous pouvez définir votre propre fonction pour gérer le upload_to mais cette fonction n'a aucune idée de qui sera l'utilisateur, donc je suis un peu perdu.

Merci pour l'aide!

Répondre

242

Vous avez probablement lu the documentation, voici donc un exemple facile à faire du sens:

def content_file_name(instance, filename): 
    return '/'.join(['content', instance.user.username, filename]) 

class Content(models.Model): 
    name = models.CharField(max_length=200) 
    user = models.ForeignKey(User) 
    file = models.FileField(upload_to=content_file_name) 

Comme vous pouvez le voir, vous ne devez même pas utiliser le nom de fichier donné - vous pouvez passer outre que dans votre upload_to appelable aussi si vous avez aimé.

+0

Ouais, il appartient probablement à docs - c'est une FAQ raisonnablement sur IRC – SmileyChris

+2

Est-ce que cela fonctionne avec ModelForm? Je peux voir que cette instance a tous les attributs du modèle de classe, mais il n'y a pas de valeurs (juste une str du nom du champ). Dans le modèle, l'utilisateur est caché. Je peux devoir soumettre une question, j'ai été googling ceci pendant des heures. – mgag

+0

Oui cela fonctionne, et oui vous devriez poser une nouvelle question (ou demander de l'aide sur #django irc) – SmileyChris

11

Cela a vraiment aidé. Pour l'amour d'un peu plus de concision, a décidé d'utiliser lambda dans mon cas:

file = models.FileField(
    upload_to=lambda instance, filename: '/'.join(['mymodel', str(instance.pk), filename]), 
) 
+2

Cela n'a pas fonctionné pour moi dans Django 1.7 en utilisant les migrations.A fini par créer une fonction à la place et la migration a pris. – aboutaaron

+0

Même si vous ne parvenez pas à utiliser lambda avec la commande str (instance.pk), c'est une bonne idée si vous avez des problèmes avec l'écrasement des fichiers lorsque vous ne le souhaitez pas. –

+0

instance n'a pas de 'pk' avant d'enregistrer. Cela ne fonctionne que pour les mises à jour et non les créations (insertions). –

3

Une note sur l'utilisation de la valeur de l'objet pk « instance ». Selon la documentation:

Dans la plupart des cas, cet objet n'a pas encore été enregistré dans la base de données, donc s'il utilise l'AutoField par défaut, il n'a peut-être pas encore de valeur pour son champ de clé primaire.

Par conséquent, la validité de l'utilisation de pk dépend de la définition de votre modèle particulier.

+0

J'ai reçu None comme valeur. Je ne peux pas comprendre comment le réparer. Pouvez-vous expliquer dans un petit détail. –

Questions connexes