How to get the slug STRING value in django models? - django

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)

Related

Dynamically naming an image file with another field name in Django2

I am trying to save an image file with the name changed to that of another field in the same form.
After some experimentation, it works well by using a handler function in the model, just when the object has been returned to the model for saving. I deconstruct the file object and can assign it a name that I want, However, I am not able to deconstruct the Charfield object and dynamically pass the first field name to the image file.
from django.db import models
import os
#handler function to customise file name.
def photo_path(instance, filename):
basefilename, file_extension= os.path.splitext(filename)
return '{add}/{room}/{basename}{ext}'.format
(add='my_Add', room="should_Be_room_type", basename= basefilename, ext= file_extension)
And the model is:
class Room(models.Model):
room_type = models.CharField( max_length=50) # i.e bedroom /living room etc
room_size = models.CharField( max_length=50)
img = models.ImageField( upload_to=photo_path, null=True, blank=True)
def __str__(self):
return self.room_type
in your case, the argument instance would be your Room instance, and you can use it to recover room_type and room_size. As the instance won't be created until after the image uploads, the only thing that won't be available on photo_path will be instance.id, but you don't need it.
Your function then, can be written as:
def photo_path(instance, filename):
basefilename, file_extension = os.path.splitext(filename)
return '{add}/{room}/{basename}{ext}'.format
(add='my_Add', room=instance.room_type, basename=basefilename, ext=file_extension)
Thanks, I ended up solving it in the view.py by using
my_room_type = request.POST['room_type']
initial_obj = form.save(commit=False)
initial_obj.save()
The idea was to get the value entered for the 'room_type' and print it on the image. It now works thanks.

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.

ORM update does not support file upload

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

Pathname to the image field in Django

I have this model which has Image field to be uploaded. It has a foreign key reference to another class.
from django.template.defaultfilters import slugify
def upload_to(path, attribute):
def upload_callback(instance, filename):
return '%s%s/%s' % (path, unicode(slugify(getattr(instance, attribute))), filename)
return upload_callback
class Data(models.Model):
place = models.CharField(max_length=40)
typeOfProperty = models.CharField(max_length=30)
typeOfPlace = models.CharField(max_length=20)
price = models.IntegerField()
ownerName = models.CharField(max_length=80)
class ImageData(models.Model):
property = models.ForeignKey(Data, related_name='images')
image = models.ImageField(upload_to = upload_to('image/', 'ownerName'),blank=True,null=True)
def __unicode__(self):
return self.property.ownerName
I have refered this This Web Page to create a dynamic field for images to be stored.
My doubt is can I use the onerName as the attribute in (as the ownerName is in the super class) :
image = models.ImageField(upload_to = upload_to('image/', 'ownerName'),blank=True,null=True)
How does Django consider this request that is need to be served?
Please can anyone explain me this?
'ownerName' is not going to work. It's quite complicated to do the definition of what you want to save in the ImageField directly. Maybe you should do something like this:
def upload_to(path):
def upload_callback(instance, filename):
return '%s%s/%s' % (path, unicode(slugify(instance.property.ownerName), filename)
return upload_callback
If you really want to make it as dynamic as possible you have to pass something like 'property.ownerName' to the function, split the string, retrieve attrtibute property from ImageData instance and then attribute ownerName from its foreign key instance.
Though I think this makes things way to complicated and you better define extra functions for different use cases.

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.