Getting Request in admin.py - python

I have a model like this:
class Item(models.Model):
code = models.CharField(max_length=200, unique=True)
barcode = models.CharField(max_length=300)
desc = models.CharField('Description',max_length=500)
display_desc = models.CharField('Description',max_length=500,
blank=True, null=True)
price = models.FloatField()
discountable = models.BooleanField(blank=True, default=False)
image_path = models.CharField(max_length=300,unique=True, blank=True, null=True)
def __unicode__(self):
return self.code + ' : ' + self.desc
But unfortunately, I don't want to store the item's image in the database, instead I want to store the image path in the server in the image_path column.
So, I created a custom admin.py for this object so that I could edit/insert the object thru the Django admin module. As a result, below is the customized admin.py
class ItemAdminForm(forms.ModelForm):
file_upload = forms.FileField(required=False)
class Meta:
model = Item
def __init__(self, *args, **kwargs):
super(ItemAdminForm, self).__init__(*args,**kwargs)
#if kwargs.has_key('instance'):
# instance = kwargs['instance']
# self.initial['file_upload'] = instance.file_upload
def handle_uploaded_file(f):
destination = open('D:/Project/pensel/penselshop/static/picture', 'wb+')
for chunk in f.chunks():
destination.write(chunk)
destination.close()
return f.name
def save(self,commit=True):
name = None
extension = None
#error here! How could I get the request?
miniform = ItemAdminForm(request.POST, request.FILES)
if miniform.is_valid():
name = handle_uploaded_file(request.FILES['file_upload'])
extension = name.split('.')[1]
model = super(ItemAdminForm, self).save(commit=False)
model.image_path = '/static/picture/' + model.code + extension
if commit:
model.save()
return model
However, during processing the save() function, I noticed that there is an error in getting the request. How can I get the request so that I could retrieve the file? I noticed that the request is automatically added in views.py, but not admin.py

Django's ImageField and FileField fields don't actually store the image in the database either. All that is stored in the database is the path, which you can control yourself. The actual image file is stored on the filesystem. So I'm not sure why you are going to all this trouble...?
But to answer your question of how to get the request in the admin, you can override ModelAdmin.save_model().

Related

Django - uploading file to folder named with id of the object

I was trying to make it this way but instead of {{product.id}}, folder is named None.
I read some articles about that, and I found out that is because folder is being made before whole object. So how should I do that to make it work?
models.py:
def getImageURL(self, filename):
return "products_images/" + str(self.pk) + "/product_image.png"
class Product(models.Model):
name = models.CharField(max_length=200)
image = models.ImageField(upload_to=getImageURL, default="media/static/products_images/default.png" )
changed my funtion to:
def getImageURL(instance, filename):
return "products_images/{}/product_image.png".format(instance.id)
But it works only while edditing existing object. When I'm trying to make a new one id is set to None.
Edit:
ok, finally I did it this way:
def getFileNumber():
queryset = Product.objects.all().order_by('pk')
last = queryset.last()
last_id = last.id
file_number = last_id+1
return str(file_number)
def getImageURL(instance, filename):
return "products_images/{}/product_image.png".format(getFileNumber())
class Product(models.Model):
name = models.CharField(max_length=200)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
availability = models.IntegerField()
price = models.DecimalField(max_digits=5, decimal_places=2)
Probably it is not the best way to do that but it's very simple to understand so why not to use it.
Some debugging:
def getFileNumber():
queryset = Product.objects.all().order_by('pk')
if queryset:
last = queryset.last()
last_id = last.id
file_number = last_id+1
return str(file_number)
else:
file_number=1
return str(file_number)
def getImageURL(instance, filename):
path = os.path.join("products_images/{}/product_image.png".format(getFileNumber()))
print(path)
if os.path.isfile("media/" + path):
print("image with this id already exist, ")
os.remove("media/" + path)
return path
else:
return path
class Product(models.Model):
name = models.CharField(max_length=200)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
availability = models.IntegerField()
price = models.DecimalField(max_digits=5, decimal_places=2)
The following is the issue:
The instance doesn't have a primary key yet before it is created
When the instance gets saved in the database, then you can get the primary key
Maybe use signals, somehow? Do the logic it in the view after saving it?
Alternative option to pk:
You can generate a UUID for the object.
id = models.UUIDField(
primary_key = True,
default = uuid.uuid4,
editable = False)
Or alternatively:
Have a look at this package, you can set the uuid alphabet, length, and some more. This would allow you access to the id, for sure (same with uuid).
https://pypi.org/project/shortuuid/
id = ShortUUIDField(
length=16,
max_length=40,
prefix="id_",
alphabet="abcdefg1234",
primary_key=True,
)
Sidenote:
def getImageURL(self, filename): #Self would normally be defined as instance, but I suppose this is just semantics.
This is because the id is saved to the model after calling save(). The first guess would be to use save() to get the object in return. But save() does not return anything. So I put together a little example
class Thingy(models.Model):
name = models.CharField(
_('name'),
max_length=64,
)
def save(self, *args, **kwargs):
super(Thingy, self).save(*args, **kwargs)
print(self.pk)
My test was:
>>> t = Thingy(name="lol")
>>> t.save()
1
And it printed the primary key since save() mutades self. You could check if the pk exists before save(). If yes, just add the image path. If not. Execute save() first, manipulate the image path using pk, and save the object again. It is not elegant in any way, but I guess that is the only way.

Django model foreignkey queries

So i have this two models in django:
class Course(models.Model):
def get_image_path(self, filename):
return os.path.join('courses', str(self.slug), filename)
def __str__(self):
return self.name
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
super(Course, self).save(*args, **kwargs)
name = models.CharField(max_length=255, verbose_name="Nombre")
description = models.CharField(max_length=255, verbose_name="DescripciĆ³n")
price = models.DecimalField(max_digits=12,decimal_places=2, verbose_name="Precio")
slug = models.SlugField(blank=True, max_length=255)
icon_img = models.ImageField(upload_to=get_image_path, blank=True, null=True, verbose_name="Imagen")
background_color = ColorField(default="#026085")
class Meta:
verbose_name = "curso"
verbose_name_plural = "cursos"
class UserCourse(models.Model):
user = models.ForeignKey(User)
course = models.ForeignKey(Course)
So whenever a user "buys" a course, it is stored in UserCourse. I have a view where the system shows a list of all the courses the user has bought. This is the view code:
def user_course_list_view(request, username):
context_dict = {}
try:
user_courses = UserCourse.objects.filter(user=request.user).course_set
context_dict['courses'] = user_courses
context_dict['heading'] = "Mis cursos"
except:
context_dict['courses'] = None
context_dict['heading'] = "Mis cursos wey"
return render(request, 'courses/course_list.html', context=context_dict)
I dont know where is the error and I cant seem to catch the exception (im using django with docker)
tl;dr
Something like this should work.
usercourse_objects = UserCourse.objects.filter(user=request.user).select_related('course')
user_courses = [x.course for x in usercourse_objects]
Explanation
There are multiple ways to do this, but one way would be to first get all the UserCourse objects for the current user:
usercourse_objects = UserCourse.objects.filter(user=request.user)
Then, for each UserCourse object, get the related Course:
user_courses = [x.course for x in usercourse_objects]
Now, the second line causes N database queries (one for each time we follow the course foreign key relation. To prevent this, the first line can be changed to:
usercourse_objects = UserCourse.objects.filter(user=request.user).select_related('course')
This pre-populates the course attribute of the UserCourse objects. More info about select_related() can be found here.

Django rest framework saving thumbnail image

I've recently started developing with django + python and everything was going very smooth until I got stuck into a problem that probably is very simple but I can not solve with my inexperience with the framework/language.
I'm receiving an JSON object through an HTTP Request which contains some data and 2 pictures. Prior to those 2 pictures I wanted to save a thumbnail from one of them but I don't see to get that task done. I can save all the data easily including the 2 images. But I can not see to find a way to generate a way an have that in the DB also, as well the folder structure that I want.
My folders should look like:
pictures
user
originals
processed
thumbnails
otherUser
originals
processed
thumbnails
My goal is: Receive 2 pictures, create a thumbnail from one of them and them save all 3 pictures in 3 separate folders and the path to the Database.
Here's how my model code looks like.
class SomeData(models.Model):
owner = models.ForeignKey('auth.User', related_name='canopeo_data')
adjustments = models.CharField(max_length=10)
latitude = GeopositionField()
longitude = GeopositionField()
notes = models.TextField(null=True, blank=True)
original_image = models.ImageField(upload_to=original_image, max_length=255, blank=True)
processed_image = models.ImageField(null=False, upload_to=processed_image, max_length=255)
thumbnail_image = models.ImageField(null=False, upload_to=thumbnail_image, max_length=255)
date_time = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ('date_time',)
def save(self, *args, **kwargs):
super(SomeData, self).save(*args, **kwargs)
def original_image(self, filename):
url = "pictures/%s/originals/%s" % (self.owner.username, filename)
return url
def processed_image(self, filename):
url = "pictures/%s/processed/%s" % (self.owner.username, filename)
return url
def thumbnail_image(self, filename):
url = "pictures/%s/thumbnail/%s" % (self.owner.username, filename)
return url
Serializer code...
class SomeDataSerializer(serializers.HyperlinkedModelSerializer):
#url = serializers.HyperlinkedRelatedField(view_name='data', format='html')
owner = serializers.Field(source='owner.username')
thumbnail_image = serializers.Field(source='original_image')
class Meta:
model = SomeData
fields = ('url', 'adjustments', 'latitude', 'longitude', 'notes', 'original_image', 'processed_image',)
View code...
class SomeDataViewSet(viewsets.ModelViewSet):
queryset = SomeData.objects.all()
serializer_class = SomeDataSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
def pre_save(self, obj):
obj.owner = self.request.user
I've tried many things such as easy_thumbnails, sorl_thumbnail, and some pre made methods on how to do it.. but I can't see to find a solution specific for what I've been wanting.
Thank you very much!
Looks like you have mistake in definition of the SomeDataSerializer. In model SomeData field original_image defined as ImageField, but in serialiser it's just Field, not ImageField. You should use correct field type:
class SomeDataSerializer(serializers.HyperlinkedModelSerializer):
#url = serializers.HyperlinkedRelatedField(view_name='data', format='html')
owner = serializers.Field(source='owner.username')
thumbnail_image = serializers.ImageField(source='original_image')
...

view permission if request data not in queryset

I have the following view -
class File_List(generics.ListAPIView):
model = cdx_composites_csv
serializer_class = cdx_compositesSerializer
def get_queryset(self):
"""
This view should return a list of all the purchases for
the user as determined by the username portion of the URL.
"""
filename = self.request.GET.get('filename')
model = get_model('markit', filename)
filedate = self.request.GET.get('filedate')
queryset = model.objects.using('markitdb').filter(Date__contains=filedate)
return queryset
For now ignore that model is listed twice it's the same model I need to figure that out later.
For permissions, I want it to deny access if the following occurs.
I have an extended Auth in my models.py
class FileIndex(models.Model):
filename = models.CharField(max_length=256)
filetype = models.CharField(max_length=16)
vendorid = models.IntegerField()
vendorname = models.CharField(max_length=256)
tablename = models.CharField(max_length=256)
class Meta:
db_table = 'file_index'
verbose_name = 'File/Vendor Index'
verbose_name_plural = 'File/Vendor Indicies'
def __str__(self):
return self.filename
class UserFile(models.Model):
userid = models.ForeignKey(User)
fileid = models.ForeignKey(FileIndex)
grant_date = models.DateTimeField()
revoke_date = models.DateTimeField(blank=True)
class Meta:
db_table = 'auth_files'
verbose_name = 'User File Matrix'
verbose_name_plural = 'User File Matricies'
I want to be able to say that if the filename does not show up in relation to the user access will be denied.
In SQL it's simply a matter of returning the list of filenames the user has access to -
select * from auth_files af
inner join auth_user au on au.id = af.userid
inner join file_index fi on fi.id = af.fileid
where au.user = 'user logged in'
then I want to tell it that if that if the filename in the request is in the list of filenames returned from the above query then yes the user can do what they want to do.
update - tweaking like so -
class File_List(generics.ListAPIView):
model = cdx_composites_csv
serializer_class = cdx_compositesSerializer
def get_queryset(self):
# authorized_files = UserFile.objects.filter(userid=self.request.user).values_list('fileid')
"""
This view should return a list of all the purchases for
the user as determined by the username portion of the URL.
"""
filename = self.request.GET.get('filename')
model = get_model('markit', filename)
filedate = self.request.GET.get('filedate')
if FileIndex.objects.filter(filename=filename).exists():
queryset = model.objects.using('markitdb').filter(Date__contains=filedate)
return queryset
I now get the following error -
'NoneType' object is not iterable
In your view you can check like this:
filename = self.request.GET.get('filename')
if FileIndex.objects.filter(filename=filename).exists():
#do something

dynamic FileField path

I'm trying to use get_file_path function to generate dynamic path. Can I use Album slug field instead of this str(instance.id) in get_file_path? thanks
Here is models
def get_file_path(instance, filename):
return os.path.join('files', str(instance.id), filename)
class Album(models.Model):
name = models.CharField(max_length=100)
slug = models.SlugField(unique = True,max_length=100,help_text="Suggested value automatically generated from name. Must be unique.")
path = models.CharField(max_length=100,null=True, blank=True)
language = models.ForeignKey(Category)
albumid = models.CharField(max_length=100)
class Song(models.Model):
title = models.CharField(max_length=100)
artist = models.ManyToManyField(Artist)
music = models.ForeignKey(Music)
album = models.ForeignKey(Album)
file = models.FileField(upload_to=get_file_path)
Update: I tried instance.slug . Its not working. instance.slug does not exist in Song Model. Its only exists in Album model ( Want to use Album Slug field)
Update2: Here is model snapshot
Quite straightforward: str(instance.album.slug)
Yes, just use instance.slug instead of instance.id
Another example you can find in the answer of post Change filename before save file in Django
Update: If not all instances have a slug field than you could be interested in a solution like this:
def get_file_path(instance, filename):
fld = getattr(instance, 'slug', instance.id)
return os.path.join('files', str(fld), filename)

Categories

Resources