sorl-thumbnail ImageField dynamic upload_to path - django

I know theres a way to dynamic upload path in django ImageFields and FileFields, which is to pass a upload_to=callable in the field, but is there a way to achieve this with sorl-thumbnail ImageField?
This is my model.py, Im getting a upload_path not defined!
class Brand(models.Model):
title = models.CharField(max_length=255, null=True, blank=True)
photo = sorl.thumbnail.ImageField(upload_to=upload_path)
external = models.BooleanField(_('External Brand? ("Key Account")?'))
def upload_path(self):
return u'%s' % self.title

See this related SO question.
Sorl-thumbnail doesn't do anything special with upload_to. It merely punts the handling of passed arguments via inheriting from Django's FileField, so anything that works with a standard FileField or ImageField will work with sorl-thumbnail's ImageField as well.
I think your problem is defining the method on the model. Every implementation I've ever seen or done myself has the method being outside the model. Django automatically passes in the instance to the method, so that's how you access the data on the model -- not through self.

I use this callback with sorl:
def get_image_path(instance, filename):
"""
puts image in MEDIA_ROOT/photos/instance_id/file
"""
return os.path.join('photos', str(instance.id), filename)
class Brand(models.Model):
...
photo = sorl.thumbnail.ImageField(upload_to=get_image_path)

Related

Checksums are calculated after the form validation: how to notify the users of an error

Django 1.11.6
I'm developing a document archive. So, I calculate checksums to control that documents are still present, that they are not corrupt etc.
Another side of this is that I can control whether a file has already been uploaded. It is important: no need to duplicate the files.
I upload files through Django admin. There is a form prepared.
But the problem is: form validators seems to be not very useful here.
At least I can't invent how to use a form validator here.
But post_save signal are useful: here we have a file already uploaded. We calculate the checksum of the file (using md5).
But if unique=True for the checksum, IntegrityError is risen.
It is Ok and predictable. But could you help me understand how to notify the user about this? Any method would suffice. It is just for our staff: no need to organize a brilliant html layout. But what is important is to show that the uploaded file coincides with an existing file with the following id.
Could you help me with this?
models.py
class FileChecksum(models.Model):
checksum = models.CharField(blank=True,
null=False,
unique=True,
max_length=255,
verbose_name=_("checksum"))
def __str__(self):
return self.checksum
class Image(models.Model):
file = models.ImageField(blank=False,
verbose_name=_("Image"),
max_length=255,
upload_to=get_sheet_path)
file_checksum = models.OneToOneField(FileChecksum,
blank=True,
null=True)
#property
def checksum(self):
pass
#checksum.setter
def checksum(self, new_checksum):
pass
signals.py
#receiver(post_save, sender=Image)
def save_file_checksum(sender, instance, **kwargs):
new_checksum = get_checksum(instance.file.path)
instance.checksum = new_checksum
admin.py
class ImageForm(FileMixin,
ModelForm):
model = Image
class ImageAdmin(admin.ModelAdmin):
form = ImageForm
admin.site.register(Image, ImageAdmin)
You have to calculate it before you save. That way your form can benefit from it and form validation will take care of bubbling up the error to the user. Decouple the get_checksum function away from the signals and calculate it as part of the form validation.
I had the same situation where I had a non-trivial hash calculation. So as soon as all the other basic validation stuff was done, I calculated the has with a function and if it clashed, made it part of the form (invariants) validation. If it didn't clash, it got used in about-to-be-created instance.
But I also, made it so that if you try to create an instance of the model, but don't have a hash set, a pre_save signal would create it. Useful for code paths where the item isn't coming in from a regular form.

django model filefield having db error

I am using django 1.4 and using django model's filefield to upload some document via modelform. I am having following issues:
When I submit form it says:
Data truncated for column 'file_name' at row 1
Following is my model for this:
class App(models.Model):
user_name=models.CharField(max_length=50)
email=models.CharField(max_length=50)
status=models.CharField(max_length=10,choices=APPLICATIONSTATUSCHOICE)
archived=models.BooleanField()
mark_spam=models.BooleanField()
date=models.DateField()
file_name=models.FileField(upload_to=PATH+"/")
def getPath(self):
return PATH
def __unicode__(self):
return self.user_name
def send_email(self):
pass
Here is the code for model form:
class AppForm(ModelForm):
class Meta:
model=App
exclude=('status','archived','mark_spam')
email=forms.EmailField()
def save(self,commit=True):
app=super(AppForm,self).save(commit=False)
app.status='sent'
app.save()
Also it is storing file with its original name,can I have it with something unique name as I am from PHP background and in PHP I normally save it like <mysql auto id>.<filextension>, so how can I do it in django. My first impression was that all this will be automatically done via django while it just save it with name of its own choice but I need to save names into db also so want to name them according to my choice. How can it be done and what is problem in my code that is giving above mentioned error?
How long is the file_name you are trying to store?
By default, FileField instances are created as varchar(100) columns in your database. As with other fields, you can change the maximum length using the max_length argument. That might be resulting the data truncation error.
Also you can rename your file whatever you want. the upload_to can be a callable that takes the instance and the name of the uploaded file as input and then you can specify the exact name and path you want to store.
Eg.
def get_file_name(instance, filename):
return '/'.join(['blah', instance.user.username, filename])
...
file_name=models.FileField(upload_to=get_file_name)
...

Django, use of ForeignKey's value within model

I would like to make a system, which is photos belong to projects. I also enabled that I can upload a zipfile directly for a project and it will unzip and register the photos to the specified project. However, I am having troubles while defining the Photo class.
I need to get the value of Project.file_zip.path with the current instance for defining img field's upload_to attribute. However, when I tried like below, it returns with AttributeError: 'ForeignKey' object has no attribute 'file_path'. How do I fix that?
class Project(models.Model):
....
owner=models.ForeignKey(User)
file_zip=models.FileField(upload_to='projects/%Y/%m/%d')
def __unicode__(self):
return self.project_name
def file_path(self):
return re.search(re.search('[^\s]+(?=\.zip)', self.file_zip).group(0))
class Photo(models.Model):
belongs_to=models.ForeignKey(Project)
img=models.ImageField(upload_to='/home/contact/python_project/all_bugs_will_reveal/'+belongs_to.file_path())
desc=models.CharField(max_length=255)
You can't refer to fields in a model within that same model's definition, as at the point when the definition is being read the class hasn't been defined yet.
The solution is to use a callable for upload_to - as shown in the documentation, this can be a function that is given the parameters instance and filename, so you can call instance.filepath() to get the correct path.

Djangothumbnails app issue

I an using this plugin to generate thumbnails. But somhow I couldn't make it work. The models work well, as images can be uploaded from the admin interface, even thumbnails get generated. I uploaded an image named "myphoto.jpg". The view I have is this.
def mainpage(request,slug):
page = get_object_or_404(MainPage, slug=slug)
image = get_object_or_404(Image)
return direct_to_template(request, 'flatpage.html',
extra_context={
'page':page,
'image':image,
})
I have defined the class in models as "Image". I had this in the template:
<img src="{% image.photo.myphoto_125x125 %}"> But the template shows error.
This is my model:
class Image(models.Model):
title = models.CharField(max_length=100)
photo = ImageWithThumbsField(upload_to='images/', sizes=((125,125),(200,200)))
# second_photo = ImageWithThumbsField(upload_to='site_media/images')
def __unicode__(self):
return self.title
The second field, "second_photo" I have commented out as it created duplicate copy of the main image. Even I am looking for a way to create entry for actual unsized image in the first field itself.
I havent tried this app, but I am using PIL to create thumbnail versions of uploaded images, and using a def in the model to retrieve the path to the thumbnail for display. This may be more of a manual approach than you are looking for but it works ok for me. You can override the save method on your model (which has your FileField) or send a post_save signal to a def to create the thumbnail.
But curious to know if this app you are using adds some useful functionality over this manual approach.
Somehow I got it working. Instead of creating a separate class, I used this line photo = ImageWithThumbsField(blank=True, upload_to='images/', sizes=((125,125),(200,200))) in my blog class. And I used the line {{% post.photo.url_125x124 %} in my index.html template.

Django admin: Default model display problem

In django models, if we have
def __unicode__(self): then it will be used as how you want to display the model by default
Now in django admin, I want to have a custmized display field(showing this object as an url so can navigate to this object), but I can't change unicode method for it used for other purpose. What do I supposed to do?
You can create a custom method for admin class
class SomeModelAdmin(admin.ModelAdmin):
list_display = ('__unicode__', 'active_status')
def active_status(self, obj):
if obj.profile.is_active:
return """One"""
return """Two"""
active_status.allow_tags = True
active_status.description = ""
This is just very simple example, so you can put your logic into this function
You can also return some html code
Don't use __unicode__ for a purpose like setting a convenience URL.
That will obscure your printed object name for any other purpose.
From which view are you trying to create a link? From the changelist view? From the change view? From a foreign key?
In general, you can simply define any method on your model (or ModelAdmin), that returns a full HTML link <a href=, set allow_tags = True, and refer to it in your admin fields.
# models method
def admin_url(self):
return 'Edit Model' % the_url
admin_url.allow_tags = True
# ModelAdmin method, through ForeignKey
def admin_url(self, obj):
return 'Edit Model' % obj.foreignkey.url
admin_url.allow_tags = True
I agree with those answers, but on my machine just not working.
I was using Python3 and Django1.8, and try to use this.
class MyModel(models.Model):
name = models.CharField(max_length=60)
def __str__(self):
return 'MyModel: {}'.format(self.name)