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() сюда).