How to Append to Array Field in Python Django - python

I am making an E commerce site, I want to store Cart elements in an integer Array Field. I am using PostGreSql as my database.
I have created model for cart by extending Django User model. Here is my models
class UserCart(models.Model):
user=models.OneToOneField(User,on_delete=models.CASCADE)
user_product=models.IntegerField(blank=True, null=True)
cart_products = ArrayField(
models.IntegerField(blank=True),
default = list
)
User.profile = property(lambda u:UserCart.objects.get_or_create(user=u)[0])
Below is my Form.py. I have created only basic form
from django import forms
from .models import UserCart
from django.db import models
from django.contrib.postgres.fields import ArrayField
class UserCartForm (forms.ModelForm):
class Meta:
model= UserCart
fields = ('user_product',)
I have searched alot on internet but was unable to find the relevant answer.I want that whenever user clicks on Add to Cart button, that product_id gets stored in cart_products array.I read somewhere that ArrayFields behave as list in Django, so here is my views.py
#login_required
def user_cart(request):
if request.method=='POST':
form=UserCartForm(request.POST , instance=request.user.profile)
if form.is_valid():
post = form.save(commit=False)
post.cart_products.append(99)
post.save()
return HttpResponseRedirect('/user_login/loggedin')
else:
HttpResponse("Error")
else:
user=request.user
profile=user.profile
form= UserCartForm(instance=profile)
args={}
args.update(csrf(request))
args['form']=form
return render_to_response('cartapi.html' ,args)
Its giving me Error that
AttributeError at /cart/ac/
'NoneType' object has no attribute 'append'
Request Method: POST
Request URL: http://localhost:8000/cart/ac/
Django Version: 1.11.2
Exception Type: AttributeError
Exception Value:
'NoneType' object has no attribute 'append'
Exception Location: C:\Users\Muhammad
Jawad\AppData\Local\Programs\Python\Python36-32\mysite\cart\views.py in
user_cart, line 19
Python Executable: C:\Users\Muhammad
Jawad\AppData\Local\Programs\Python\Python36-32\python.exe
And if i save cart_products this way
post.cart_products=99
Then it throws this error
column "cart_products" is of type int4range but expression is of type integer
LINE 1: ...er_id" = 1, "user_cart" = 3000, "cart_products" = 99 WHERE "...
^
HINT: You will need to rewrite or cast the expression.
Request Method: POST
Request URL: http://localhost:8000/cart/ac/
Django Version: 1.11.2
Exception Type: ProgrammingError
Exception Value:
column "cart_products" is of type int4range but expression is of type integer
LINE 1: ...er_id" = 1, "user_cart" = 3000, "cart_products" = 99 WHERE "...
^
HINT: You will need to rewrite or cast the expression.
Kindly Help me in this matter.Summarizing my Question:
How can i get user_product as id and save it in cart_products

change yor views like this
views.py
#login_required
def user_cart(request):
if request.method=='POST':
form=UserCartForm(request.POST , instance=request.user.profile)
if form.is_valid():
post = form.save(commit=False)
if post.cart_products:
post.cart_products.append(99)
else:
post.cart_products = [99]
post.save()
return HttpResponseRedirect('/user_login/loggedin')
else:
HttpResponse("Error")
else:
user=request.user
profile=user.profile
form= UserCartForm(instance=profile)
args={}
args.update(csrf(request))
args['form']=form
return render_to_response('cartapi.html' ,args)

Your database is messed up. Drop it and remigrate (or craft a custom migration if you have data to preserve: basically, you just have to expand existing ranges into the full array).
See https://docs.djangoproject.com/en/2.1/_modules/django/contrib/postgres/fields/ranges/#IntegerRangeField
The int4range is the db type associated with the IntegerRangeField. This indicates either problem with your migrations (try running ./manage.py makemigrations) or that your database is out-of-sync with your DB (try running ./manage.py migrate).
It's hard to say what exactly the problem is without looking at your migrations and the current table definition in the database, but this should get you started.

keyword_from_user="My name is John Doe"
I have Django 3.1.7 and this method has worked for me.
models.py
class Keys(models.Model):
keys = ArrayField(models.CharField(max_length=50, blank=True),size=5,blank=True)
docfile = models.FileField(upload_to='documents/%Y/%m/%d', blank=True, null=True)
views.py create object
new_document_object = Keys.objects.create(keys= keyword_from_user.split(), docfile =file)
views.py create object
new_document_object = Keys.objects.create(keys= keyword_from_user.split(), docfile =file)
views.py update object
keys = Keys.objects.get(id=id_from_user)
keys.keys=user_data['keyword_update_list']
keys.save()

You can save your cart_products into a python list then modify that list using the append method. Thereafter, you can save the new value of the list into the ArrayField
#login_required
def user_cart(request):
if request.method=='POST':
form=UserCartForm(request.POST , instance=request.user.profile)
if form.is_valid():
post = form.save(commit=False)
# copy the existing cart_products to a temp variable
temp_cart = post.cart_products
# append your new product code to the temp_cart
temp_cart.append(99)
# save the new value of temp_cart to the cart_products field
post.cart_products = temp_cart
# save the post
post.save()
return HttpResponseRedirect('/user_login/loggedin')
else:
HttpResponse("Error")
else:
user=request.user
profile=user.profile
form= UserCartForm(instance=profile)
args={}
args.update(csrf(request))
args['form']=form
return render_to_response('cartapi.html' ,args)

Related

How can i fetch my data from database to django template?

Whenever I run this,
Exception Value:
name 'current_user' is not defined;
error is raised.
I am not getting where i am doing the mistake as I m new in django programming. Please help me fetch the data
# To add a new product in the database
def AddNewProduct(request):
if request.method == "POST":
current_user = request.user
product_title =request.POST['product_title']
uid = request.POST['uid']
specification =request.POST['specification']
sale_price = request.POST['sale_price']
discount = request.POST['discount']
img1 = request.FILES['img1']
img2 = request.FILES['img2']
promote_method = request.POST['promote_method']
terms_conditions = request.POST['terms_conditions']
newproduct = AffProduct(user_id=current_user.id, product_title=product_title, uid=uid, specification=specification, sale_price=sale_price,
discount=discount, img1=request.FILES.get('img1'), img2=request.FILES.get('img2'),
promote_method=promote_method, terms_conditions=terms_conditions)
newproduct.save()
# Status message
messages.success(request, 'Product added successfully')
return render(request, 'blink_network.html')
else:
return render(request, 'blink_network.html')
#Here i m trying to fetch my data.
def showproduct(request):
if request.user.is_authenticated:
result = AffProduct.objects.filter(user_id=current_user.id)
else:
result = AffProduct.objects.all()
return render(request, 'blink_viewproduct.html', {'result': result})
It looks like you will be getting that problem from showproduct(request) because you don't define current_user in that method before calling it.
to call this
result = AffProduct.objects.filter(user_id=current_user.id)
you need to define current_user = request.user beforehand
Could you share the relevant models.py file as well? You probably linked the user model with the ForeignKey with the Product model. If you did this, you need to give current_user, not current_user.id, django handles the matching itself.
Also, I guess you are using django form. If you are using it, I recommend you to use it because you can increase the readability of your code by writing less code.

Include the pk or models fields when creating the object in POST

I have my Order model which has a FK to Item model. I customized the Order create method to create the item which is passed in from the POST request. I want to customize it to allow the POST request to pass the Item pk instead of the name. so if the pk exists, I just use it and no need to create a new item.
However, when I look at the validated_data values in the create(), the id field doesn't exist.
class Item(models.Model):
name = models.CharField(max_length=255,blank=False)
class Order(models.Model):
user = models.OneToOneField(User,blank=True)
item = models.OneToOneField(Item,blank=True)
I want the POST body to be
{
"name":"iPhone"
}
or
{
"id":15
}
I tried to implement this kind of behavior myself, and didn't find a satisfying way in terms of quality. I think it's error prone to create a new object without having the user confirming it, because the user could type in "iphone" or "iPhon" instead of "iPhone" for example, and it could create a duplicate item for the iphone.
Instead, I recommend to have two form fields:
a select field for the item name,
a text input to create an item that's not in the list.
Then, it's easy to handle in the form class.
Or, with autocompletion:
user types in an Item name in an autocompletion field,
if it doesn't find anything, the autocomplete box proposes to create the "iPhon" Item,
then the user can realize they have a typo,
or click to create the "iPhone" item in which case it's easy to trigger an ajax request on a dedicated view which would respond with the new pk, to set in the form field
the form view can behave normally, no need to add confusing code.
This is how the example "creating choices on the fly" is demonstrated in django-autocomplete-light.
You may need to use Django Forms.
from django import forms
from django.contrib.auth.decorators import login_required
from django.core.exceptions import ValidationError
from .models import Order, Item
from django.shortcuts import render
class OrderForm(forms.Form):
item_name = forms.CharField(required=False)
item = forms.ModelChoiceField(queryset=Item.objects.none(), required=False)
def __init__(self, *args, **kwargs):
super(OrderForm, self).__init__(*args, **kwargs)
self.fields['item'].queryset = Item.objects.all()
def clean_item(self):
item_name = self.cleaned_data['item_name']
item = self.cleaned_data['item']
if item:
return item
if not item_name:
raise ValidationError('New item name or existing one is required.')
return Item.objects.create(name=item_name)
#login_required
def save(request):
if request.method == 'GET':
return render(request, 'template.html', {'form': OrderForm()})
user = request.user
form = OrderForm(request.POST)
if form.is_valid():
order = Order.objects.create(user=user, item=form.cleaned_data['item'])
return render(request, 'template.html', {'form': OrderForm(), 'order': order, 'success': True})
else:
return render(request, 'template.html', {'form': OrderForm(), 'error': True})

Django Integrity Error Handling

I have created a website for user registration with first name, last name, phone no and so on.
I have successfully established a connection to MySQL database. I want help regarding IntegrityError handling in django,since I'm a newbie.
When 2 users input same phone number, django takes me to its debug page with whole lots of information. Instead I want to notify the user then and there that another user with same phone number already exists. Please provide any pointers on this.
Following is my views.py file in which I process the form:
from django.shortcuts import render
from formProcessing.forms import UserForm
def form(request):
#This is using regular Django forms
#print request.POST
#form = EmailForm(request.POST or None)
#This is using model forms
form = UserForm(request.POST or None)
if form.is_valid():
new_instance = form.save(commit=True)
new_instance.save()
context = {"form": form }
template = "form.html"
return render(request,template,context)
In your UserForm you can overwrite clean method of your number attribute, lets say that your attribute is called 'number'
class UserForm(ModelForm):
#your user form attributes and stuff
def clean_number(self, value):
user_number = value
number_occurrences = User.objects.filter(number=user_number).count()
if number_occurrences > 0:
raise forms.ValidationError("You number is already taken by other user")
return self.cleaned_data
Check django docs about form validation
If you dont wan't to overwrite clean method and do it whitin your view. you can. (Is not elegant)
def form(request):
#This is using regular Django forms
#print request.POST
#form = EmailForm(request.POST or None)
#This is using model forms
number = request.POST.get('telephone')
number_occurrences = User.objects.filter(number=user_number).count()
if number_occurrences > 0:
context = {'error':'Number already exist'}
return render(request,template,context)
form = UserForm(request.POST or None)
if form.is_valid():
new_instance = form.save(commit=True)
new_instance.save()
context = {"form": form }
template = "form.html"
return render(request,template,context)
Before you create an object, query the db for the existence of that phone number.
if form.is_valid():
ph_number = #"Phone number from form"
if User.objects.filter(phone_number = ph_number).first():
return HttpResponse("The number already exists.")
new_instance = form.save(commit=True)
new_instance.save()
The first() method returns the index 0 of the queryset. So, if there is element 0 in the queryset, the error message will be displayed to the user.
you can probably do something with field validation, although I donĀ“t know exactly what your error is, or how the model is designed.
Anyway, you could try to look up whether the value is unique (i.e., look if another record exists with the same number), before trying to save it; this might be the cleanest.
https://docs.djangoproject.com/en/1.7/ref/forms/validation/#cleaning-a-specific-field-attribute
so something like:
def clean_telephone(self):
n = User.objects.filter(telephone=self.cleaned_data['telephone']).count()
if n > 0:
raise forms.ValidationError("telephone number is already in database")
return data
Or you could try to save it and catch the unique error with a try/except clause. This uses less databases access attempts.

MutipleCheckBox saving to Database with Django

I'm trying to find some kind of canonical reference for this problem where I use the follow type model:
class MyPreferencesForm(forms.Form):
MyGenderPref = forms.MultipleChoiceField(choices=GENDER_CHOICES, widget=forms.CheckboxSelectMultiple())
and the view
def GoPreferences(request):
if request.method == "POST":
f = MyPreferencesForm(request.POST)
if f.is_valid():
model_instance = f.save(commit=False)
model_instance.save()
f.save_m2m()
return redirect('/')
else:
f = MyPreferencesForm()
return render(request, "mypreferences.html", {'form': f})
However I tried to follow what I thought was sensible and include the many to many. But I still cannot make this work. My error is the following:
Exception Type: AttributeError
Exception Value:
'MyPreferencesForm' object has no attribute 'save'
The error emanates from line containing model_instance = f.save(commit=False)
save is available only for forms inherited from ModelForm objects. Here, you are inheriting form forms.Form Hence the error.
Either inherit the form from forms.ModelForm and specify a Meta attribute
class MyPreferencesForm(forms.ModelForm):
MyGenderPref = forms.MultipleChoiceField(choices=GENDER_CHOICES, widget=forms.CheckboxSelectMultiple())
class Meta:
model = MyModel
You can read more on ModelForms here - You might have to modify your form slightly based on your specific requirements.
OR
model_instance = MyModel.objects.create(**form.cleaned_data) #manage manually
If your m2m tables in your models.py uses through then you'll need to manage the saving manually using object.create and you can't use save_m2m() or save()

Django Error: 'function' object has no attribute 'save'

Can someone please tell me what i am doing wrong?
Model.py
class Cattest(models.Model):
category = models.ForeignKey(Category)
info = models.CharField(max_length=35, blank=True)
form.py
class CattestForm(forms.Form):
autocomplete = forms.CharField(
label='Type the name of a category (AutoCompleteWidget)',
widget=selectable.AutoCompleteWidget(CategoryLookup),
required=False,
)
info = forms.CharField(max_length=35, label="Information")
view.py
def cattest(request):
if request.method == 'POST':
form = CattestForm(request.POST)
if form.is_valid():
cattest.save()
else:
if request.GET:
form = CattestForm(initial=request.GET)
else:
form = CattestForm()
return render_to_response('bsmain/form.html', {'form': form}, context_instance=RequestContext(request))
Traceback:
AttributeError at /bsmain/cattest/
'function' object has no attribute 'save'
Request Method: POST
Request URL: http://127.0.0.1:8000/bsmain/cattest/
Django Version: 1.3.1
Exception Type: AttributeError
Exception Value:
'function' object has no attribute 'save'
Exception Location: /home/bill/workspace/boatsite/../boatsite/bsmain/views.py in cattest, line 50
Python Executable: /usr/bin/python
Python Version: 2.6.5
You have a type-o in your view.
you are calling save() on the function you are in cattest.save()
I think this should be on the form?? You might want to look at ModelForm it provides a form that maps directly to your model, which it looks like you are doing.
https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#django.forms.ModelForm
The form you are using is just a normal form and doesn't have a save method. After subclassing ModelForm you can then call save on a form instance.
if your_form.is_valid():
your_form.save()
You are calling save method on function itself. That is the reason behind the error. if you are looking for form to save then:
if form.is_valid():
form.save()
class CattestForm(forms.Form): should be class CattestForm(forms.ModelForm):

Categories