I'm trying to force certain FilerImageFields to be convert to another format on saving.
I've created this model
class SearchImage(FilerImageField):
def convert_to_webp(self):
print("in convert")
extension = ['jpeg', 'png', 'jpg', 'img', 'gif']
if any(ext in self.file.name.lower() for ext in extension):
#try:
img = Image.open(self.file)
correggi_nome = self.file.name.split('.')[0]
img.save(correggi_nome + '.webp','webp')
logger.debug('img.save save another copy of the file not repalced the original!')
#except Exception as ex:
# logger.error(ex)
def save(self, *args, **kwargs):
self.convert_to_webp()
print("Save search image")
super().save()
class Organisation(models.Model):
....
search_image = SearchImage(
related_name='+',
verbose_name=_('Search thumbnail image'),
help_text=_('Search thumbnail image'),
on_delete=models.SET_NULL,
blank=True,
null=True
)
....
def save(*args, **kwargs):
print('saving')
print("just before search thumbnail save")
self.search_image.save()
print("just after search thumbnail save")
super.save()
my SeachImage.save() is never called. When I save an image (or organisation) I see the print statements within the Organisation.save() but not the SearchImage.save(). How to I get this to work?
Okay so I went down a bit of a rabbit hole but it looks like you want to overwrite the Image object's save method, not the FilerImageField, which is a ForeignKey object:
class MyImageModel(Image):
def convert_to_webp(self):
print('in convert')
extension = ['jpeg', 'png', 'jpg', 'img', 'gif']
if any(ext in self.file.name.lower() for ext in extension):
print('Doing the conversion')
def save(self, *args, **kwargs):
self.convert_to_webp()
print('Save search image')
super().save(*args, **kwargs)
class SearchImage(FilerImageField):
default_model_class = MyImageModel
class Organisation(models.Model):
search_image = FilerImageField(
verbose_name='Search thumbnail image',
help_text='Search thumbnail image',
on_delete=models.SET_NULL,
blank=True,
null=True
)
def save(self, *args, **kwargs):
self.search_image.save()
super().save(*args, **kwargs)
Related
I'm new to Django I got an issue. I don't know how to retrieve the current post inside of models.py. I've tried different way for that.
'QuerySet' object has no attribute 'aliments'
or no error and no add to Post from ListAliments
get_object_or_404(Post, id=kwargs['id'])
here is my models.py
class ListAliments(models.Model):
name = models.CharField(max_length=40, unique=True)
slug = models.SlugField(editable=False)
status = models.IntegerField(choices=STATUS, default=1)
def save(self, *args,**kwargs):
if not self.slug:
self.slug = unique_slugify(self, slugify(self.name))
super(ListAliments, self).save(*args, **kwargs)
def __str__(self):
return self.name
class Post(models.Model):
title = models.CharField(max_length=190)
url_image = models.URLField(max_length=200, default=None)
aliments = models.ManyToManyField('ListAliments',blank=True, related_name='listaliments_post')
...
def save(self, *args, **kwargs):
if not self.slug:
self.slug = unique_slugify(self, slugify(self.title))
super(Post, self).save(*args, **kwargs) -> First save for Post which has not no ID
...
if self.url_image:
request = ...
response = ...
if response:
names = []
for concept in response.outputs[0].data.concepts:
current_aliments = ListAliments.objects.filter(name=concept.name)
current_post = Post.objects.filter(url_image=self.url_image) #get_object_or_404(Post, id=kwargs['id'])
if current_aliments.count()<1:
create_aliments = self.aliments.create(name=concept.name)
current_post.aliments.add(create_aliments)
else:
existed_aliments = ListAliments.objects.get(name=concept.name)
current_post.aliments.add(existed_aliments)
super().save(*args, **kwargs)
Post.objects.filter(url_image=self.url_image) returns QuerySet
in order to get object call first so Post.objects.filter(url_image=self.url_image).first(); note that you can get None
I am using the django-resized package to resize the image.
When I upload a PNG file using this package, the extension is changed to apng.
I don't want this extension to change..
Other image files are normally uploaded.
What should I fix it?
Background
- django==2.1.5
- django-resized==0.3.9
When use Django's default model.ImageField, the extension of png does not change.
# models.py
def upload_to(instance, filename):
return 'vip/{username}/{filename}'.format(
username=instance.whose.whose.username, filename=filename)
class VipIndex(models.Model):
whose = models.OneToOneField(Profile, on_delete=models.CASCADE, related_name='vipindex')
main_big_image = ResizedImageField(crop=['middle', 'center'], size=[500, 300], quality=50, blank=True, upload_to=upload_to)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['-created_at']
# forms.py
class VipMainForm(forms.ModelForm):
class Meta:
model = VipIndex
fields = (
'main_big_image',
)
def __init__(self, *args, **kwargs):
super(VipMainForm, self).__init__(*args, **kwargs)
self.fields['main_big_image'].widget.attrs = {'autocomplete': 'off', 'class': 'form-control'}
# views.py
#login_required
def profile_2(request):
if request.method == 'POST':
form_main = VipMainForm(request.POST, request.FILES)
if form_main.is_valid():
nav = form_main.save(commit=False)
nav.whose = request.user.profiles
nav.save()
return redirect('profile_2')
else:
form_main = VipMainForm()
return render(request, 'accounts/profile_2.html', {
'form_main':form_main,
})
Are there specific settings to keep the extension of the png file?
Add the following to settings.py
DJANGORESIZED_DEFAULT_FORMAT_EXTENSIONS = {'PNG': ".png"}
and it will override saving the file as .apng
I've a product-stock model as given below.
TRANSACTION_TYPE=(('I','Stock In'),('O','Stock Out'))
class Stock(models.Model):
product=models.ForeignKey('product.Product', blank=False,null=False)
date=models.DateField(blank=False, null=False,)
quantity=models.PositiveIntegerField(blank=False, null=False)
ttype=models.CharField(max_length=1,verbose_name="Transaction type",choices=TRANSACTION_TYPE, blank=False, db_index=True)
I need to log the update activity on this model, along with the id of the user who updated it.
ACTIONS=(('EC','Edit Category'),
('EG','Edit Group'),
('EP','Edit Product'),
('ES','Edit Stock'))
class MyLog(models.Model):
user=models.ForeignKey(auth.models.User, blank=False)
action= models.CharField(max_length=2, choices=ACTIONS, null=False,blank=False)
date=models.DateTimeField(blank=False, auto_now=True)
data = JSONField()
I've the added following code to the Stock model.
def __init__(self, *args, **kwargs):
super(Stock, self).__init__(*args, **kwargs)
if self.pk != None :
self.__important_fields = ['product','date', 'quantity', 'ttype', ]
for field in self.__important_fields:
setattr(self, '__original_%s' % field, getattr(self, field))
field_name='__original_%s' % field
def save(self, *args, **kwargs):
if self.pk != None :
print("Editing")
flag=False
log=MyLog(user=?,action='ES')
log.data=[]
for field in self.__important_fields:
original=getattr(self, '__original_%s' % field)
if original != getattr(self, field):
flag=True
log.data.append({field : str(original)})
if flag:
log.save()
else:
print("Adding")
super(Stock, self).save(*args, **kwargs)
This works, when I hard code a user object into the line log=MyLog(user=?,action='ES').
I need to log the id of the user who performed this edit operation.
How can I achieve this?
Thanks.
Here's how I finally achieved my goal.
Instead of logging the event from the model, I switched my code to the forms.
Here's my final code.
mylog app model
ACTIONS=(('EC','Edit Category'),
('EG','Edit Group'),
('EP','Edit Product'),
('ES','Edit Stock'))
class MyLog(models.Model):
user=models.ForeignKey(settings.AUTH_USER_MODEL, blank=False)
model_id=models.IntegerField(default=0)
action= models.CharField(max_length=2, choices=ACTIONS, null=False,blank=False)
date=models.DateTimeField(blank=False, auto_now=True)
old_data = JSONField(default=None)
new_data = JSONField(default=None)
stock app - update view
class UpdateStock(UpdateView):
model=Stock
form_class=UpdateStockForm
def get_form_kwargs(self):
kwargs = super( UpdateStock, self).get_form_kwargs()
kwargs.update({'user_id': self.request.user.id})
return kwargs
stock app - update form
class UpdateStockForm(forms.ModelForm):
def __init__(self,pk= None, *args, **kwargs):
self.user_id=kwargs.pop('user_id')
super(UpdateStockForm, self).__init__(*args, **kwargs)
def clean(self):
cleaned_data = super(UpdateStockForm, self).clean()
quantity = cleaned_data.get('quantity')
date= cleaned_data.get('date')
priv_quantity=self.instance.quantity
priv_date=self.instance.date
if priv_quantity!=quantity or priv_date != date:
#log!
log=MyLog(user=auth.models.User.objects.get(pk=self.user_id),action='ES', model_id=self.instance.id)
log.old_data=[]
log.old_data.append({'date' : str(priv_date), 'quantity':priv_quantity })
log.new_data=[]
log.new_data.append({ 'date' : str(date), 'quantity':quantity })
log.save()
return cleaned_data
I have a model, which contains an ImageField. I want to autocreate 2 additional fields from that ImageField.
class Images(models.Model):
...
img = models.ImageField(upload_to='img')
#for autocreating
rimg = models.ImageField(upload_to='rimg', null=True, blank=True)
limg = models.ImageField(upload_to='limg', null=True, blank=True)
def create_rimg(self):
# some work for generating rimg
self.rimg.save()
def create_limg(self):
# some work for generating limg
self.limg.save()
def save(self, *args, **kwargs):
self.create_rimg()
self.create_limg()
force_update = False
if self.id:
force_update = True
super(Images, self).save(force_update=force_update, *args, **kwargs)
That code gives a 500 error. If i call that code, it works perfect:
def save(self, *args, **kwargs):
self.create_rimg()
#self.create_limg()
force_update = False
or
def save(self, *args, **kwargs):
#self.create_rimg()
self.create_limg()
force_update = False
How can i call that 2 functions in save() method?
I have a django model that takes an audio file:
class Thing(models.Model):
audio_file = AudioFileField( upload_to=audio_dir, blank=True, null=True )
photo_file = models.ImageField( upload_to=img_dir, blank=True, null=True )
...
where the AudioFileField is a subclass of FileField that performs some validation:
class AudioFileField(models.FileField):
def validate(self, value, model_instance):
try:
if not (value.file.content_type == "audio/x-wav" or
value.file.content_type == "audio/amr" or
value.file.content_type == "video/3gpp"):
raise ValidationError(u'%s is not an audio file' % value)
except IOError:
logger.warning("no audio file given")
and the audio_dir callback sets the path and renames the file:
def audio_dir(instance, filename):
return os.path.join("audio", "recording_%s%s" % (
datetime.datetime.now().isoformat().replace(":", "-"),
os.path.splitext(filename)[1].lower() ))
In Django REST framework the ImageField works fine, but the subclassed AudioFileField doesn't. This is because the subclass serializers.FileField doesn't accept the keyword argument upload_to.
How can I expose the same functionality through the API? The audio_dir callback is particularly important to me.
I search how to customize filefield and I don't know if it's fix your problem. If not I will search again for it and just tell me the error.
class Thing(models.Model):
audio_file = AudioFileField(
upload_to=audio_dir,
blank=True, null=True,
content_types=['audio/x-wav', 'audio/amr', 'video/3gpp']
)
...............
class AudioFileField(models.FileField):
def __init__(self, *args, **kwargs):
self.content_types = kwargs.pop("content_types")
super(AudioFileField, self).__init__(*args, **kwargs)
def clean(self, *args, **kwargs):
data = super(AudioFileField, self).clean(*args, **kwargs)
audio_file = data.audio_file
try:
content_type = audio_file.content_type
if content_type in self.content_types:
raise ValidationError(u'{0} is not an audio file'.format(content_type))
else:
raise forms.ValidationError(_('Audio file type not supported.'))
except AttributeError:
pass
return data