Как мне получить pk внешнего ключа?

#python #django

#python #django

Вопрос:

Я хочу разрешить загрузку, которая будет храниться следующим образом:

 class Upload(models.Model):
    user = models.ForeignKey(User)
    category = models.ForeignKey(Category)
    file = models.FileField(upload_to='uploads/'   str(category.pk)   '/'   str(user.pk))

    class Meta:
        unique_together = ('user', 'category')
  

Таким образом, каждая загрузка будет изолирована в своем собственном каталоге, сначала по идентификатору категории, а затем по идентификатору пользователя. Мне не пришлось бы беспокоиться о дублирующихся именах файлов, а структура каталогов была бы аккуратной и организованной.

Однако ForeignKey у него нет экземпляра pk , поэтому приведенный выше код фактически не работает. Есть ли способ сохранить файл в каталоге на основе категории и пользователя? Или, в качестве альтернативы, существует ли другая стратегия, обычно используемая для организации загрузки файлов в Django?

Ответ №1:

Вы можете использовать вызываемую функцию для upload_to:

 import os

def upload_path(instance, filename):
    return os.path.join('uploads', str(instance.category.pk), str(instance.user.pk))

file = models.FileField(upload_to=upload_path)
  

Ответ №2:

Здесь нужно рассмотреть две вещи.

Суть в том, что pk связанный Category доступен в Upload экземпляре в памяти как self.category_id , а pk связанный User self.user_id как .

Несколько более сложная вещь заключается в том, что для использования dynamic upload_to вы должны предоставить ему вызываемое, а не произвольное выражение. Из документов:

Это также может быть вызываемый объект, такой как функция, которая будет вызвана для получения пути загрузки, включая имя файла. Этот вызываемый объект должен быть способен принимать два аргумента и возвращать путь в стиле Unix (с косыми чертами) для передачи в систему хранения. Будут переданы два аргумента:

экземпляр

Экземпляр модели, в которой определено поле FileField. Более конкретно, это конкретный экземпляр, к которому прикрепляется текущий файл.

В большинстве случаев этот объект еще не был сохранен в базе данных, поэтому, если он использует автоматическое поле по умолчанию, у него может еще не быть значения для его поля первичного ключа.

имя файла

Имя файла, которое изначально было присвоено файлу. Это может учитываться или не учитываться при определении конечного пути назначения.

Итак, вы захотите определить функцию, которая принимает Upload экземпляр и возвращает желаемый путь:

 def upload_location(upload, original_filename):
    return os.path.join(str(upload.category_id), str(upload.user_id), original_filename)
  

Или что-то в этом роде. Затем используйте его в модели:

 file = models.FileField(upload_to=upload_location)
  

Комментарии:

1. Я думал использовать os.path.join Не думайте, что я скопировал вас 🙂

2. @AamirAdnan — хех. Не то чтобы это было глубоко секретным. Я признаю, что ваш ответ напомнил мне о необходимости упорядочивать целое число FKs.