Создать уникальный идентификатор для модели - PullRequest
2 голосов
/ 11 февраля 2011

У меня есть модель, содержащая FileField. Мне бы хотелось, чтобы этот FileField имел уникальный путь.

Сначала, хотя и об использовании идентификатора записи, но Django переместит файл в путь загрузки_1003 * до сохранения записи, поэтому идентификатор будет пустым.

Более того, я не могу использовать что-то вроде заголовка или любых других элементов модели (кроме даты создания), поскольку они могут быть изменены пользователем. И я предпочитаю не копировать / удалять файл каждый раз, когда пользователь меняет заголовок своей записи (если я использую заголовок как часть моего пути).

Здесь начну мое исследование, я нашел это:

  • Создайте уникальный ключ и сравните его с базой данных. Пока ключ существует, мы генерируем новый ( Django, генерация уникального поля ): проблема в том, что потенциальные попадания могут быть сделаны в базу данных до того, как будет создан уникальный ключ

  • Получение метки времени от даты создания. Проблема здесь в том, что если два человека добавят файл в одно и то же время, это вызовет конфликты

Я бы хотел, чтобы этот уникальный идентификатор был как можно меньше, максимальная длина 7 была бы большой. Идеальным решением было бы иметь идентификатор записи. Знаете ли вы обходной путь для этого (вызов save () перед перемещением файлов в их папку upload_to ?) Или, если нет, то какая реализация будет лучшей, основываясь на одном из моих решения или тот, который вы считаете лучшим?

Ответы [ 2 ]

1 голос
/ 11 февраля 2011

Поскольку FileField по умолчанию имеет значение null = True, пусто = True, существует возможность дважды сохранить модель, сначала удалив значение файла (= Нет), сохранив, а затем добавив значение файла ( который был ранее сохранен во временной переменной), и сохраните снова.

Вот код

# this method goes in your model
def save(self, *args, **kwargs):
    # ignoring the double save if this is an update or if there is no files
    if self.pk or not self.file:
        return super(MyModel, self).save(*args, **kwargs)

    old_file = self.file._file
    self.file = None

    super(MyModel, self).save(*args, **kwargs)

    self.file = old_file

    return super(MyModel, self).save(*args, **kwargs)

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

Надеюсь, это поможет!

0 голосов
/ 11 февраля 2011

Первый вариант, который вы дали, был бы отличным выбором, если бы вы не пытались минимизировать размер поля.Если у вас есть идентификатор int64, который достигает 2 ^ 64 - 1 (64-разрядное целое число), вам нужно иметь более триллиона записей (~ 2 ^ 40) в вашей БД, прежде чем вы начнете беспокоиться о том, чтоболее 1 запроса.Второе также вряд ли произойдет, если вы используете datetime, и вы можете предотвратить это с помощью того же цикла while, манипулируя датой, если она столкнулась.

Один из вариантов - иметь генератор уникальных идентификаторов.Вы можете сохранить его в своей БД, и когда вы собираетесь создать FileField, вы делаете один запрос для извлечения последнего сгенерированного идентификатора, увеличиваете его на единицу и снова сохраняете в БД.

Другой вариант - реализация FileField.рукой.Вместо использования FileField, используйте что-то вроде CharField и управляйте связями файлов и путями самостоятельно.

...