django override model save method error - django

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?

Related

How to force a FilerImageField to convert image format

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)

Django models.py (API result) - retrieve current post to add api result

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

Django - how to create a file and save it to a field in ModelSerializer

I have a model with a FileField namely file_test
I would like to manually create a file and assign in to file_test in the serializer
Below are my code, would like some help. Thanks
class Test(models.Model):
file_test = models.FileField(storage=OverwriteStorage(),
upload_to=_get_landmark_upload_path, max_length=100, blank=True)
class TestSerializer(serializers.ModelSerializer):
test = serializers.CharField(write_only=True, required=True)
class Meta:
model = Test
fields = ('file_test','test')
def save(self, *args, **kwargs):
self.file_test.save('test.txt', ContentFile(self.validated_data['test']))
return super().save(*args, **kwargs)
Or is there a way to create a file and assign it to file_test?
example in serializer
def save(self, *args, **kwargs):
kwargs['file_test'] = ?????(how to create this file)
return super().save(*args, **kwargs)
I'd manage to solve the issue by using ContentFile
Look at example below
def save(self, *args, **kwargs):
kwargs['file_test'] = ContentFile(
self.validated_data['test'], name="test.txt")
return super().save(*args, **kwargs)

django - logging edit event - need to get id of logged in user

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

Why Couldn't I set the OneToOneField in ModelForm's save() function?

Let's say we got two model:
model.py
class Engine(models.Model):
name = models.CharField(max_length=25)
class Car(models.Model):
name = models.CharField(max_length=25)
engine = models.OneToOneField(Engine)
engine_admin.py
class EngineAdmin(admin.ModelAdmin):
def get_changelist_form(self, request, **kwargs):
return EngineChangeListForm
form.py
class EngineChangeListForm(forms.ModelForm):
class Meta:
model = Engine
fields = []
# this work!
def save(self, *args, **kwargs):
car_obj = Car.objects.create(engine = self.instance)
return super(EngineChangeListForm, self).save(*args, **kwargs)
if I change save() to below, it would create a new car object, but in the end, engine object's car field will be empty.
I don't understand why the code below won't work.
# this won't work!
def save(self, *args, **kwargs):
car_obj = Car.objects.create(engine = self.instance)
self.instance.car = car_obj
return super(EngineChangeListForm, self).save(*args, **kwargs)
You need to call super() first to save the engine, before you create the car.
def save(self, *args, **kwargs):
instance = super(EngineChangeListForm, self).save(*args, **kwargs)
car_obj = Car.objects.create(engine=instance)
return instance