I have a function that crops user images but I don't want the model to have 2 fields so I made a function that overrides the original file and I noticed that the function works well on normal files but when I add the function to the view new file is made but at the media directory not even the the specified folder so how can i override files by Django ?
models.py
# defining directory for every patient
def user_directory_path(instance, filename):
# file will be uploaded to MEDIA_ROOT/patient_<id>/<filename>
return 'patient_{0}/{1}'.format(instance.patient.id, filename)
class UploadedImages(models.Model):
patient = models.ForeignKey(Patient,on_delete=models.CASCADE,related_name='images')
pre_analysed = models.ImageField(upload_to = user_directory_path ,
verbose_name = 'Image')
upload_time = models.DateTimeField(default=timezone.now)
the cropping function:
import os
from PIL import Image
def crop(corrd, file ,path,pk):
image = Image.open(file) #To open the image as file.path won't open
path_1 , fn = os.path.split(path) #which is MEDIA_ROOT/and <filename>
patient_dir = 'patient_{}'.format(pk) #to get the user directory
path_ = path_1+patient_dir+fn #MEDIA_ROOT/patient_<id>/<filename>
cropped_image = image.crop(corrd)
resized_image = cropped_image.resize((384, 384), Image.ANTIALIAS)
resized_image.save(path_)
return path_
views.py
if form.is_valid():
image = form.save(commit=False)
x = float(request.POST.get('x'))
y = float(request.POST.get('y'))
w = float(request.POST.get('width'))
h = float(request.POST.get('height'))
print(x)
print(y)
print(w)
print(h)
crop((x,y,w+x,y+h),image.pre_analysed,image.pre_analysed.path)
image.patient = patient
messages.success(request,"Image added successfully!")
image.save()
forms.py
class ImageForm(ModelForm):
x = forms.FloatField(widget=forms.HiddenInput())
y = forms.FloatField(widget=forms.HiddenInput())
width = forms.FloatField(widget=forms.HiddenInput())
height = forms.FloatField(widget=forms.HiddenInput())
class Meta:
model = UploadedImages
fields = ('pre_analysed', 'x', 'y', 'width', 'height', )
so what do I need to do here?
thanks in advance.
The path you get from .path is relative to your MEDIA_ROOT folder, which may prevent your crop function from being able to open() the image file.
You can then make a new cropped file somewhere in your MEDIA_ROOT. Be sure to use os.makedirs() to create all the directories between here and the file. Also I don't see you saving the path returned from crop() back into the ImageField.
Related
I'm looking to write a signature to PDF. I'm using JSignature and Reportlab. My code works successfully for writing the data to a file and the database. I just cannot figure out how to write the signature to the canvas. Has anyone passed the signature into the canvas successfully?
Thank you in advance.
Here's a look at my code:
pdf.py
import io
from django.core.files.base import ContentFile
from reportlab.lib.units import inch
from reportlab.pdfgen import canvas
from reportlab.lib.utils import ImageReader
def create_pdf(parent):
# create a file-like buffer to receive PDF data
buffer = io.BytesIO()
# create the pdf object, using the buffer as its "file"
p = canvas.Canvas(buffer)
# create text
textobject = p.beginText()
# start text at top left of page
textobject.setTextOrigin(inch, 11*inch)
# set font and size
textobject.setFont("Helvetica-Bold", 18)
textobject.textLine("My Document")
textobject.textLine("")
# write page 1
textobject.setFont("Helvetica", 12)
p_name = f'Name: {participant.first_name} {participant.middle_initial} {participant.last_name}'
textobject.textLine(p_name)
sig = f'Signature:'
textobject.textLine(sig)
----insert signature here----
# write created text to canvas
p.drawText(textobject)
# close the pdf canvas
p.showPage()
p.save()
buffer.seek(0)
# get content of buffer
pdf_data = buffer.getvalue()
# save to django File object
file_data = ContentFile(pdf_data)
# name the file
file_data.name = f'{participant.last_name}.pdf'
#
participant.pdf = file_data
participant.save()
Model:
class Participant(models.Model):
first_name = models.CharField(max_length=50)
middle_initial = models.CharField(max_length=50, blank=True)
last_name = models.CharField(max_length=50, blank=True)
signature = JSignatureField()
pdf = models.FileField(blank=True, null=True)
For those interested in how I was able to get this functioning. The primary issue was The image would be completely black when pulling it into the PDF. Here’s what is required:
In your View:
Use the Jsignature draw_signature function and get the image:
rsr_image = draw_signature(signature)
save the signature as a PNG and then store
# save signature as png to prevent darkening, save to model
rsr_file_name = str(new_parent.id)+'_rsr.png'
buffer = BytesIO()
rsr_image.save(buffer, 'PNG')
new_parent.rsr_image.save(rsr_file_name, File(buffer))
Create the following function, in order to…
Open the image, create a new background for the image, and save it.
def get_jpeg_image(new_parent):
# open png image
png_image = Image.open(new_parent.rsr_image)
# create new image with 'RGB' mode which is compatible with jpeg,
# with same size as old and with white(255,255,255) background
bg = Image.new("RGB", png_image.size, (255, 255, 255))
# paste old image pixels in new background
bg.paste(png_image, png_image)
# give image file name
file_name_jpeg = str(new_parent.id)+'.jpg'
bg.save(file_name_jpeg)
return file_name_jpeg
Reference that function inside your create PDF function to convert the PNG to JPG
jpeg_image = get_jpeg_image(participant)
Hope this helps someone.
I want to access the name of the file uploaded to models.FileField() in my class.
Here is my class
class extract(models.Model):
doc = models.FileField(upload_to='files/')
Is there a function or some method, to access the original name of the uploaded file, without modifying the name during upload.
like something like this
name = doc.filename()
Edit - 2:
I'm very new to django and programming in general. So this might seem stupid but I want something like this:
class extract(models.Model):
def get_name(instance,filename):
path = 'files'
name = filename
return name,path
doc = models.FileField(fname,upload_to==get_name)
def ex(fname):
path0 = "E:/Projects/PDF Converter/pdf/files/"
fullpath = path0 + fname
document = open(fullpath)
reader = PyPDF2.PdfFileReader(document)
page1 = reader.getPage(0)
data = page1.extractText()
return data
text = models.TextField(default=ex(fname),editable=False)
Per the documentation, this can be accomplished by passing a callback function as the upload_to argument, and the callback function will be called with the given filename as the second argument:
def get_filename(_, filename):
print(filename) # or do whatever you want with the original filename here
return 'files/'
class extract(models.Model):
doc = models.FileField(upload_to=get_filename)
I have a model
class Audiopart(models.Model):
book_id = models.ForeignKey(Audiobook, on_delete=models.CASCADE)
part_title = models.CharField(max_length = 255)
part_text = models.TextField(blank = True, null=True)
part_reader = models.CharField(max_length = 255)
filename = models.FileField(upload_to=get_upload_path, blank=True)
with function
def get_upload_path(instance, filename):
return os.path.join(
'audio',
instance.book_id.folder,
filename
)
I want to upload files in the directory and save in the database just filename (without path). But not found any way to do it.
So, I make a function for cleaning filename
def clear_filename(_filename):
if '/' in _filename:
_filename = _filename.split('/')[2]
return _filename
How can I print my objects in view with cleaned filename?
def audioparts(request, _book_id):
all_audioparts = list(Audiopart.objects.filter(book_id=_book_id, published=True).values())
return JsonResponse(all_audioparts, safe=False)
First of all, you're not understanding what the FileField is. It's actually for storing and accessing the file itself. So your field should not be called filename but file or audio_file or something that describes a file.
So when you have an instance of AudioPart, e.g. part, you can actually access the file directly: part.filename is the file in your code, not its name.
If you want a method to access just the name of the file, define a #property on your model:
import os
class AudioPart(Model):
file = FileField(...)
...
#property
def filename(self):
return os.path.basename(self.file.name)
then part.file is the file and part.filename is the name of the file. This way you can read() the file or return its url so people can download it (part.file.url) or manipulate it in other ways.
In your view, you can just loop over your files to add the filename to the list before returning your JSON.
I am trying to create a thumbnail from ImageField and save it to my model. I am using this as reference: http://www.yilmazhuseyin.com/blog/dev/create-thumbnails-imagefield-django/
Files are created correctly, I get no errors but fields are not saved in model.
I think i could messed things up in save method. What am I doing wrong?
Here is my code:
def get_avatar_path(instance, filename):
# file will be uploaded to MEDIA_ROOT/user_<id>/<filename>
return 'avatars/{0}/{1}'.format(instance.id, filename)
class User(AbstractUser):
# First Name and Last Name do not cover name patterns
# around the globe.
name = models.CharField(_('Name of User'), blank=True, max_length=255)
avatar = models.ImageField(upload_to=get_avatar_path, blank=True)
small_avatar = models.ImageField(upload_to=get_avatar_path,
blank=True)
def create_thumbnail(self):
# If there is no image associated with this.
# do not create thumbnail
if not self.avatar:
return
# Set our max thumbnail size in a tuple (max width, max height)
THUMBNAIL_SIZE = (200, 200)
DJANGO_TYPE = self.avatar.file.content_type
print DJANGO_TYPE
if DJANGO_TYPE == 'image/jpeg':
PIL_TYPE = 'jpeg'
FILE_EXTENSION = 'jpg'
elif DJANGO_TYPE == 'image/png':
PIL_TYPE = 'png'
FILE_EXTENSION = 'png'
elif DJANGO_TYPE == 'image/gif':
PIL_TYPE = 'gif'
FILE_EXTENSION = 'gif'
# Open original photo which we want to thumbnail using PIL's Image
image = Image.open(StringIO(self.avatar.read()))
# use our PIL Image object to create the thumbnail, which already
image.thumbnail(THUMBNAIL_SIZE, Image.ANTIALIAS)
# Save the thumbnail
temp_handle = StringIO()
image.save(temp_handle, PIL_TYPE)
temp_handle.seek(0)
# Save image to a SimpleUploadedFile which can be saved into ImageField
print os.path.split(self.avatar.name)[-1]
suf = SimpleUploadedFile(os.path.split(self.avatar.name)[-1],
temp_handle.read(), content_type=DJANGO_TYPE)
# Save SimpleUploadedFile into image field
print os.path.splitext(suf.name)[0]
self.small_avatar.save(
'%s_thumbnail.%s' % (os.path.splitext(suf.name)[0], FILE_EXTENSION),
suf, save=False)
def save(self, *args, **kwargs):
self.create_thumbnail()
super(User, self).save()
Thanks for feedback. Sorry for newbie problems, I am a beginner developer.
Problem seems to be resolved by invalidating caches, restarting IDE and services.
In my opinion code above should be persisted as some of solutions on the web are outdated.
I know this has been asked a couple of times, but I am new to django and couldn't find that in the documentation or here. I want to upload images to a class and the name should have the same name as the name of the class.
models:
import os
def upload_to_company(instance, filename):
blocks = filename.split('.')
ext = blocks[-1]
filename = "%s.%s" % (Cars.name, ext)
instance.title = blocks[0]
return os.path.join('media/', filename)
class Cars(models.Model):
image_file = models.ImageField(upload_to=upload_to_company, null=True, blank=True)
name = models.CharField(max_length=200)
How do I get the name of the cars class? I thought Cars.name will do it but it doesn't.
Can anyone help?
Thanks !
to get the class' name use
Cars.__name__
If you go through an object (e.g. camaro = Cars()), use
camaro.__class__.__name__
In case you want to name of the image to depend on one of the other model attributes (e.g. name)
def upload_to_company(instance, filename):
if hasattr(instance, 'imgpath'):
if os.path.exists(instance.imgpath):
os.remove(instance.imgpath)
blocks = filename.split('.')
ext = blocks[-1]
filename = "%s.%s" % (instance.name, ext)
instance.title = blocks[0]
instance.imgpath = os.path.join('media', filename)
return instance.imgpath
Note: that will always replace the existing file.
And finally, get your indentation right: the Cars class appears to be defined within the upload_to_company function.