Django, use of ForeignKey's value within model - django

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.

Related

Passing The ID of a Field in another Field of the same model Django

Hello, I am trying to pass the ID of a Model in an Image Field URL(upload_to) and then access it Through a URL unique to The instance.
Here's What I did (Amature);
class User(models.Model):
serial = models.AutoField(primary_key=True)
profile = models.ImageField(upload_to=f"profiles/{serial}/")
But all I'm Getting is OSError.
I wanted to save the file to profiles/{serial}/ directory in the app.
So Every Instance of the Model has its own Directory. And Then access it Through host:port/api/users/{serial}/profile.jpg
My View Set is served through host:port/api/users
Is there a way I can Do it?
Any Help is Highly Appreciated. A Detailed Explaination is Even more Appreciated.
From https://docs.djangoproject.com/en/3.0/ref/models/fields/#django.db.models.FileField.upload_to
upload_to may also be a callable, such as a function. This will be called to obtain the upload path, including the filename. This callable must accept two arguments and return a Unix-style path (with forward slashes) to be passed along to the storage system. The two arguments are: instance and filename
So you can do something like this
def profile_handler(instance, file_name)
return f"profiles/{instance.id}/{file_name}"
class User(models.Model):
serial = models.AutoField(primary_key=True)
profile = models.ImageField(upload_to=profile_handler)
on model override save method like this
def save(self,*args, **kwargs):
self.fieldname=currentmodel.objects.last().id+1
super(Orders, self).save(*args, **kwargs)

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)
...

sorl-thumbnail ImageField dynamic upload_to path

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)

django not taking in consideration model fields declared in __init__

When using Model class like this:
class MyModel(models.Model):
def __init__(self, *args, **kwargs):
self.myfield = models.Field()
super(MyModel, self).__init__(*args, **kwargs)
It doesn't take into consideration myfield(in the admin form, when saving the object... )
But if i declare like that:
class MyModel(models.Model):
myfield = models.Field()
It works just fine.
Why?
Edit
I think i have a good reason: I have an abstract class UploadItem that defines a field called file like this: self.file = models.FileField(upload_to=upload_to) As you can see, in each child class, i have to call parent init method with appropriate upload_to variable(say 'videos' for Video model). So i cannot do it the normal way.
Because the Django ORM code does some serious meta-magic during class definition (just browse the django/db code to see how magic). You are doing an end-run around that magic by creating fields on the fly in the __init__() function.
Is there a really good reason for not creating the class in the normal way? If not, then do it the normal way. If you do have a good reason then get ready to get into the really deep end of the pool -- both of Python and Django.
Setting a dynamic path for the upload_to attribute is absolutely not a good reason for wanting to muck around with model field declaration.
This is something that Django handles already - if you set upload_to to a callable, you can return the correct value dependent on the model instance. See the documentation.

Create & return a default ImageFieldFile from inside a function

In my UserProfile model I would like to have a function which returns either the user's ImageFileField object or a default image if the user has not uploaded their own.
For example:
class UserProfile(models.Model):
pic = models.ImageField('Headshot',blank=True,
upload_to=get_path_and_filename)
def get_pic(self):
if self.pic:
return self.pic
else:
# return ImageFileField with a default value
I want to return an equivalent ImageFileField because I have filters that work with this object type (so I can't just pass it a string, easily) ... I tried looking at the source code but I can't quite figure out how to do it myself.
Is there an easy way to initialize a new ImageFileField object by passing it a path to an image file and then return it?
PS: I had thought about using a default setting for the ImageField, however, it seems less flexible because the file is stored at model creation ... and if I later want to change the default file, I would have to update all the database entries that had the old file.
It was probably a typo, but what you actually want to return is an ImageFieldFile.
The ImageField makes the property of the model instance actually aa ImageFileDescriptor. When you access the property, it returns an ImageFieldFile instance.
As long as you don't call the save() or delete() methods of the ImageFieldFile, you can instanciate one reasonably easily:
from django.db.models.fields.files import ImageFieldFile, FileField
class UserProfile(models.Model):
# ...
def get_pic(self):
if self.pic:
return self.pic
return ImageFieldFile(instance=None, field=FileField(),
name='pictures/default.jpg')