I'd like to save uploaded images to separate folders. So for example user 4 photos should be stored in /media/images/4/
Here is the function and model and views that I came up with:
Model:
def get_uplaod_file_name(user,filename):
return 'photos/%s/%s_%s' % str(user.id), (str(time()).replace('.','_'), filename)
class UserPic(models.Model):
user = models.ForeignKey(User, unique=False)
picfile = ImageWithThumbsField(upload_to= get_uplaod_file_name, sizes=((200,200),(1200,1200)))
caption = models.CharField(max_length=200 , blank=True, null=True)
created_at = models.DateTimeField(auto_now_add=True)
#models.permalink
def get_absolute_url(self):
return ('view_pirate', None, {'user': self.account.user})
def __unicode__(self):
return unicode(self.picfile.name)
Views:
#login_required
def upload(request):
# Handle file upload
thisuser =User.objects.get(username = request.user.username)
# Load pics of this user
if request.method == 'POST':
picform = PicForm(request.POST, request.FILES)
if picform.is_valid():
newpic = UserPic(picfile = request.FILES['picfile'])
newpic = picform.save(commit=False)
newpic.user_id = request.user.id
newpic.save()
message = "file %s is uploaded" % newpic
else:
picform = PicForm() # A empty, unbound form
args= {}
args['picform'] = picform
return render_to_response('userpics/upload.html',args,
context_instance=RequestContext(request))
However, after many tweaks of get_uplaod_file_name it still does not work. I get errors like:
TypeError at /pics/upload/
not enough arguments for format string
Appreciate your help to resolve this.
You should pass a tuple to the string formatting operator:
def get_uplaod_file_name(userpic, filename):
return u'photos/%s/%s_%s' % (str(userpic.user.id),
str(time()).replace('.', '_'),
filename)
Note the first and last round brackets.
Also note the unicode prefix u' which is mandatory in case if user will upload a file with non-ascii symbols in the name.
Related
I have a userprofile that captures the username and the group the user is assigned to. I want the uploaded files to be saved under the group name folder. The folders already exit at the media root, the files shoud be routed to these folder
I solved the problem by the solution given. Now the username is shown as a dropdown list on the upload page. I want only the logged it username to be shown or exclude even showing it
models.py
class uploadmeta(models.Model):
path = models.ForeignKey(Metadataform, on_delete=models.CASCADE)
user_profile = models.ForeignKey(UserProfile, on_delete=models.CASCADE, null=True, verbose_name='Username')
tar_gif = models.FileField(upload_to=nice_user_folder_upload, verbose_name="Dataset") # validators=[FileExtensionValidator(allowed_extensions=['tar', 'zip'])]
def __str__(self):
return self.request.user.username
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
Group= models.CharField(max_length=500, choices=Group_choices, default='Please Select')
def __str__(self):
return self.user.username
view.py
def uploaddata(request):
if request.user.is_authenticated:
if request.method == 'POST':
form = uploadmetaform(request.POST, request.FILES)
if form.is_valid():
form.save()
return redirect('file_list')
else:
form = uploadmetaform()
return render(request, 'uploaddata.html', {
'form': form
})
else:
return render(request, 'home.html')
forms.py
class uploadmetaform(forms.ModelForm):
count = Metadataform.objects.all().latest('id').id #To know the id of latest object
data = Metadataform.objects.all().filter(id=count) #return the queryset with only latest object
path = forms.ModelChoiceField(queryset=data)
def __init__(self, *args, **kwargs):
super(uploadmetaform, self).__init__(*args, **kwargs)
count = Metadataform.objects.all().latest('id').id
data = Metadataform.objects.all().filter(id=count)
self.fields['path'] = forms.ModelChoiceField(queryset=data)
class Meta:
model = uploadmeta
fields = ['path', 'user_profile','tar_gif',]
You can use the upload_to argument in the FileField.
It accept a string representing the path where you want to store the file or you can pass in a function which let you add more details.
More info from the doc: https://docs.djangoproject.com/fr/2.2/ref/models/fields/#django.db.models.FileField.upload_to
You may need to add a foreign key form uploadmeta to UserProfile like :
user_profile = models.ForeignKey(UserProfile, on_delete=models.PROTECT)
Then you can use the following
def nice_user_folder_upload(instance, filename):
extension = filename.split(".")[-1]
return (
f"your_already_definied_folder/{instance.user_profile.group}/{file}.{extension}"
)
Then use it in uploadmeta FileField
doc = models.FileField(upload_to=nice_user_folder_upload, verbose_name="Dataset")
Here I am trying to upload multiple files but it's not working properly.I got problem while storing the foreign key for each files selected ?
I got this error.
Cannot assign "<property object at 0x04667960>": "MoreImage.image_title" must be a "Gallery" instance.
models
class Gallery(models.Model):
image_title = models.CharField(max_length=100, blank=True, null=True)
image_date = models.DateField(blank=True, null=True)
image = models.ImageField(upload_to='gallery', default='default.png')
class MoreImage(models.Model):
image_title = models.ForeignKey(Gallery, on_delete=models.CASCADE)
images = models.ImageField(upload_to='moreimage', default='default.png')
date = models.DateTimeField(auto_now_add=True)
views
def add_more_image(request):
images = Gallery.objects.all().order_by('-date')
if request.method == 'POST':
form = MoreImageForm(request.POST or None, request.FILES or None)
if form.is_valid():
more = form.save(commit=False)
for file in request.FILES.getlist('image'):
MoreImage.objects.create(image_title=Gallery.pk, images=file)
#for field in request.FILES.keys():
#for form_file in request.FILES.getlist(field):
#img = MoreImage(image_title_id=Gallery.pk,images=form_file)
#img.save()
more.save()
messages.success(request, ' Images added.')
return redirect('admin:add_gallery')
MoreImage Form
class MoreImageForm(forms.ModelForm):
class Meta:
model = MoreImage
fields = '__all__'
First of all, you shouldn't call Gallery.pk because it's won't return anything since it's a class. It should be something like gallary_instance.pk
and I don't think gallary_instance.pk will work for you because you've set commit=False which prevent to save the object into DB.
Try this,
def add_more_image(request):
images = Gallery.objects.all().order_by('-date')
if request.method == 'POST':
form = MoreImageForm(request.POST or None, request.FILES or None)
if form.is_valid():
more = form.save() # remove commit=False
for file in request.FILES.getlist('image'):
MoreImage.objects.create(image_title=more.image_title, images=file)
messages.success(request, ' Images added.')
return redirect('admin:add_gallery')
I am making a kind of inventory where the ids of the existing items are written in a text file and I only need to upload the text file to the server.
I have uploaded videos, images and TIFFs to the same server without problems, but I have no idea why it is not working now!
My model:
def inventory_file_path(instance, file_name):
name = instance.date.__str__()+'.txt'
path = concatenate_paths([inventory_folder, name])
return path
class Inventory(models.Model):
date = models.DateField('Date', null=True, blank=True)
crosses = models.ManyToManyField(Cross,verbose_name='Crosses scanned', null=True, blank=True)
file = models.FileField(upload_to=inventory_file_path, blank=True, null=True)
The form:
class InventoryForm(forms.ModelForm):
class Meta:
model = Inventory
exclude = [InventoryFields.crosses]
file = forms.FileField()
def __init__(self, *args, **kwargs):
super(InventoryForm, self).__init__(*args, **kwargs)
end_year = datetime.date.today().year + 1
self.fields[InventoryFields.date].widget = forms.SelectDateWidget(years=range(start_year, end_year))
self.file = forms.FileField()
The views:
def new_inventory(request):
if request.method == GET:
inv = Inventory()
inv.date = datetime.date.today()
form = InventoryForm(instance=inv)
if request.method == 'POST':
form = InventoryForm(request.POST, request.FILES)
if form.is_valid():
inv = form.save()
when I check the database, the inventory object is being saved and it's date is right but the file is not uploaded. further more, the upload_to method is not being called
I'm using python-social-auth to log users in to my site, which works fine but I want to use a custom user model that will not only save basic info about the user, but also gets their profile picture.
Here is my user model
def get_upload_file_name(instance, filename):
return "%s_%s" % (str(time()).replace('.', '_'), filename)
class UserProfile(models.Model):
user = models.OneToOneField(User, unique=True)
name = models.CharField(max_length=250, null=True, blank=True)
profile_image = models.ImageField(upload_to = get_upload_file_name, null=True, blank=True)
def __str__(self):
return u'%s profile' % self.user.username
This is the pipeline function
def user_details(strategy, details, response, user=None, *args, **kwargs):
if user:
if kwargs['is_new']:
attrs = {'user': user}
if strategy.backend.name == 'facebook':
fb = {
'name': response['first_name']
}
new_user = dict(attrs.items() + fb.items())
UserProfile.objects.create(
**new_user
)
elif strategy.backend.name == 'google-oauth2':
new_user = dict(attrs.items())
UserProfile.objects.create(
**new_user
)
elif strategy.backend.name == 'twitter':
new_user = dict(attrs.items())
UserProfile.objects.create(
**new_user
)
And this is the other function that gets the user profile image
def save_profile_picture(strategy, user, response, details, is_new=False,
*args, **kwargs):
if is_new and strategy.backend.name == 'facebook':
url = 'http://graph.facebook.com/{0}/picture'.format(response['id'])
try:
response = request('GET', url, params={'type': 'large'})
response.raise_for_status()
except HTTPError:
pass
else:
S_user = setattr(UserProfile, "profile_image", "{0}_social.jpg".format(user.username), ContentFile(response.content))
S_user.save()
I'm only trying it on facebook first, but I can't seem to populate the name field in the database, and I also have to sign in twice before it gets saved to the default social-auth table. Both functions have been added to the settings.py file, I was also wondering if it matters where they go in the cue if it matters since they're at the bottom, the last part of the auth process?
I figured it out, since i was using python3 i should of used list() on my dict values like so: attrs = dict(list(attrs.items()) + list(fb_data.items()))
Also instead of saving the image in the database it was best just to save the url, saving alot of space
I am totally new in Django and I'm trying to use django forms for the first time. I have searched for this but I still haven't exactly found the answer. Basically I have a view like this:
def pay(request):
if request.method == 'POST':
form = PaymentForm(request.POST)
if form.is_valid():
# I have to calculate the checksum here
myModel = form.save()
else:
print form.errors
else: # The request is GET
form = PaymentForm()
return render_to_response('payment/payment.html', {'form':form})
and I want add an additional field, checksum to the form from the inputs I got from the form So when the user submits the entries the checksum should be added and added to the form and the form should be sent to an external server. But I don't know how to do that (I have defined checksum in my Model). Could anyone help me on this?
My model looks like this:
class PaymentModel(models.Model):
alphanumeric = RegexValidator(r'^[0-9a-zA-Z]*$', 'Only alphanumeric characters are allowed!')
secret_key = '6cd118b1432bf22942d93d784cd17084'
pid = models.CharField(primary_key=True, max_length=50, validators=[alphanumeric])
sid = models.CharField(primary_key=True, max_length=50, validators=[alphanumeric])
amount = models.DecimalField(max_digits=9, decimal_places=2)
success_url = 'http://localhost:8000/success'
cancel_url = 'http://localhost:8000/cancel'
error_url = 'http://localhost:8000/error'
checksum = 0
def calc_checksum(self):
checksumstr = "pid=%s&sid=%s&amount=%s&token=%s"% (self.pid, self.sid, self.amount, self.secret_key)
m = md5(checksumstr)
checksum = m.hexdigest()
return checksum
def __unicode__(self): #returns the unicode representation of the object
return self.name
and my form looks like this:
class PaymentForm(ModelForm):
class Meta:
model = PaymentModel
You can use the commit=False keyword argument to form.save():
def pay(request):
if request.method == 'POST':
form = PaymentForm(request.POST)
if form.is_valid():
# Will not save it to the database
myModel = form.save(commit=False)
# keep your business logic out of the view and put it on the form or model
# so it can be reused
myModel.checksum = form.calculate_checksum()
myModel.save()
else:
print form.errors
else: # The request is GET
form = PaymentForm()
return render_to_response('payment/payment.html', {'form':form})
Django form.save() documentation.