Comparing date field in a form with current date - django

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)

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

form for formset object has no attribute 'cleaned deta'

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)

IntegrityError with a foreignKey

i have these models, states and cities,
class State(models.Model):
name = models.CharField(max_length=255)
shortname = models.CharField(max_length=100)
def __unicode__(self):
return self.name
class City(models.Model):
name = models.CharField(max_length=255)
state = models.ForeignKey(State)
def __unicode__(self):
return self.name
and im getting a "IntegrityError (1048, "Column 'state_id' cannot be null")" when i save the form, the weird thing is that the state are created, this is what im doing
def form_valid(self, form):
city = form.cleaned_data['city_name']
state = form.cleaned_data['state_name']
m = State.objects.get_or_create(name=state)
state_id = m[0].id
City.objects.get_or_create(name=state, id=state_id)
form.save()
what can i do?
class StoreForm(ModelForm):
class Meta:
model = Store
fields = '__all__'
class StoreGoogleMapForm(StoreForm):
city_name = forms.CharField(
widget=forms.TextInput(
attrs={'readonly': 'readonly'}
)
)
state_name = forms.CharField(
widget=forms.TextInput(
attrs={'readonly': 'readonly'}
)
)
class Meta(StoreForm.Meta):
exclude = (
'state', 'city'
)
widgets = {
'retailer': forms.HiddenInput(),
'lon': forms.HiddenInput(),
'lat': forms.HiddenInput(),
}
def clean(self):
cleaned_data = super(StoreGoogleMapForm, self).clean()
city_name = cleaned_data.get("city_name")
state_name = cleaned_data.get("state_name")
return cleaned_data
class NewStore(LoginRequiredMixin, CreateView):
model = Store
template_name = "new_store.html"
form_class = StoreGoogleMapForm
def get_context_data(self, **kwargs):
ctx = super(NewStore, self).get_context_data(**kwargs)
ctx['cobrand'] = self.retailer
return ctx
def get(self, request, *args, **kwargs):
self.retailer = get_object_or_404(Cobrand, pk=kwargs['pk'])
self.object = Store(retailer=self.retailer)
form_class = self.get_form_class()
form = self.get_form(form_class)
return self.render_to_response(self.get_context_data(form=form))
def form_valid(self, form):
city = form.cleaned_data['city_name']
state = form.cleaned_data['state_name']
m = State.objects.get_or_create(name=state)
City.objects.get_or_create(name=city, state=m[0])
form.save()
messages.add_message(
self.request,
messages.SUCCESS,
'The store was successfuly created!',
extra_tags='success'
)
return HttpResponseRedirect(self.get_success_url())
def get_success_url(self):
return reverse_lazy('store_list', kwargs={'pk': self.kwargs['pk']})
def post(self, request, *args, **kwargs):
self.retailer = get_object_or_404(Cobrand, pk=kwargs['pk'])
self.object = Store(retailer=self.retailer)
form_class = self.get_form_class()
form = self.get_form(form_class)
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
fix the line as
City.objects.get_or_create(name=city, state=m[0])
you don't need form.save().
Anyway this code is a bit strange, what about your Form?
get_or_create returns two parameters https://docs.djangoproject.com/en/1.7/ref/models/querysets/#django.db.models.query.QuerySet.get_or_create and you can then pass the object straight into the next statement.
state, created = State.objects.get_or_create(name=state)
City.objects.get_or_create(name=state, state=state)
suspect you shouldn't be doing this in form_valid but without rest of your code, can't be sure.

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)