ORM update does not support file upload - django

I have following model
class Category(models.Model):
name = models.CharField(max_length=30)
is_active=models.BooleanField()
photo=models.ImageField(upload_to='category')
def __unicode__(self):
name = str(self.name)
return name
class Meta:
permissions = (
('category','Category'),
('view_category', 'View category'),
)
My form class is as follows
class categoryForm(forms.Form):
name = forms.CharField(widget=forms.TextInput(attrs={'class':'box'}),max_length=32,label='Category',required=True)
is_active = forms.BooleanField(required=False)
id = forms.CharField(widget=forms.HiddenInput,required=False)
photo = forms.FileField(
required=False,
label='Select an Image',
help_text='max. 4 megabytes'
)
In view.py I have the following
formdata = categoryForm(request.POST,request.FILES)
if formdata.is_valid():
cd = formdata.cleaned_data
p1=Category()
p1.id=cd['id']
p1.name=cd['name']
p1.is_active=cd['is_active']
p1.photo=cd['photo']
p1.save()
It is working fine but when i changed it to the following, image is not uploaded
Category.objects.filter(id='%s'%(cd['id'])).update(name='%s'%(cd['name']),
is_active='%s'%(cd['is_active']),
photo=cd['photo']
)
I think the second method is faster way, but why it is not working for ImageField

the id in the code pasted above is a string, try converting it to an int. That will i guess make the filter query work and hence make the update on it work as well.

You shouldn't be passing a string to is_active. Just pass the boolean and it should work. Also, you shouldn't be writing code like '%s' % string; you can just use string

You need to use get_or_create

Related

Django-import-export doesn't skip unchanged when skip_unchanged==True

I'm building an app using Django, and I want to import data from an Excel file using django-import-export.
When importing data I want to skip unchanged rows, for this, I'm using skip_unchanged = True in the resource class (like below) but I get unexpected behavior. In my model, I have an attribute updated_at which is a DateTimeField with auto_now=True attribute, it takes a new value each time I upload the Excel file even if the values of rows have not changed in the file.
Below are portions of my code.
models.py
class HREmployee(models.Model):
code = models.IntegerField()
name_en = models.CharField(max_length=55)
status = models.CharField(max_length=75)
termination_date = models.DateField(null=True)
hiring_date = models.DateField()
birth_date = models.DateField()
# other fields to be imported from the file ...
# fields that I want to use for some purposes (not imported from the file)
comment = models.TextField()
updated_at = models.DateTimeField(auto_now=True)
resources.py
class HREmployeeResource(ModelResource):
code = Field(attribute='code', column_name='Employee Code')
name_en = Field(attribute='name_en', column_name='Employee Name - English')
status = Field(attribute='status', column_name='Employee Status')
termination_date = Field(attribute='termination_date', column_name='Termination Date')
hiring_date = Field(attribute='hiring_date', column_name='Hiring Date')
birth_date = Field(attribute='birth_date', column_name='Birth Date')
# other fields to be imported ...
class Meta:
model = HREmployee
import_id_fields = ('code', )
skip_unchanged = True
How can I fix this unexpected behavior?
Edit
After few tries, I've found that columns with date values are causing this problem.
In the Excel file, I have three columns that have date values like in the picture below, when I comment the corresponding attributes in the resource class and do the import, I get the expected behavior (if no changes in the file the import_type equals skip and no changes are made in the DB).
I've edited the code of the model and resource classes (please check above).
This should be easy to fix, simply use the fields parameter to define only the fields you wish to import (docs):
class Meta:
...
fields = ('code', 'name',)
If skip_unchanged is True, then only these fields will be compared for changes, and the instance will be updated if any one of them has changed, otherwise it will be skipped.
The field name has to be the model attribute name, not the name of the column in the import.
Sorry for the revival of that post, but I was stucked on the same issue, and I found only this post exaclty related to, so i post my answer.
In my model I've defined dateField and not DateTimeField.
But it import as DateTimeField, so the comparison failed.
To compare carrots with carrots, I defined a field class to convert values if needed :
import datetime
class DateField(Field):
def get_value(self, obj):
val=super().get_value(obj)
if isinstance(val, datetime.datetime):
return val.date()
return val
and then in my resource
class HREmployeeResource(ModelResource):
hiring_date = DateField(attribute='hiring_date', column_name='Hiring Date')
birth_date = DateField(attribute='birth_date', column_name='Birth Date')
# ....

How to get the slug STRING value in django models?

Basically, I have 3 classes (Vehicle, Car and Motorcycle, these 2 last extend the first one)... In the Vehicle class there's the main_image attribute which is a models.ImageField type, as you can see bellow:
class Vehicle(models.Model):
def __str__(self):
return self.title
[...]
main_image = models.ImageField(
upload_to = 'media/images/' + str(slug) + '/', verbose_name = 'Foto principal',
null = False
)
So, the str(slug) doesn't work properly, 'cause when I upload an image, it is always uploaded to
/media/images/<django.db.models.fields.SlugField>
when it should actually upload to
/media/images/(object-slug-value)/
I've tried many different things but any of them worked the way I wanted.
How can I get the string value from the slug attribute?
The slug you are using is the field in your model, not the instance. upload_to takes a callable, which you can use to build the path:
def get_path(instance, filename):
return 'media/images/{}/{}'.format(instance.slug, filename)
class Vehicle(models.Model):
.
.
.
main_image = models.ImageField(upload_to=get_path)

Django model field, alternative value return if null?

Is there a way to return a different set value for a django model field if that field has a null value?
I have users with profile images (image_url), for users who do not have one I'd like to return a default no avatar url, rather than 'None'.
class User(models.Model):
name = models.CharField(max_length=800)
image_url = models.URLField(max_length=2000, blank=True, null=True)
The easiest way is to just add an extra property to the model:
#property
def image_url_with_default(self):
return self.image_url or whatever_the_default_url_is
as #paulo-scardine suggested, just add a condition when you want to actually use it - i.e in a template, or if it's bound to be used in multiple places, as a method/property of the model (as #remcogerlich) suggested.
#property
def avatar(self):
return self.image_url or settings.DEFAULT_AVATAR_URL
Have you tried using the default option on the URLField?
you could do someting like:
image_url = models.URLField(max_length=2000, blank=True, null=True, default='http://misyte.com/default-image.jpg')
Haven't tested it... there's also an ImageField on django.. maybe you could check that too
Hope this helps
You could override the __getattribute__ method, per this answer. This has the advantage of not introducing an additional property (that you'll need to remember, or update any relevant references for):
class User(models.Model):
....
def __getattribute__(self, name):
attr = models.Model.__getattribute__(self, name)
if name == 'avatar' and not attr:
return 'path/to/default/img'
return attr
Oh, my... URL entered by the user... Looks dangerous.
class User(models.Model):
name = models.CharField(max_length=800)
image = models.ImageField(upload_to='avatars', blank=True, null=True)
def avatar(self):
if self.image: return self.image.url
return '/path/to/default/avatar.png'
If you store the image at your side you can at least run something like "nude" in order to analyze an image for nudity.

Django entry creating. Method in views/other file or as a method of model class

Django creating entry.
1) As seen in Django docs:
class Article(models.Model):
user = models.ForeignField(User)
title = models.CharField(#some_params)
content = models.CharField(#some_params)
date = models.DateTimeField(#some_params)
Then in my views I can:
new_article = Article(user=user, title="abc", content="xyz", date = datetime.utcnow())
new_article.save()
2) But it also can be done like by calling method within Article class, ie:
class Article(models.Model):
user = models.ForeignField(User)
title = models.CharField()
content = models.CharField()
def add_article(self, title, content):
self.title = title
self.content = content
self.date = datetime.utcnow()
self.save()
and then in views:
title = "abc"
content = "xyz"
new_article = Article(user=user)
new_article.add_article(abc, xyz)
I am asking because I have seen both ways of adding content into database. I would like to ask:
What is better practice?
Any concerns about security in 2nd example?
Option 1 is, in my opinion, better practice. add_article is unnecessary, because you can set the date by using the auto_now property of the date field, and everything else is already built-in. You'll have less code and less maintenance.

How can I add a related object to the Admin index view?

I want to be able to show if an Image has been associated with each Product from the list_display view.
I seem to be having trouble because I'm dealing with an associated object.
models.py
class ImageMain(models.Model):
"""This is the Main Image of the product"""
product = models.ForeignKey(Product)
photo = models.ImageField(upload_to='lcdtvs')
pub_date = models.DateTimeField('date published', auto_now_add=True)
class Product(models.Model):
name = models.CharField(max_length=100)
poll = models.ForeignKey(Poll)
pub_date = models.DateTimeField('date published', auto_now_add=True)
size = models.IntegerField(default=0)
admin.py
def photo_for_product(obj):
images = obj.imagemain_set.all()
return images[0].photo
class ProductAdmin(admin.ModelAdmin):
list_display = ('name', "photo_for_product")
inlines = [DescriptionInline, FeatureInline, AffiliateInline]
def upper_case_name(self, obj):
return ("%s" % (obj.name)).upper()
def photo_for_product(self, obj):
images = self.imagemain_set.all()
return images[0].photo
admin.site.register(ImageMain)
admin.site.register(Product, ProductAdmin)
For some reason, the upper_case_name() displays fine in the list view.
The photo_for_product() just keeps displaying (None).
I also tried use pdb in the photo_for_product method, but Django doesn't like that.
I also tried to put the callable before the ModelAdmin method, however, that created a lot of errors:
ProductAdmin.list_display[1], 'photo_for_product' is not a callable or an attribute of 'ProductAdmin' or found in the model 'Product'.
It's not clear from your question exactly what you want the output to be. You say you want to know "if an image has been associated" - if so, you could try this:
def photo_for_product(self, obj):
images = self.imagemain_set.all()
if images:
return True
else:
return False
photo_for_product.boolean = True
If you want to actually see the image, you'll need to return some HTML that renders it in an img tag.
def photo_for_product(self, obj):
images = self.imagemain_set.all()
if images:
return '<img src="%s">' % images[0].photo.url
else:
return ''
photo_for_product.allow_tags = True
Write a method that returns the necessary information as a string and add the name of the method to list_displays on your admin class.
I wanted the output to be a string of the path to the image. Apparently, the issue is that images[0].photo is am ImageFieldFile and not a string.
It seems that by default, ImageFieldFile has the following attributes:
ImageFieldFile.name
ImageFieldFile.path
ImageFieldFile.url
All those attributes return unicode strings.