Django form with filefield loses the file when editing an instance - django

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

Related

signals post_save called twice after updating data in class base view django

So i've been stack on this problem that everytime I update my stock in orders it called twice for updating I use the class base view built in Django but in models I have a post signal which it removing the stock of the product. I already use the dispatch_uid but it's not working or any solution that I found on internet not working on my problem.
here is my class base view for updating:
class ItemQtyUpdateClassBaseView(UpdateView):
template_name = 'components/update/item.html'
form_class = ItemForm
def get_context_data(self, **kwargs):
kwargs['context_title'] = 'Update Order Qty'
return super(ItemQtyUpdateClassBaseView, self).get_context_data(**kwargs)
def form_valid(self, form):
try:
order_item = OrderModel.objects.get(pk = self.kwargs[self.pk_url_kwarg])
fetch_product = ProductsModel.objects.get(product_name = order_item.product_name)
print(fetch_product.qty)
if fetch_product.dough != None:
if int(fetch_product.dough.qty) <= 0:
messages.error(self.request, 'Not enough qty to order.')
return self.form_invalid(form)
if int(fetch_product.qty) <= 0:
messages.error(self.request, 'Not enough qty to order.')
return self.form_invalid(form)
else:
self.object = form.save()
messages.success(self.request, 'Successfully update qty.')
except Exception as e:
messages.error(self.request, e)
return self.form_invalid(form)
return super(ItemQtyUpdateClassBaseView, self).form_valid(form)
def form_invalid(self, form):
return super().form_invalid(form)
def get_queryset(self):
return OrderModel.objects.filter(pk = self.kwargs[self.pk_url_kwarg])
def get_success_url(self):
return reverse_lazy('core:createorder', kwargs = {
'typeoforder': self.kwargs['typeoforder']
})
and here is my model with signal post_save:
class OrderModel(models.Model):
date = models.DateField(auto_now = True)
invoice_no = models.ForeignKey(InvoiceModel, on_delete = models.CASCADE)
product_name = models.CharField(max_length = 150, blank = False, null = True)
price = models.DecimalField(max_digits = 10, decimal_places = 2)
qty = models.FloatField(default = 1)
class Meta:
db_table = 'orders'
ordering = ['-pk']
#receiver(post_save, sender = OrderModel, dispatch_uid='signals.ordermodel_removeqty')
def removeQty(sender, instance = None, created = False, **kwargs):
product = ProductsModel.objects.get(product_name = instance.product_name)
if product.dough != None:
dough = DoughModel.objects.get(pk = product.dough.pk)
dough.qty = abs(dough.qty - (product.qty * instance.qty))
dough.save()
else:
product.qty = abs(product.qty - instance.qty)
product.save()
You are calling save() method two times in form_valid() method :
self.object = form.save()
super(ItemQtyUpdateClassBaseView, self).form_valid(form)
You have to remove the below line from form_valid() method:
self.object = form.save()
See what form_valid(form)(Django Docs) method do:
Saves the form instance, sets the current object for the view, and
redirects to get_success_url().

Matching query doesn't exist?

I am making a retweet function and it works quite smooth but I am not able to retweet my own tweets , I am able to retweet other users tweets but not mine
. It shows that matching query doesn't exist.
Here is the tweets models
class TweetManager(models.Manager):
def retweet(self,user,parent_obj):
if parent_obj.parent:
obj_parent = parent_obj.parent
else:
obj_parent = parent_obj
qs = self.get_queryset().filter(user = user, parent = obj_parent)
if qs.exists():
return None
obj = self.model(
user = user,
parent = obj_parent,
content = parent_obj.content
)
obj.save()
return obj
class Tweet(models.Model):
parent = models.ForeignKey("self",blank = True,null = True)
user = models.ForeignKey(settings.AUTH_USER_MODEL)
content = models.CharField(max_length = 130)
time = models.DateTimeField(auto_now_add = True)
objects = TweetManager()
def __str__(self):
return self.content
class Meta:
ordering = ['content']
Here's the views.py
class Retweet(View):
def get(self, request, pk, *args, **kwargs):
tweet = get_object_or_404(Tweet, pk=pk)
if request.user.is_authenticated:
new_tweet = Tweet.objects.retweet(request.user, tweet)
return HttpResponseRedirect("/")
return HttpResponseRedirect(tweet.get_absolute_url())

Save file into folder

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?

Django queryset calling only objects belonging to User

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.

Access missing value in form.cleaned_data

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.