form for formset object has no attribute 'cleaned deta' - django

I have genericview which handle 3 difference form(2 formsets), when i try check cleaned_data, i have error, but when i try make the same by debugger i didn't see anything problem, who may know why i can't make it?
My View :
class CompanyCreateView(LoginRequiredMixin, CreateView):
model = Company
template_name = 'main/company/create_page.html'
form_class = CompanyCreateForm
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['page'] = Page.objects.active().filter(slug='add_company').first()
if self.request.POST:
context['images'] = ImageGalleryFormSet(self.request.POST, self.request.FILES)
context['company_locations'] = CompanyLocationFormset(self.request.POST)
else:
context['images'] = ImageGalleryFormSet(self.request.GET or None)
context['company_locations'] = CompanyLocationFormset(self.request.GET or None)
return context
#transaction.atomic
def form_valid(self, form):
context = self.get_context_data()
images = context['images']
company_locations = context['company_locations']
self.object = form.save()
self.object.active = False
self.object.status = CompanyConstants.CompanyStatus.NEW
self.object.owner = self.request.user
self.object.save()
for image in range(len(images)):
key_image = 'gallery_items-' + str(image) + '-image'
form_image = self.request.FILES.get(key_image)
if form_image:
ImageGallery(image=form_image, company_id=int(self.object.id)).save()
print(company_locations.forms[0].get_cleaned_data)
for location in range(len(company_locations)):
key_locations = 'form-' + str(location) + '-location'
key_address = 'form-' + str(location) + '-address'
if self.request.POST.get(key_locations):
location = self.request.POST.get(key_locations)
address = self.request.POST.get(key_address)
company = self.object
CompanyLocation.objects.create(location=clean_location(location), address=address, company=company)
return super().form_valid(form)
def get_success_url(self):
return reverse('main:profile', args=[self.request.user.username])
When i try print this i have error, this code that i have works correct but, he is bad.
MY FORM :
class CompanyLocationForm(forms.ModelForm):
location = geo_forms.PointField(widget=GooglePointFieldWidget)
class Meta:
model = CompanyLocation
fields = ('location', 'address')
CompanyLocationFormset = formset_factory(CompanyLocationForm, max_num=10)

you need to clean your data to check the problem
#transaction.atomic
def form_valid(self, form):
def clean(self):
all_clean_data = super().clean()
all_clean_data[['page'] = Page.objects.active().filter(slug='add_company').first()
...
So i see a lot off data Just test
def Test(request):
if request.method == "POST":
form =CompanyLocationForm(data=request.POST)
if form.is_valid():
print(company_locations.forms[0].get_cleaned_data)

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

prepoluate a generec createview

i want that a form is prepoluate with data
my model:
TYPE = (("S",'Swing'),
("R","Rapide"))
class valuation(models.Model):
stock = models.ForeignKey("stock",on_delete=models.CASCADE,related_name='valuation',)
date = models.DateField(auto_created=True)
val_type = models.CharField(choices=TYPE, max_length=1,default='R')
user = models.ForeignKey("users.User", on_delete=models.CASCADE)
def __str__(self):
return f"{self.stock} - {self.date} - {self.val_type}"
my view:
class valuationCreateviewSwing(CreateView):
template_name = "evaluation/evaluation_create.html"
form_class = valuationModeform
def get_form_kwargs(self): # prepopulate form
kwargs = super(valuationCreateviewSwing, self).get_form_kwargs()
stck = get_object_or_404(stock, pk=self.kwargs['pk'])
kwargs['user'] = self.request.user
kwargs['val_type'] = "S"
kwargs['stock'] = stck
return kwargs
def get_context_data(self, **kwargs):
# we need to overwrite get_context_data
# to make sure that our formset is rendered
data = super().get_context_data(**kwargs)
if self.request.POST:
data["val_detail"] = ChildFormset1(self.request.POST)
else:
data["val_detail"] = ChildFormset1()
data.update({
"typeVal": "Swing",})
return data
def form_valid(self, form):
context = self.get_context_data()
val_detail_Swing = context["val_detail_Swing"]
self.object = form.save(commit=False)
# add data info neede about valuation model
self.object = form.save()
if val_detail_Swing.is_valid():
val_detail_Swing.instance = self.object
val_detail_Swing.save()
return super().form_valid(form)
def get_success_url(self):
return reverse("stock:stock-list")
I've a child form in my view (this part works ok):
ChildFormset1 = inlineformset_factory(
valuation, val_detail_Swing, form=valuationSwingModelform, can_delete=False)
I tried to use ge_for_kwargs but it seems not working as I've an error message :
init() got an unexpected keyword argument 'user'
You can use get_initial() method:
class valuationCreateviewSwing(CreateView):
template_name = "evaluation/evaluation_create.html"
form_class = valuationModeform
def get_initial(self):
query = self.request.GET
return {
'user': self.request.user.pk
'val_type': "S",
'stock': self.kwargs.get('pk')
}
...
Or you should override __init__() method and stay to use get_form_kwargs()
class valuationModeform(ModelForm):
class Meta:
model = Valuation
fields = '__all__'
def __init__(self, *args, **kwargs):
user = kwargs.pop('user', None)
val_type = kwargs('val_type', None)
stock = kwargs.pop('stock', None)
super().__init__(*args, **kwargs)
# assign initial values
self.fields['user'].initial = user
self.fields['val_type'].initial = val_type
self.fields['stock'].initial = stock

How to save many-to-many data using form.instance?

I am writing an application on Django.
How can I save data (provider.category) from form using form.instance.
models
class RequestProvider(models.Model):
category = models.ManyToManyField(Category, related_name="provider_request")
forms
class ProviderForm(forms.ModelForm):
class Meta:
model = RequestProvider
fields = ('category',)
widgets = {
'category': forms.SelectMultiple(
attrs={
'class': 'select2',
'style': 'width: 246px;'
}
),
}
views
#method_decorator(currency_account_dec, name='dispatch')
class ProviderCreateView(CreateView):
form_class = ProviderForm
template_name = 'provider_create.html'
def form_valid(self, form):
provider_id = self.kwargs.get('provider_id',None)
session_user = self.request.user
if provider_id:
form.instance.provider = Provider.objects.get(pk=provider_id)
form.instance.user = self.request.user
#form.instance.category = form.cleaned_data.get('category')
return super(ProviderCreateView,self).form_valid(form)
def get_context_data(self, **kwargs):
provider_id = self.kwargs.get('provider_id',None)
ss = RequestProvider.objects.filter(user=self.request.user)
for s in ss:
print(s.category)
ctx = super(ProviderCreateView, self).get_context_data(**kwargs)
ctx['organizations'] = Organization.objects.filter(user=self.request.user)
ctx['payments'] = Payment.objects.all()
if provider_id:
this_provider = Provider.objects.get(pk=provider_id)
ctx['this_provider'] = this_provider
ctx['categories'] = Category.objects.all()
ctx['roles'] = this_provider.role.all()
ctx['payments'] = Payment.objects.all()
ctx['deliveries'] = Delivery.objects.all()
return ctx
I believe you can do form.save()
No need to rewrite the form_valid.
#method_decorator(currency_account_dec, name='dispatch')
class ProviderCreateView(CreateView):
form_class = ProviderForm
template_name = 'provider_create.html'
def post(self, request):
provider_id = self.kwargs.get('provider_id',None)
session_user = request.user
form = ProviderForm(request.POST)
if form.is_valid():
rq = form.save(commit=False)
if provider_id:
rq.provider = Provider.objects.get(pk=provider_id)
rq.user = self.request.user
rq.save()
rq.category = form.cleaned_data.get('category')
return HttpResponseRedirect('/providers/')
else:
return HttpResponseRedirect('/providers/create/')

Comparing date field in a form with current date

I am trying to check with an if statement if the date entered in a form is before the current date. If so write to an object in the model. I am also not sure if there are a better way of doing this.
I get this error
'<' not supported between instances of 'DateField' and 'datetime.date'
My view:
class ActionCreateView(LoginRequiredMixin, generic.CreateView):
login_url = '/scrty/login/'
template_name = "nodiso/actioncreate.html"
form_class = forms.LeadActionCreateForm
# success_url = reverse_lazy('nodisoapp:leaddetail', kwargs['pk'] )
def get_success_url(self, **kwargs):
return reverse("nodisoapp:leaddetail", kwargs={'pk':
self.kwargs['pk']})
def form_valid(self, form):
if form.fields['Duedate'] < datetime.date.today():
self.object.overdue = 1
else:
pass
self.object = form.save(commit=False)
self.object.lead_id = self.kwargs['pk']
self.object.creator = self.request.user.firstname
self.object.save()
return super(ActionCreateView, self).form_valid(form)
The Model:
class LeadActions(models.Model):
lead = models.ForeignKey(Leads)
name = models.CharField(max_length=265)
crdate = models.DateField(auto_now_add=True)
Duedate = models.DateField()
creator = models.CharField(max_length=265)
overdue = models.IntegerField(null=True,blank=True)
def __str__(self):
return self.name
The form:
class LeadActionCreateForm(forms.ModelForm):
class Meta:
model = models.LeadActions
fields = ['name','Duedate']
Since you already pull out the unsaved model from the form here:
self.object = form.save(commit=False)
Why not read the Duedate directly from the model instance, and set the overdue flag accordingly ?
is_overdue = self.object.Duedate > datetime.date.today()
self.object.overdue = 1 if is_overdue else None
Complete code:
class ActionCreateView(LoginRequiredMixin, generic.CreateView):
login_url = '/scrty/login/'
template_name = "nodiso/actioncreate.html"
form_class = forms.LeadActionCreateForm
# success_url = reverse_lazy('nodisoapp:leaddetail', kwargs['pk'] )
def get_success_url(self, **kwargs):
return reverse("nodisoapp:leaddetail", kwargs={'pk': self.kwargs['pk']})
def form_valid(self, form):
self.object = form.save(commit=False)
is_overdue = self.object.Duedate > datetime.date.today()
self.object.overdue = 1 if is_overdue else None
self.object.lead_id = self.kwargs['pk']
self.object.creator = self.request.user.firstname
self.object.save()
return super(ActionCreateView, self).form_valid(form)

Class Based Generic UpdateView inline

I have the following models
class Cv(models.Model):
name = models.CharField(_('name'), max_length=250)
objective = models.CharField(_('objective'), max_length=250)
slug = models.SlugField(editable=False)
class Position(models.Model):
cv = models.ForeignKey(Cv, verbose_name=_('cv'))
start = models.DateField(_('start'))
end = models.DateField(_('end'))
name = models.CharField(_('name'), max_length=250)
currently_employed = models.BooleanField(_('currently employed'))
sector = models.IntegerField(_('sector'), choices=SECTOR_CHOICES)
duties = models.TextField(_('duties'))
and the following forms:
class CvForm(ModelForm):
class Meta:
model = Cv
class PositionForm(ModelForm):
class Meta:
model = Position
widgets = {
'start': DateInput(attrs={'class':'datepicker'}),
'end': DateInput(attrs={'class':'datepicker'}),
}
PositionFormSet = inlineformset_factory(Cv, Position, form=PositionForm, extra=1)
I have created the following Generic CreateView which works great:
class CreateCvView(CreateView):
model = Cv
form_class = CvForm
template_name = 'recruitment/cv/cv_detail.html'
def get_success_url(self):
self.success_url = '/'
return self.success_url
def get_context_data(self, **kwargs):
context = super(CreateCvView, self).get_context_data(**kwargs)
if self.request.POST:
context['position_form'] = PositionFormSet(self.request.POST)
else:
context['position_form'] = PositionFormSet(instance=self.object)
return context
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.slug = slugify(self.request.user)
context = self.get_context_data()
position_form = context['position_form']
if position_form.is_valid():
self.object = form.save()
position_form.instance = self.object
position_form.save()
return HttpResponseRedirect(self.get_success_url())
else:
return self.render_to_response(self.get_context_data(form=form))
What I want to do is an UpdateView and so I copied the createview and passed it the slug as follows:
class EditCvView(UpdateView):
model = Cv
form_class = CvForm
template_name = 'recruitment/cv/cv_detail.html'
def get_success_url(self):
self.success_url = '/'
return self.success_url
def get_context_data(self, **kwargs):
context = super(EditCvView, self).get_context_data(**kwargs)
if self.request.POST:
context['position_form'] = PositionFormSet(self.request.POST)
else:
context['position_form'] = PositionFormSet(instance=self.object)
return context
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.slug = slugify(self.request.user)
context = self.get_context_data()
position_form = context['position_form']
if position_form.is_valid():
self.object = form.save()
position_form.instance = self.object
position_form.save()
return HttpResponseRedirect(self.get_success_url())
else:
return self.render_to_response(self.get_context_data(form=form))
It loads fine but when I post the form I get a 'list index out of range' error on PositionFormSet(self.request.POST) in get_context_data. Has anyone else had this problem?
in EditCvView:
context['position_form'] = PositionFormSet(self.request.POST, instance=self.object)