I'm trying save a file into a folder created from my app, but the file always is saved out of the folder.
I've the view:
#login_required(login_url='/sn/login/')
def upload_file(request, folder_id=None):
user = UserProfile.objects.get_profile_user(request.user.email)
store, created = UserStore.objects.get_or_create(user=user)
if folder_id is not None:
parent_folder = UserFolder.objects.get_parent_folder(store, folder_id)
else:
parent_folder = None
if request.method == 'POST':
form = UploadFileForm(user, request.POST, request.FILES)
if form.is_valid():
form.save(parent_folder)
if not parent_folder:
return HttpResponseRedirect(reverse('store_view'))
else:
return HttpResponseRedirect(reverse('folder_view', args=(folder_id,)))
else:
form = UploadFileForm(user)
return render_to_response('quaba/storage/upload_file.html',
{'form': form, 'folder': parent_folder},
context_instance=RequestContext(request))
urls.py
url(r'^quaba/main/storage/upload_file/$',
'upload_file',
name='upload_file'),
url(r'^quaba/main/storage/folder/(?P<folder_id>[\d]+)/upload_file/$',
'upload_file',
name='upload_file_in_folder')
And forms.py
class UploadFileForm(forms.Form):
def __init__(self, user, *args, **kwargs):
super(UploadFileForm, self).__init__(*args, **kwargs)
self.fields['file'] = forms.FileField(label='...')
self.user = user
self.store = UserStore.objects.get(user=user)
def clean_file(self):
total_size = 0
all_files = UserFile.objects.all_files(self.store)
if all_files:
for fi in all_files:
total_size = total_size+fi.file.size
all_folders = UserFolder.objects.all_folders(self.store)
if all_folders:
for fo in all_folders:
total_size = total_size + fo.get_folder_size()
MAX_SIZE = 15728640 #12 MB
content = self.cleaned_data['file']
if content._size > MAX_SIZE:
raise ValidationError('...')
STORE_MAX = 5368709120 #5 GB
if total_size+content._size > STORE_MAX:
raise ValidationError('...')
return content
def save(self, folder):
if folder:
userfile = UserFile(store=self.store,
file=self.cleaned_data['file'],
creator=self.user,
parent_folder=folder)
else:
userfile = UserFile(store=self.store,
file=self.cleaned_data['file'],
creator=self.user)
userfile.save()
return userfile
Optional argument folder_id is always None, I don't know why. Anybody can help me?
Related
I'm having to do some validation across both a form and formset. The £££ amount in the form must equal the sum of the amounts in the formset.
After a lot of Googling I found a solution where I add a custom init to the baseformset as follows:
class BaseSplitPaymentLineItemFormSet(BaseFormSet):
def __init__(self, cr=None, *args, **kwargs):
self._cr = cr
super().__init__(*args, **kwargs)
def clean(self):
if any(self.errors):
return
sum_dr = 0
for form in self.forms:
sum_dr += form.cleaned_data.get('dr')
if sum_dr != float(self._cr):
raise forms.ValidationError('The amount entered needs to equal the sum of the split payments.')
I then pass the amount value from the form when the formset is instantiated, so that the value can be used in the formset validation:
lineitem_formset = LineItemFormSet(form.data['amount'], request.POST)
This worked great for the create_new view which uses formset_factory(). This morning I wrote the update view using inline_formsetfactory(), but I now get an error:
__init__() got an unexpected keyword argument 'instance'
I only have a basic understanding of how the custom init works, so I can't find a solution to this error.
Forms.py:
class SplitPaymentForm(forms.Form):
date = forms.DateField(widget=DateTypeInput())
account = GroupedModelChoiceField(queryset=Ledger.objects.filter(coa_sub_group__type='a').order_by('coa_sub_group__name','name'), choices_groupby = 'coa_sub_group')
store = forms.CharField(required=True)
amount = forms.DecimalField(decimal_places=2)
class SplitPaymentLineItemForm(ModelForm):
ledger = GroupedModelChoiceField(queryset=Ledger.objects.all().order_by('coa_sub_group__name', 'name'), choices_groupby = 'coa_sub_group', empty_label="Ledger", required=True)
project = forms.ModelChoiceField(queryset=Project.objects.filter(status=0), empty_label="Project", required=False)
class Meta:
model = LineItem
fields = ['description','project', 'ledger','dr',]
# This init disallows empty formsets
def __init__(self, *arg, **kwarg):
super(SplitPaymentLineItemForm, self).__init__(*arg, **kwarg)
self.empty_permitted = False
class BaseSplitPaymentLineItemFormSet(BaseFormSet):
def __init__(self, cr=None, *args, **kwargs):
self._cr = cr
super().__init__(*args, **kwargs)
def clean(self):
if any(self.errors):
return
sum_dr = 0
for form in self.forms:
sum_dr += form.cleaned_data.get('dr')
if sum_dr != float(self._cr):
raise forms.ValidationError('The amount entered needs to equal the sum of the split payments.')
Views.py:
def split_payments_new(request):
LineItemFormSet = formset_factory(SplitPaymentLineItemForm, formset=BaseSplitPaymentLineItemFormSet, extra=2)
if request.method == 'POST':
form = SplitPaymentForm(request.POST)
lineitem_formset = LineItemFormSet(form.data['amount'], request.POST)
if form.is_valid() and lineitem_formset.is_valid():
q0 = JournalEntry(user=request.user, date=form.cleaned_data['date'], type="SP",)
q1 = LineItem(journal_entry=q0, description=form.cleaned_data['store'], ledger=form.cleaned_data['account'], cr=form.cleaned_data['amount'])
q0.save()
q1.save()
for lineitem in lineitem_formset:
q2 = LineItem(journal_entry=q0,description=lineitem.cleaned_data.get('description'),ledger=lineitem.cleaned_data.get('ledger'),project=lineitem.cleaned_data.get('project'),dr=lineitem.cleaned_data.get('dr'))
q2.save()
messages.success(request, "Split payment successfully created.")
return HttpResponseRedirect(reverse('journal:split_payments_show_detail', kwargs={'pk': q0.id}) )
else:
form = SplitPaymentForm(initial = {'date': datetime.date.today().strftime('%Y-%m-%d')})
lineitem_formset = LineItemFormSet()
return render(request, 'journal/split_payments_new.html', {'form': form, 'formset': lineitem_formset})
def split_payments_update(request, pk):
journal_entry = get_object_or_404(JournalEntry, pk=pk, type="SP")
lineitem = LineItem.objects.get(journal_entry=journal_entry.id, dr__isnull=True)
initial = {
'date': journal_entry.date.strftime('%Y-%m-%d'),
'account': lineitem.ledger,
'store': lineitem.description,
'amount': lineitem.cr,
}
form = SplitPaymentForm(initial=initial)
LineItemFormSet = inlineformset_factory(JournalEntry, LineItem, form=SplitPaymentLineItemForm, formset=BaseSplitPaymentLineItemFormSet, extra=0)
lineitem_formset = LineItemFormSet(instance=journal_entry)
if request.method == 'POST':
lineitem_formset = LineItemFormSet(form.data['amount'], request.POST, instance=journal_entry)
form = SplitPaymentForm(request.POST)
if lineitem_formset.is_valid() and form.is_valid():
lineitem_formset.save()
journal_entry.date = form.cleaned_data['date']
lineitem.ledger = form.cleaned_data['account']
lineitem.description = form.cleaned_data['store']
lineitem.cr = form.cleaned_data['amount']
journal_entry.save()
lineitem.save()
messages.success(request, "Split payment successfully updated.")
return HttpResponseRedirect(reverse('journal:split_payments_show_detail', kwargs={'pk': journal_entry.id}) )
return render(request, 'journal/split_payments_update.html',{'form': form, 'formset': lineitem_formset, 'journal_entry': journal_entry})
Solved. Just had to use BaseInlineFormSet.
When I choose two images in my template, the save method always save the last image selected but I don't understand what it is happens.
this is my view:
class imgcreate(CreateView):
model = Archivos
template_name = 'img.html'
form_class = imgForm
success_url = reverse_lazy('BackEnd:unidades')
def post(self, request, *args, **kwargs):
form_class = self.get_form_class()
form = self.get_form(form_class)
files = request.FILES.getlist('imagen')
if form.is_valid():
a = 0
for imagen in files:
a = a+1
img = form.save(commit=False)
img.id_unidad = 1
img.tipo_archivo = 1
img.nombre_archivo ='hhh'+ str(a)
img.save()
print(a);
return self.form_valid(form)
else:
return self.form_invalid(form)
print always returns the name of the image with 2 that mean only the last image is saved
This works for me:
if request.method=="POST":
form = PlanfileForm(request.POST, request.FILES)
if form.is_valid():
files = request.FILES.getlist('large_img')
for a_file in files:
instance = Planfile(
plan_id = 1, #the foreign key
large_img=a_file
)
instance.save()
return HttpResponse("success!")
else:
...
I'm unable to figure out how to only call a queryset of items that belong to a specific User in the django forms.
dropoffs/models.py
class DropoffItem(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True)
dropoff = models.ForeignKey('Dropoff', null=True, blank=True)
product = models.ForeignKey(Product)
location = models.CharField(max_length=120, choices=LOCATION_CHOICES, default="Customer")
def __str__(self):
return str('%s' + " " + "(" + '%s' + ")") %(self.product.title, self.product.sku)
def sku(self):
return self.product.sku
def title(self):
return self.product.title
def dropoff_id(self):
return str(self.dropoff.id)
forms.py
class AddPickupItemForm(forms.ModelForm):
dropoffitem = forms.ModelChoiceField(queryset=DropoffItem.objects.none())
class Meta:
model = PickupItem
# fields = ["product", "quantity"]
fields = ['dropoffitem']
def __init__(self, user, *args, **kwargs):
# self.request = kwargs.pop("request")
the_user = kwargs.pop('user', None)
super(AddPickupItemForm, self).__init__(*args, **kwargs)
if the_user is not None:
self.fields["dropoffitem"].queryset = DropoffItem.objects.filter(user=the_user)
views.py
def add_item_to_pickup_order(request):
request.session.set_expiry(120000)
try:
user = request.user
the_id = request.session['pickup_id']
pickup = Pickup.objects.get(id=the_id)
except:
user = request.user
new_pickup_order = Pickup(user=user)
new_pickup_order.save()
request.session['pickup_id'] = new_pickup_order.id
the_id = new_pickup_order.id
pickup = Pickup.objects.get(id=the_id)
try:
dropoffitem = DropoffItem.objects.filter(user=user)
except DropoffItem.DoesNotExist:
pass
except:
pass
form = AddPickupItemForm(request.POST, user=request.user)
if request.method == "POST":
dropoffitem_id = int(request.POST['dropoffitem'])
pickup_item = PickupItem.objects.create(pickup=pickup, dropoffitem_id=dropoffitem_id)
pickup_item.save()
return HttpResponseRedirect('%s'%(reverse('add_item_to_pickup_order')))
context = {
"pickup": pickup,
"form": form,
}
return render(request, 'pickups/create_pickup_order.html', context)
With the modifications to init, I'm getting a TypeError of: init() got multiple values for keyword argument 'user'.
Could that be because of how I'm requesting a 'session'?
class AddPickupItemForm(ModelForm):
def __init__(self,*args,**kwargs)
the_user = kwargs.pop('user',None)
super(AddPickupItemForm, self).__init__(*args,**kwargs)
if the_user is not None:
self.fields['dropoffitem'].queryset = DropOffItem.objects.filter(user=the_user)
In other words, pass your user to the form when instantiating, if you need to.
I'm trying to make a form that can be used to make a new instance of "LearningObjects" as well as edit existing instances. It seems to work fine except that when I'm editing an existing instance I lose the filefield. Since it is a required field it asks me to upload a new file and obviously I don't always want to do that.
Form.py
class LearningObjectuploadform(forms.ModelForm, edit):
level = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple,queryset=None,required=False)
agebracket =forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple,queryset=None,required=False)
pathway = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple,queryset=None,required=False)
class Meta:
model = LearningObject
fields =['title','archivefile','description','tags','pathway','level','subject','agebracket']
def __init__(self, *args, **kwargs):
super(LearningObjectuploadform, self).__init__(*args, **kwargs)
self.fields['level'].queryset = AssoeLevel.objects.all()
self.fields['pathway'].queryset = AssoePathway.objects.all()
self.fields['agebracket'].queryset = AgeBracket.objects.all()
View.py
def createLearningobject(request,learningobject_pk=False):
if request.method == 'GET':
if learningobject_pk:
print learningobject_pk
instance = LearningObject.objects.get( pk=learningobject_pk)
print instance
form = LearningObjectuploadform(request.POST or None, request.FILES or None, instance=instance)
else:
form = LearningObjectuploadform()
else:
form = LearningObjectuploadform(request.POST, request.FILES)
if form.is_valid():
learningobject = request.FILES['archivefile']
title = form.cleaned_data['title']
description = form.cleaned_data['description']
tags = form.cleaned_data['tags']
levels = form.cleaned_data['level']
pathways = form.cleaned_data['pathway']
agebrackets = form.cleaned_data['agebracket']
post = LearningObject.objects.create(archivefile=learningobject,title=title, description=description)
for tag in tags:
post.tags.add(tag)
for level in levels:
post.level.add(level.pk)
for pathway in pathways:
post.pathway.add(pathway.pk)
for agebracket in agebrackets:
post.agebracket.add(agebracket.pk)
post.save()
return HttpResponseRedirect(reverse('index', ))
else:
print "form not valid"
return render(request, 'mediamanager/edit_learningobject.html', {'form': form,})
Models.py
class DefaultResource(models.Model):
#
# This class is the parent class for all resources in the media manager
#
title = models.CharField(max_length=100)
created_date = models.DateTimeField(auto_now_add=True, auto_now=False)
edited_date = models.DateTimeField(auto_now_add=False,auto_now=True)
level = models.ManyToManyField(AssoeLevel)
agebracket= models.ManyToManyField(AgeBracket)
pathway= models.ManyToManyField(AssoePathway)
tags = TaggableManager()
slug = models.SlugField(max_length=100,editable=False,blank=True)
updownvotes = RatingField(can_change_vote=True)
views = models.DecimalField(max_digits=20,decimal_places=2,default=0,blank=True)
score = models.DecimalField(max_digits=20,decimal_places=4,default=0,blank=True)
icon = models.CharField(max_length=254,editable=False,blank=True)
subject = models.ManyToManyField(AssoeSubjects)
#def return_tags(self):
# taglist = self.tags.names()
# return taglist
def calculate_score(self):
score = float(self.updownvotes.likes) - float(self.updownvotes.dislikes)
score = score + (float(self.views)**(float(1)/float(2)))
self.score = score
rounded_score = int(round(self.score))
if rounded_score < -1:
return -1
else:
return rounded_score
def __unicode__ (self):
return self.title
def save(self, *args, **kwargs):
self.calculate_score()
if not self.id:
self.slug = slugify(self.title)
super(DefaultResource, self).save(*args, **kwargs)
class LearningObject(DefaultResource):
archivefile = models.FileField(upload_to='static/learningobject/archivefiles/%Y/%m/%d')
indexpath = models.CharField(max_length=254,editable=False,blank=True)
description = models.TextField(blank=True)
def unpackarchive(self):
archive = self.archivefile
filename = os.path.basename(str(archive))
folder = str(filename).split(".")[0]
print folder
index_found = "False"
with zipfile.ZipFile(archive,"r") as z:
for each in z.namelist():
if each == "index.html" or each == "index.htm":
index_found = "True"
else:
pass
if not index_found:
print "zip file does not contain a valid index.html file"
else:
path = os.path.join("static","learningobject","unpackedarchives",folder)
z.extractall(path)
self.findindex(path)
def findindex(self,path):
print path
for root, dirnames, filenames in os.walk(path):
for filename in fnmatch.filter(filenames, 'index.ht*'):
print filename
self.indexpath = os.path.join(root, filename)
print self.indexpath
def save(self, *args, **kwargs):
self.icon = "/static/images/icons/box.png"
self.unpackarchive()
super(LearningObject, self).save(*args, **kwargs)
I have faced similar problems with file uploads in django forms. This is what I hope should help you out(provided you are willing to alter the required attribute of the archivefile field.)
if request.method == 'GET':
if learningobject_pk:
print learningobject_pk
instance = LearningObject.objects.get( pk=learningobject_pk)
print instance
form = LearningObjectuploadform(request.POST or None, request.FILES or None, instance=instance)
form.base_fields['archivefile'].required = False
else:
form = LearningObjectuploadform()
I was trying to dynamically generate fields as shown in http://jacobian.org/writing/dynamic-form-generation/. My case slightly differs in that I am looking to use multiplechoicefield that is dynamically created. This is what I came up with...
views.py
def browseget(request):
success = False
if request.method == 'POST':
list_form = ListForm(request.POST)
if list_form.is_valid():
success = True
path = list_form.cleaned_data['path']
minimum_size = list_form.cleaned_data['minimum_size']
follow_link = list_form.cleaned_data['follow_link']
checkboxes = list_form.cleaned_data['checkboxes']
....do something
else:
list_form = ListForm(name_list)
ctx = {'success': success, 'list_form': list_form, 'path': path, 'minimum_size': minimum_size}
return render_to_response('photoget/browseget.html', ctx, context_instance=RequestContext(request))
forms.py
class ListForm(forms.Form):
path = forms.CharField(required=False)
minimum_size = forms.ChoiceField(choices=size_choices)
follow_link = forms.BooleanField(required=False, initial=True)
def __init__(self, *args, **kwargs):
name_list = kwargs.pop('name_list', None)
super(ListForm, self).__init__(*args, **kwargs)
print 'Received data:', self.data
if name_list:
name_choices = [(u, u) for u in name_list]
self.fields['checkboxes'] = forms.MultipleChoiceField(required=False, label='Select Name(s):', widget=forms.CheckboxSelectMultiple(), choices=name_choices)
def clean_path(self):
cd = self.cleaned_data
path = cd.get('path')
if path == '': path = None
return path
def clean_minimum_size(self):
cd = self.cleaned_data
minimum_size = cd.get('minimum_size')
if minimum_size is None: minimum_size = 0
return int(minimum_size)
The form generates and displays perfectly... until I post some data. The 'checkboxes' field doesn't show up in list_form.cleaned_data.items() while it shows in self.data. As it is the form breaks with a KeyError exception. So Im asking, how do i access the checkboxes data?
You're not passing in the name_list parameter when you re-instantiate the form on POST, so the field is not created because if name_list is False.