Django: strange IntegrityError upon saving a ModelFormset form - python

I am trying to save a couple ModelFormset forms, but am running into an IntegrityError. Here is the code:
billing_formset = BillingFormSet(request.POST,prefix='billing')
cc_formset = CCFormSet(request.POST,prefix='cc')
if billing_formset.is_valid() and cc_formset.is_valid():
bp = UserBillingProfile()
cc = UserCreditCard()
for form in billing_formset.forms:
billing_profile = form.save(commit=False)
billing_profile.user = request.user
bp = billing_profile.save()
for form in cc_formset.forms:
cc = form.save(commit=False)
cc.billing_profile = bp
cc = form.save()
This code caused the following code:
IntegrityError at [url removed]
(1048, "Column 'user_billing_profile_id' cannot be null")
EDIT: Here is some iterative code that also fixes my typo. I'm running into basically the same problem.
billing_profile_form = billing_formset.forms[0]
cc_form = cc_formset.forms[0]
unsaved_billing_profile = billing_profile_form.save(commit=False)
user_billing_profile = unsaved_billing_profile.save()
unsaved_cc = cc_form.save(commit=False)
unsaved_cc.user_billing_profile = user_billing_profile
cc = unsaved_cc.save()
Problem line gives: "Cannot assign None: "UserCreditCard.user_billing_profile" does not allow null values." It seems unsaved_billing_profile.save() is returning null? Why?
This is kind of crazy; everything seems to be right. I don't get any errors when saving the billing profile. Any ideas on what I should check? Things seem to be going wrong in the second loop, where bp apparently has a value of None.
Thanks in advance.

This means you are trying to save a model instance with user_billing_profile set to None, looks like you are calling "billing_profile" instead of "user_billing_profile".
The "save" method returns None every time commit=False isn't specified. you should instead call something like this:
billing_profile.save()
bp = billing_profile.instance

Related

local variable 'product' referenced before assignment ? in Django

I am facing the issue I can't find the solution yet. It's working so far. but now showing an error. don't know how to fix this. please need help.
views.py
def add_product(request):
product_form = ProductForm()
product_variant_images_form = ProductVariantsImagesForm()
if request.method == 'POST':
product_form = ProductForm(request.POST)
product_variant_images_form = ProductVariantsImagesForm(request.POST,request.FILES)
if product_form.is_valid():
print(request.POST)
product = product_form.save(commit=False)
vendor = CustomUser.objects.filter(id=request.user.id)
product.vendoruser = vendor[0]
product.save()
vendor = CustomUser.objects.get(id=request.user.id)
product_variant = ProductVariants()
product_variant.product_id = product ###ERROR SHOWING IN THIS LINE
product_variant.vendoruser = vendor
product_variant.price = request.POST.get('price')
product_variant.initial_stock = request.POST.get('initial_stock')
product_variant.weight_of_product = request.POST.get('weight_of_product')
product_variant.save()
return redirect('vendor:inventory_display')
else:
productform = ProductForm()
productvariantsform = ProductVariantsForm()
product_variant_images_form = ProductVariantsImagesForm()
return render(request, 'vendor/add_product.html',
{'productform': productform,'product_variant_images_form':product_variant_images_form,
'productvariantsform': productvariantsform})
It's working fine.After product added multiple time the error occurred. how can I get rid of this error.please some help much appreciated.
Its because your product variable isn't set if you don't go inside if product_form.is_valid():,
you could just set a default value before this if statement in order to fix your error.
I hope this helped.
The product variable is only defined if the form is valid. Either you can set a default value for product outside of the if statement or you could move all of the code involving data from the form inside of the if statement.

Django check if post value exists in db

I'm trying to submit two forms with one submit button. First I want to check if form 1 already exists in the db, if id does then just post the second form using the "ticker" from first form as Foreginkey. But seem to get an error:
'UserTickerForm' object has no attribute 'get'
My code:
if request.method == 'POST':
request_form_user_ticker = UserTickerForm(request.POST)
request_form_trade = TradesForm(request.POST)
if request_form_user_ticker.is_valid() and request_form_trade.is_valid():
if not User_Ticker.objects.filter(portfolio=select_portfolio, ticker=request_form_user_ticker.get('ticker')).exists():
user_ticker_instace = request_form_user_ticker.save(commit=False)
user_ticker_instace.portfolio = select_portfolio
user_ticker_instace.save()
trade_instance = request_form_trade.save(commit=False)
trade_instance.ticker = request_form_user_ticker.get('ticker')
trade_instance.save()
else:
trade_instance = request_form_trade.save(commit=False)
trade_instance.ticker = request_form_user_ticker.get('ticker')
trade_instance.save()
Does anyone know who this is happening and what I can do to fix this?
instead of request_form_user_ticker.get('ticker') you should call .get('ticker') on cleaned data so request_form_user_ticker.cleaned_data.get('ticker')

Validation Error in Python Django

I have HTML form with one optional field like this
<input type="number" name="total_amount" id="total_amount" class="completedtype" onchange="add()"/>
When I input some number in the field then I the whole form data gets saved in to the database. But when there is no data then I get Validation Error
ValidationError at /oms_data/ [u"'' value must be a decimal number."]
I have tried to resolve this issue for more than half a day but nothing helped me. I have tried the following to resolve this error.
I have used something like this which was suggested in some SO answer:
total_amount = request.POST.get("total_amount",0) ## get total_amount or take default value 0
That didn't work so I used the famous try: except: as shown below:
try:
total_amount = request.POST["total_amount"]
except: ## whatever the exception and not just Validation Error
total_amount = 0
I don't know why none of this worked.The error occurs when trying to save the form.
save_Order_Selling_Pricing = models.Order_Selling_Pricing(order_id=order_id,vendor_name = vendor_name,total_amount =total_amount,
vendor_discount_percent=vendor_discount_percent,dg_percent = dg_percent,
vendor_discount_amount=vendor_discount_amount,vendor_percent = vendor_percent,
dg_discount_percent = dg_discount_percent,dg_discount_amount=dg_discount_amount,
final_selling_price = final_selling_price,order_selling_pricing_id=order_selling_pricing_id,
order_payment_mode = order_payment_mode,present_datetime=present_datetime)
save_Order_Selling_Pricing.save()
Any help in this regard would be great!
Thanks in advance! I'm using Django 1.8 python 2.7 if this helps.
UPDATE 1:
I have my models defined as shown below:
total_amount = models.DecimalField(max_digits=10,decimal_places=2,blank = True,null = True,default = Decimal('0.00'))

iterate over django form results (not in a template)

I am trying to iterate over form results and I can't help but think that I am re-inventing the wheel here.
filterlist = []
if request.POST:
form = FilterForm(request.POST)
if form.is_valid():
for key, value in form.cleaned_data.iteritems():
filterlist.append(key)
filterlist.append(value)
This works, but seems very awkward and creates lots of other problems. For example the values come back with u' so I have to use value.encode("utf8") but then if a value is None it throws in error. So now I have to check if it is None, if not then encode. There has to be a better way.
EDIT: What I am trying to do.
I am trying to filter what is shown on a page. The problem I am running into is that if a value is empty (the user don't fill the box because they only want to filter against one object) then I get no results. For example a user wants to search for all books by the author name "Smith" but doesn't want to search against a genre.
results = Books.objects.filter(author=author, genre=genre)
The user would get no results because this is an AND search. But, if a user put in "Smith" for the author and "mystery" for the genre then it works exactly like I want it to, only giving results where both are true.
So, I am trying to eliminate the empty stuff by iterating over the form results. Like I said I am probably re-inventing the wheel here.
In Python 3 use:
for key, value in form.cleaned_data.items():
If the field names are the same in the model and the form, try this:
filter = {}
if request.method == 'POST':
form = FilterForm(request.POST)
if form.is_valid():
for key, value in form.cleaned_data.iteritems():
if value:
filter[key] = value
results = Books.objects.filter(**filter)
Python is one of the few languages having named parameters. You can assemble a dict with the non-empty form fields and pass it to the filter method using the kwargs unpacking operator **.
For example:
kwargs = {"author": "Freud"}
results = Books.objects.filter(**kwargs)
Is the same as:
results = Books.objects.filter(author="Freud")
I think the problem is that by default the Model form is not valid if a form field does not have a value entered by the user, if you don`t require the field every time from the user you need to set the required field to false in the ModelForm class in forms.py as shown in the code below. Remember that the field is set false only in the model form not in the model itself
class myForm(forms.ModelForm):
myfield_id = forms.CharField(required=False)
myfield_foo = forms.CharField(required=False)
myfield_bar = forms.CharField(required=False)
myfield_name = forms.CharField(required=False)
class Meta:
model = myModel
exclude = ('myfield_ex','myfield_file')
fields = ['myfield_id','myfield_foo','myfield_bar','myfield_name',]
After you have the form entered by the user what you need is use the Q object which can be used to create complex queries as described in the manula page here
https://docs.djangoproject.com/en/1.7/topics/db/queries/#complex-lookups-with-q
A simple example code would look like
if form.is_valid():
qgroup = []
for key,value in form.cleaned_data.iteritems():
if value:
q_name = Q(**{"%s"%format(filterKey[key]) : value})
qgroup.append(q_name)
q = None
# can use the reduce as shown here qgroup = reduce(operator.or_, (Q(**{"{0}".format(filterKey[key]): value}) for (key,value) in form.cleaned_data.iteritems()))
for key,value in form.cleaned_data.iteritems():
if value:
q_name = Q(**{"%s"%format(filterKey[key]) : value})
qgroup.append(q_name)
for x in qgroup:
q &= x ### Or use the OR operator or
if q:
resultL = myModel.objects.filter(q).select_related()
The filterKey can look something on the lines of
filterKey = {'myfield_id' : "myfield_id",
'myfield_foo' : "myfield_foo__icontains",
'myfield_bar' : "myfield_bar__relative_field__icontains",
}

change a form value before validation in Django form

I have a django form and on my view function I do this :
search_packages_form = SearchPackagesForm( data = request.POST )
I would like to overwrite a form field called price which is decleared as such :
price = forms.ChoiceField( choices = PRICE_CHOICES, required = False,widget = forms.RadioSelect )
I would like to overwrite the form field before calling search_packages_form.is_valid()
I thought of doing :
search_packages_form.data['price'] = NEW_PRICE
But it does not work. Any ideas ?
Probably not the Django way but based on https://stackoverflow.com/a/17304350/2730032 I'm guessing the easiest way to change your form value before validation is to do something like the following:
def search_packages_view(request):
if request.method == 'POST'
updated_request = request.POST.copy()
updated_request.update({'price': NEW_PRICE})
search_packages_form = SearchPackagesForm(updated_request)
if search_packages_form.is_valid():
# You're all good
This works but I'd be interested if anyone has another way that seems more in line with Django, or if there isn't: then an explanation about why.
one trick for what you want is to do it like this:
changed_data = dict(request.POST)
changed_data['price'] = NEW_PRICE
search_packages_form = SearchPackagesForm(data = changed_data)
My solution is build on an earlier proposal. It is a working solution, which can be used in several cases.
#Milad Khodabandehloo
had a tricky solution to solve the problem.
changed_data = dict(request.POST)
changed_data['price'] = NEW_PRICE
search_packages_form = SearchPackagesForm(data = changed_data)
as #The EasyLearn Academy commented: it does not allow you to access actual data submitted in form.
This is because the request.POST is immutable.
But there is a solution to the problem - just have to be more tricky.
This solution is only good if a reference to the object is enough for the certain cause. It leaves the object itself the same.
# write object to variable (data)
data = request.POST
# set to mutable
data._mutable = True
# modify the values in data
data[modified_field] = new_value
# set mutable flag back (optional)
data._mutable = False
Hope it's useful!
form.is_valid() runs through your form's (and model's in case of a ModelForm) clean method's, returning True or False
If you plan on changing form data you can do it within the general clean method or at field level, e.g.
class YourForm(DerivingClass):
# regular stuff
def clean_<ATTR>(self):
# here
return self.cleaned_data
def clean(self):
# or here
return super(YourForm, self).clean()

Categories

Resources