AttributeError: объект '_io.BufferedWriter' не имеет атрибута 'save'
Я пытаюсь сохранить следующий файл
Вот модель:
class someModel(models.Model):
someFile = models.FileField(storage=someModule(), blank=True)
Вот как я создаю файл, который хочу сохранить:
flat_array = array.flatten(order="F")
with open(filename, "wb") as some_transformed_file:
some_transformed_file.write(struct.pack(">i", 192837465))
some_transformed_file.write(flat_array[i].real)
return some_transformed_file
Вот спасительная часть:
doc_io = BytesIO()
some_transformed_file.save(doc_io)
some_file_object = File(doc_io, filename=os.path.basename(name))
item = someModel.objects.create(someFile=some_file_object )
Я получаю ошибку
AttributeError: '_io.BufferedWriter' object has no attribute 'save'
>
На самом деле, ваши пользовательские методы create_user
(и create_superuser
, которые вы, вероятно, также переписали) не вызываются при создании нового пользователя из панели администратора. Я не совсем понимаю почему, но думаю, что функция create_user
- это просто ярлык.
Почему бы не переопределить save()
метод вашего CustomUser
? Из документации Django:
Классический случай использования переопределения встроенных методов - если вы хотите, чтобы что-то происходило всякий раз, когда вы сохраняете объект.
Не совсем то, что вы ищете? Посмотрите документацию Django здесь (чтобы сделать это на уровне формы) и здесь (если вы предпочитаете изменять непосредственно саму модель, независимо от того, какая форма используется) для получения дополнительной информации.
Например, если вы предпочитаете второй вариант, вы можете добавить этот метод в CustomUser
:
from django.apps.apps import get_model
from django.db import transaction
class CustomUser(AbstractUser):
# your initial code goes here ...
def save(self, *args, **kwargs):
# make the distinction between the creation and the update of the instance
if not self._state.adding:
# doesn't change the initial method if the user has already been saved in DB
return super(CustomUser, self).save(*args, **kwargs)
# guarantee of atomicity
with transaction.atomic():
# dynamic resolution to avoid a circular import, might not be necessary
customer = get_model("stripe", "Customer").create(
email=self.email,
name=self.name,
)
self.stripe_customer_id = customer.id
super(CustomUser, self).save(*args, **kwargs)
return self
Не забывайте делать различие между созданием и обновлением экземпляра.
UserAdmin
полагается на реализацию в ModelAdmin
для создания экземпляра, проверки формы, а затем сохранения экземпляра, а не вызова пользовательского метода в менеджере модели.
Цепочка вызовов: ModelAdmin.add_view()
→ ... → self._changeform_view()
, которая вызывает:
- (i)
form.is_valid()
(изModelForm
) → ... →self._post_clean()
→self.instance = construct_instance(...)
, - (ii)
self.save_form(...)
→new_object = form.save(commit=False)
(изBaseModelForm
) возвращаяself.instance
, и - (iii)
self.save_model(..., new_object, ...)
→obj.save()
.
Вы можете переопределить ModelAdmin.save_form
для вызова метода create_user
пользовательского менеджера пользователей и заменить form.instance
:
class CustomUserAdmin(UserAdmin):
model = CustomUser
fieldsets = (
(None, {'fields': (model.USERNAME_FIELD, 'name', 'password')}),
) + UserAdmin.fieldsets[2:]
add_fieldsets = (
(None, {'fields': (model.USERNAME_FIELD, 'name', 'password1', 'password2')}),
)
ordering = (model.USERNAME_FIELD,)
def save_form(self, request, form, change):
if not change:
form.instance = self.model.objects.create_user(
form.cleaned_data['email'],
form.cleaned_data['password1'],
form.cleaned_data['name'],
)
return super().save_form(request, form, change)
⚠️ Заметьте в обычной цепочке вызовов, что save_form()
не вызывает obj.save()
, так как ModelAdmin
обрабатывает множественные наборы форм и m2m модели, в то время как CustomUserManager.create_user
вызывает user.save()
. Можно изменить это поведение в UserAdmin
с известной областью применения, хотя вы можете рассмотреть возможность разделения CustomUserManager.create_user
на CustomUserManager.construct_instance
и CustomUserManager.save_new_model
(перенести stripe.Customer.create(...)
и user.save()
сюда).