Django create file programatically on save - python

The goal with this is for the user to create an instance of the model where they populate a source URLField, and on save, it would fetch the URL and save it as a file.
class ComicImage(UUIDModel):
src = models.URLField('Comic URL', max_length=512, blank=True)
img = models.FileField('Images', null=True, blank=True, upload_to='comics')
def save(self, *args, **kwargs):
img_data = BytesIO(requests.get(self.src).content)
self.img.save(f'{self.hash}-i.webp', content=img_data)
super().save(*args, **kwargs)
But I keep getting an error
ValueError: The 'img' attribute has no file associated with it.
Which appears that it's not assigning a file to the field. Or rather, it doesn't until AFTER the model is saved.
Alternatively:
I also tried
self.img.save(f'{self.hash}-i.webp', content=img_data, save=True)
But it gets stuck in a loop of saving forever. If I set save=False, then it creates the model but not the file.
Is there a way to create/populate/modify the file before it's saved?

Related

How to save an image in a directory named on the User?

I am using Django2.2 and I am currently learning Django. I have created a model where I have to post an image of a certain thing and that model is connected with a User. I want to save the image on a directory named on that certain user
I have a custom User Model where I created a field called Profile Photo and that profile photo is saved to a directory named on that User.But then I created another application called 'Product' and there I created many fields including an image field.I am trying to save that image on that directory named on that specific User.
def user_directory_path(instance, filename):
return 'media/%s/%s' % (instance.username, filename)
class Products(models.Model):
title = models.CharField(max_length=100)
body = models.CharField(max_length=1000)
image = models.ImageField(upload_to = user_directory_path)
product_user = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.title
When I try to save a Product and error occurs.
'Products' object has no attribute 'username'
Is there any successful ways to do it.
A Products instance indeed has no username attribute. The product_user has, you thus can change this to:
def user_directory_path(instance, filename):
return 'media/%s/%s' % (instance.product_user.username, filename)
Note: models have usually singular names, so Product, instead of Products.

How to overwrite a model's save method to fill a field upon model instance saving

In the model below, I have added file_name field to store just the filename.
I have overwritten the save method to fill this field upon saving, but the field is still empty after uploading the file through admin panel. Even if I put a print statement in the save method, it will not print the file name.
Migrations are applied.
What am I doing wrong?
class DataFile(models.Model):
file = models.FileField(upload_to='data files')
file_name = models.TextField(default='', blank=True)
uploaded_at = models.TimeField(default=datetime.datetime.now())
def __str__(self):
return f'{os.path.basename(self.file.path)}, uploaded at: {str(self.uploaded_at)})'
def __save__(self, *args, **kwargs):
self.file_name = os.path.basename(self.file.name)
super(DataFile, self).save(*args, **kwargs)

saving processed data in django model?

I'm working in a project where users upload a photo and it will be processed on a server then served back and saved to be shown as some sort of comparison.
this is my model for the uploaded images
class AnalysesImages(models.Model):
user = models.ForeignKey(user,on_delete=models.CASCADE)
image = models.ImageField(upload_to = user_directory_path ,
verbose_name = 'Image')
i have the idea of creating another model for the processed data(image) but how i should retrieve it? any ideas?
I figured out a way. If the process would be done with the same language (in my case is python) you can make a function where it simply call the image and process it and be saved as another field in the model like:
class AnalysesImages(models.Model):
patient = models.ForeignKey(Patient,on_delete=models.CASCADE)
pre_analysed = models.ImageField(upload_to = user_directory_path ,
verbose_name = 'Image')
analysed = models.ImageField(upload_to=analyses_directory_path,
verbose_name='analysed Image')
# function for analysing the images
def analyse_image(self):
return self.pre_analysed
def save(self, *args, **kwargs):
self.analysed = self.analyse_image()
super(AnalysesImages, self).save(*args, **kwargs)

Create model instance out of Form and add it to other instance

In my models.py I have model called Bus. It contains multiple fields, including the field file below:
class Bus(models.Model):
file = models.OneToOneField('File', on_delete=models.PROTECT, editable=False)
The File model consists of:
class File(models.Model):
file = models.FileField(
upload_to=get_filepath,
max_length=45,
validators=[
FileExtensionValidator(allowed_extensions=['pdf', 'jpg', 'png']),
file_size,
]
)
original_name = models.CharField(max_length=45)
extension = models.CharField(max_length=3)
When you want to create a new Bus I need of course a form. That's defined in my forms.py:
class BusForm(forms.ModelForm):
upload = forms.FileField(max_length=45, required=False,
validators=[
FileExtensionValidator(allowed_extensions=['pdf', 'jpg', 'png']),
file_size,
],)
My problem:
In the save() method of BusForm I have to create a File instance and add it to the Bus instance (file field).
For multiple hours I tried to achieve that. However, I don't get it. If someone could try to help me how the save() method has to look like, that would be great!
You can create save method like this
def save(self, commit=False):
# This will create bus_instance but not save in database
bus_instance = super(self, BusForm).save(commit=False)
# create file instance
file_instance = File.objects.create() # add the required parameters
# Assign file_instance to file attribute of bus_instance
bus_instance.file = file_instance
# Save to database only if user calling save method wants to save in database
if commit:
bus_instance.save()
return bus_instance

Django make non persistent field when file uploading

I have a model for Document like :
class Document(models.Model):
document_name = models.CharField(max_length=64)
author = models.ForeignKey(Client, null=False, default=1)
size = models.IntegerField(default=0)
version = models.CharField(max_length=64)
file = models.FileField(upload_to='documents/%Y/%m/%d')
but I also want to upload that file. My form looks like
class UploadDocumentForm(ModelForm):
class Meta:
model = Document
fields = ('document_name', 'author', 'size', 'version', 'file',)
def __init__(self, *args, **kwargs):
super(UploadDocumentForm, self).__init__(*args, **kwargs)
Now obviously, I want my file to be saved in a folder and not have its own column i nthe db. In db I only want the other data. Problem is, django tries to persist it and crashes with
The above exception (table document has no column named file)
Is there a way to make file a non persisted field or something?
Im following this tutorial, https://simpleisbetterthancomplex.com/tutorial/2016/08/01/how-to-upload-files-with-django.html
I tried removing file form the model and adding it just in the form somehow but it doesn't work. It is not recognized liek that. I just want it to not be persisted in the sqlite database. Any ideas?
I thought about making a second model without the file and create somehow both of them or override the save method.. Im not sure how to make it work.

Categories