Django: доступ к первичному ключу в файле models.filefield(upload_to)
Я хочу сохранить свои файлы, используя первичный ключ записи.
Вот мой код:
def get_nzb_filename(instance, filename):
if not instance.pk:
instance.save() # Does not work.
name_slug = re.sub('[^a-zA-Z0-9]', '-', instance.name).strip('-').lower()
name_slug = re.sub('[-]+', '-', name_slug)
return u'files/%s_%s.nzb' % (instance.pk, name_slug)
class File(models.Model):
nzb = models.FileField(upload_to=get_nzb_filename)
name = models.CharField(max_length=256)
Я знаю, что при первом сохранении объекта первичный ключ недоступен, поэтому я готов взять дополнительный удар, чтобы сохранить объект, чтобы получить первичный ключ, а затем продолжить.
Приведенный выше код не работает. Он выдает следующую ошибку:
maximum recursion depth exceeded while calling a Python object
Я предполагаю, что это бесконечный цикл. Вызов метода save
вызовет метод get_nzb_filename
, который снова вызовет метод save
и т.д.
Я использую последнюю версию соединительной линии Django.
Как я могу получить первичный ключ, чтобы я мог использовать его для сохранения моих загруженных файлов?
Обновить @muhuk:
Мне нравится ваше решение. Можете ли вы помочь мне реализовать его? Я обновил свой код до следующего, и ошибка 'File' object has no attribute 'create'
. Возможно, я использую то, что вы выписали из контекста?
def create_with_pk(self):
instance = self.create()
instance.save()
return instance
def get_nzb_filename(instance, filename):
if not instance.pk:
create_with_pk(instance)
name_slug = re.sub('[^a-zA-Z0-9]', '-', instance.name).strip('-').lower()
name_slug = re.sub('[-]+', '-', name_slug)
return u'files/%s_%s.nzb' % (instance.pk, name_slug)
class File(models.Model):
nzb = models.FileField(upload_to=get_nzb_filename, blank=True, null=True)
name = models.CharField(max_length=256)
Вместо того, чтобы принудительно использовать требуемое поле в моей модели, я сделаю это в своем классе Form. Нет проблем.
Ответы
Ответ 1
Кажется, вам нужно предварительно создать свои модели File
с пустыми полями файлов. Затем выберите один и сохраните его с данным файлом.
У вас может быть такой метод пользовательского менеджера:
def create_with_pk(self):
instance = self.create()
instance.save() # probably this line is unneeded
return instance
Но это будет проблематично, если вам нужно какое-либо из ваших полей. Поскольку вы изначально создаете нулевой объект, вы не можете принудительно применять обязательные поля на уровне модели.
ИЗМЕНИТЬ
create_with_pk
должен быть метод пользовательского менеджера, в вашем коде это обычный метод. Следовательно, self
не имеет смысла. Все это правильно документировано с примерами.
Ответ 2
Вы можете сделать это, установив upload_to
во временное место и создав собственный способ сохранения.
Метод save должен сначала вызвать super, чтобы сгенерировать первичный ключ (это сохранит файл во временное местоположение). Затем вы можете переименовать файл с помощью первичного ключа и перенести его в нужное место. Позвоните супер еще раз, чтобы сохранить изменения, и вам хорошо идти! Это работало хорошо для меня, когда я столкнулся с этой точной проблемой.
Например:
class File( models.Model ):
nzb = models.FileField( upload_to='temp' )
def save( self, *args, **kwargs ):
# Call save first, to create a primary key
super( File, self ).save( *args, **kwargs )
nzb = self.nzb
if nzb:
# Create new filename, using primary key and file extension
oldfile = self.nzb.name
dot = oldfile.rfind( '.' )
newfile = str( self.pk ) + oldfile[dot:]
# Create new file and remove old one
if newfile != oldfile:
self.nzb.storage.delete( newfile )
self.nzb.storage.save( newfile, nzb )
self.nzb.name = newfile
self.nzb.close()
self.nzb.storage.delete( oldfile )
# Save again to keep changes
super( File, self ).save( *args, **kwargs )
Ответ 3
Контекст
Была та же проблема.
Решил, что он присваивает id текущему объекту, сначала сохраняя объект.
Метод
- создать пользовательскую функцию upload_to
- определить, имеет ли объект pk
- Если нет, сначала сохраните экземпляр, извлеките pk и назначьте его объекту
- создайте свой путь с помощью
Пример рабочего кода:
class Image(models.Model):
def upload_path(self, filename):
if not self.pk:
i = Image.objects.create()
self.id = self.pk = i.id
return "my/path/%s" % str(self.id)
file = models.ImageField(upload_to=upload_path)
Ответ 4
Ty, есть ли причина, по которой вы загрузили свой собственный фильтр slugify?
Django поставляется со встроенным фильтром slugify
, вы можете использовать его так:
from django.template.defaultfilters import slugify
slug = slugify(some_string)
Не уверен, что вы знали, что он доступен для использования...