django Grabing form input and edit an instance - django

i'm trying to make a simple inventory app but i'm have trouble with restock logic for instance if i have a new stock bought with diffrent price than the first one i want just get the average price on the whole stock in shell works fine but when i go to my form i always get the form input instead of the desired value, after some investigation i found out that i'm grabbing the instance data using request.POST.get and even before the save quantity = item.quantity!! my question now is how can i grab my input and the instance separately
##models
class Supply(models.Model):
name = models.CharField(max_length=100, unique=True)
quantity = models.PositiveIntegerField()
price = models.DecimalField(max_digits=11, decimal_places=2)
created = models.DateField(auto_now_add=True)
last_modefied = models.DateField(auto_now=True)
def __str__(self):
return self.name
##form
class SupplyForm(forms.ModelForm):
class Meta:
model = Supply
fields = ["name", "quantity", "price"]
#view
def add_supply(request):
form = SupplyForm()
if request.POST:
# getting form input data
name = request.POST.get("name")
quantity = request.POST.get("quantity")
price = request.POST.get("price")
# getting Supply instance
item = Supply.objects.get(name=name)
# instantiating the form
form = SupplyForm(request.POST, instance=item)
if form.is_valid:
# Logic
old_supply = item.quantity * item.price
new_supply = int(quantity) * int(price)
new_quantity = item.quantity + int(quantity)
item.price = (old_supply + new_supply) / new_quantity
item.quantity = new_quantity
form.save()
return redirect("project_list")
return render(request, "restock.html", {"form": form})

found this answer to who ever might need it :
1st remove modelform and make a form.Forms with 2 new fields something like that
#forms
class RestockForm(forms.Form):
name = forms.CharField(max_length="30")
quantity = forms.IntegerField(min_value=0)
price = forms.DecimalField(max_digits=11, decimal_places=2)
new_quantity = forms.IntegerField(min_value=0)
new_price = forms.DecimalField(max_digits=11, decimal_places=2)
#views
def add_supply(request, pk):
#getting the object
item = get_object_or_404(Supply, pk=pk)
# instantiating the form on using initial since its not a model form
form = RestockForm(initial={"name": item.name, "quantity": item.quantity, "price": item.price})
if request.POST:
# getting form extra input data
quantity = request.POST.get("new_quantity")
price = request.POST.get("new_price")
form = RestockForm(request.POST,)
if form.is_valid():
old_supply = item.quantity * item.price
new_supply = int(quantity) * int(price)
_quantity = item.quantity + int(quantity)
item.price = (old_supply + new_supply) / _quantity
item.quantity = _quantity
# important need to save the object
item.save()
return redirect("project_list")
return render(request, "restock.html", {"form": form})
#urls
path('restock/<int:pk>', stock_views.add_supply, name="restock"),

Related

''QuerySet' object has no attribute 'enter_the_destination_account_number'

Can anyone tell me what's wrong with my code? I am trying to use filter but its showing ''QuerySet' object has no attribute 'enter_the_destination_account_number'. I tried get() but it shows,
get() returned more than one MoneyTransfer -- it returned 14!.
here's some snap of code. Thanks in advance
models.py
class Status (models.Model):
user_name = models.CharField(max_length=150, default=None)
account_number = models.IntegerField()
balance = models.IntegerField()
phone_number= models.CharField(max_length=20, default=0)
class MoneyTransfer(models.Model):
enter_your_user_name = models.CharField(max_length = 150, default = None)
enter_the_destination_account_number = models.IntegerField()
enter_the_destination_phone_number=models.CharField(max_length=20, default=None)
enter_the_amount_to_be_transferred_in_INR = models.IntegerField()
views.py
def TransferMoney(request):
if request.method == "POST":
form = forms.MoneyTransferForm(request.POST)
if form.is_valid():
form.save()
curr_user = models.MoneyTransfer.objects.filter(enter_your_user_name=request.user)
dest_user_acc_num = curr_user.enter_the_destination_account_number #dest_phone number add korte hobe
dest_phone_num= curr_user.enter_the_destination_phone_number
temp = curr_user # NOTE: Delete this instance once money transfer is done
dest_user = models.Status.objects.get(account_number=dest_user_acc_num) # FIELD 1
dest_phn= models.Status.objects.get(phone_number= dest_phone_num)
transfer_amount = curr_user.enter_the_amount_to_be_transferred_in_INR # FIELD 2
curr_user = models.Status.objects.get(user_name=request.user) # FIELD 3
# Now transfer the money!
curr_user.balance = curr_user.balance - transfer_amount
#dest_phn.balance = dest_phn.balance + transfer_amount
dest_user.balance = dest_user.balance + transfer_amount
# Save the changes before redirecting
curr_user.save()
dest_user.save()
temp.delete() # NOTE: Now deleting the instance for future money transactions
return redirect(index)
else:
form = forms.MoneyTransferForm()
return render(request, "epayapp/Transfer_money.html", {"form": form})
The issue is that filter returns a queryset, not an object.
So you cannot access the fields directly from the queryset, what you can do is grab the first element from the queryset and perform the operations you want.
Like this: curr_user = models.MoneyTransfer.objects.filter(enter_your_user_name=request.user).first()
So it'll look like this:
def TransferMoney(request):
if request.method == "POST":
form = forms.MoneyTransferForm(request.POST)
if form.is_valid():
form.save()
# Grab the first object from the queryset
curr_user = models.MoneyTransfer.objects.filter(enter_your_user_name=request.user).first()
dest_user_acc_num = curr_user.enter_the_destination_account_number #dest_phone number add korte hobe
dest_phone_num= curr_user.enter_the_destination_phone_number
temp = curr_user # NOTE: Delete this instance once money transfer is done
dest_user = models.Status.objects.get(account_number=dest_user_acc_num) # FIELD 1
dest_phn= models.Status.objects.get(phone_number= dest_phone_num)
transfer_amount = curr_user.enter_the_amount_to_be_transferred_in_INR # FIELD 2
curr_user = models.Status.objects.get(user_name=request.user) # FIELD 3
# Now transfer the money!
curr_user.balance = curr_user.balance - transfer_amount
#dest_phn.balance = dest_phn.balance + transfer_amount
dest_user.balance = dest_user.balance + transfer_amount
# Save the changes before redirecting
curr_user.save()
dest_user.save()
temp.delete() # NOTE: Now deleting the instance for future money transactions
return redirect(index)
else:
form = forms.MoneyTransferForm()
return render(request, "epayapp/Transfer_money.html", {"form": form})
the filter method on objects does not returned an object as you think. it will return a Queryset object
You have to loop into the results of filter or take an item with first() function for example
def TransferMoney(request):
if request.method == "POST":
form = forms.MoneyTransferForm(request.POST)
if form.is_valid():
form.save()
queryset = models.MoneyTransfer.objects.filter(enter_your_user_name=request.user)
curr_user = queryset.first()
dest_user_acc_num = curr_user.enter_the_destination_account_number #dest_phone number add korte hobe
dest_phone_num= curr_user.enter_the_destination_phone_number
temp = curr_user # NOTE: Delete this instance once money transfer is done
dest_user = models.Status.objects.get(account_number=dest_user_acc_num) # FIELD 1
dest_phn= models.Status.objects.get(phone_number= dest_phone_num)
transfer_amount = curr_user.enter_the_amount_to_be_transferred_in_INR # FIELD 2
curr_user = models.Status.objects.get(user_name=request.user) # FIELD 3
# Now transfer the money!
curr_user.balance = curr_user.balance - transfer_amount
#dest_phn.balance = dest_phn.balance + transfer_amount
dest_user.balance = dest_user.balance + transfer_amount
# Save the changes before redirecting
curr_user.save()
dest_user.save()
temp.delete() # NOTE: Now deleting the instance for future money transactions
return redirect(index)
else:
form = forms.MoneyTransferForm()
return render(request, "epayapp/Transfer_money.html", {"form": form})
get function have to returned only one element or it will raises a exception...
Maybe set account_number and user_name unique in your fields definition for rpeventing this cases

Django: While loop doesn't work correctly

i'm buildint a warehouse management application, i have a product model and an placement for each product, every placement has a volume, once i put a product in a placement, the volume of this placement must be reduced. The problem is when the app finds a placement for the product, the placement volume stay the same
models.py
class Emplacement(models.Model):
address = models.CharField(max_length=25, blank=True)
volume = models.DecimalField(max_digits=10, decimal_places=2, null=True)
class Product(models.Model):
name = models.CharField(max_length=100)
quantity = models.PositiveIntegerField()
is_disponible = models.BooleanField(default=False)
volume = models.DecimalField(max_digits=20, decimal_places=2, null=True)
emplacement = models.ForeignKey(Emplacement, on_delete=models.CASCADE, null=True)
views.py
def product_detail(request, pk):
product = get_object_or_404(Product, id=pk)
if request.method == 'POST':
form = ValidateProductForm(request.POST, instance=product)
if form.is_valid():
product = form.save(commit=False)
product.volume = form.cleaned_data['longueur'] * form.cleaned_data['largeur'] * form.cleaned_data['hauteur']
product.is_disponible = True
all_emplacements = Emplacement.objects.all()
i=1
while i <= product.quantity:
for emplacement in all_emplacements:
if product.volume < emplacement.volume:
product.emplacement = emplacement
emplacement.volume -= product.volume
i+=1
product.save()
return redirect('print-barcode', product.id)
else:
form = ValidateProductForm(instance=product)
context = {
'product': product,
'form': form,
}
return render(request, 'dashboard/product_detail.html', context)
You're not saving the emplacement object.
Try this:
if request.method == 'POST':
form = ValidateProductForm(request.POST, instance=product)
if form.is_valid():
product = form.save(commit=False)
product.volume = form.cleaned_data['longueur'] * form.cleaned_data['largeur'] * form.cleaned_data['hauteur']
product.is_disponible = True
all_emplacements = Emplacement.objects.all()
i=1
while i <= product.quantity:
for emplacement in all_emplacements:
if product.volume < emplacement.volume:
product.emplacement = emplacement
emplacement.volume -= product.volume
emplacement.save()
i+=1
product.save()
return redirect('print-barcode', product.id)
else:
form = ValidateProductForm(instance=product)
Edit
Your Product model indicates that each Product has only ONE Emplacement, since that's where the ForeignKey is. But, a single Emplacement, can have MANY Product objects. ForeignKey is a ManyToOne relationship. When iterating through ALL Emplacements, you are using the SAME Product, and that's why they are all getting the same number in your admin. I'm guessing, but perhaps what you're after is to find the SINGLE appropriate Emplacement model that the specific Product object has, nad then update just that one. In other words, NO iterating at all.
if request.method == 'POST':
form = ValidateProductForm(request.POST, instance=product)
if form.is_valid():
product = form.save(commit=False)
product.volume = form.cleaned_data['longueur'] * form.cleaned_data['largeur'] * form.cleaned_data['hauteur']
product.is_disponible = True
# Here are my proposed changes:
product.save() # Update the product
emplacement = product.emplacement # Get the correct Emplacement
emplacement.volume -= product.volume # Adjust the volume
emplacement.save() # Save the emplacement
return redirect('print-barcode', product.id)
else:
form = ValidateProductForm(instance=product)

Django how to iterate a form and save multiple objects?

I have a modelform (model: Student) with a TextField where the user enters several names at once. My intention is for my view to parse this text input (getting a first name, last name, and then coming up with a nickname) and loop through the lines, saving a new student each time through the loop. However, only the last time through the loop is a student saved.
In the past I have solved this problem by using a custom save method in my model but I wanted to try doing it all in the view. I saw some posts in stackoverflow such as this one where it seemed that others were able to iterate through a loop and save objects.
models.py
class Student(models.Model):
classroom = models.ForeignKey(Classroom, on_delete=models.CASCADE)
student_first = models.CharField(default='John', max_length=30)
student_last = models.CharField(default='Smith', max_length=30)
nickname = models.CharField(default='JohnS', max_length=31)
attend = models.BooleanField(default=True)
do_not_pick = models.BooleanField(default=False)
multistudentinput = models.TextField(blank=True, default='')
def __str__(self):
return self.nickname
forms.py
class MultiStudentForm(ModelForm):
class Meta:
model = Student
fields = ('multistudentinput',)
views.py
def addmultistudent(request, classroom_id):
classblock = Classroom.objects.get(id=classroom_id)
if request.method == 'POST':
form = MultiStudentForm(request.POST)
if form.is_valid():
student = form.save(commit=False)
# save the classroom that the student belongs to
student.classroom = classblock
student_list = []
student_list = student.multistudentinput.split('\n')
for line in student_list:
line = line.strip('\r')
all_names = line.split()
num_names = len(all_names)
if num_names == 2:
last = all_names[1]
student.student_last = last
else:
last = ' '
student.student_last = ''
student.nickname = all_names[0] + last[:1]
student.student_first = all_names[0]
print(student)
student.save()
form = MultiStudentForm(None)
context = {'form': form}
return render(request, "gradebook/addmultistudent.html", context)
else:
context = {'form': form}
return render(request, "gradebook/addmultistudent.html", context)
else:
form = MultiStudentForm(None)
context = {'form': form}
return render(request, "gradebook/addmultistudent.html", context)

Django changing models field into views

I everyone, I have a problem with a django's view. My goal is to change the 'execute' field into 'True' if newOrder is buy and there is some other sell order with a inferior price. And reverse for sell newOrders. I want to change the 'execute' field for the newOrder and also for the other order (in pairs). That's my code:
views.py
def order(request):
form = OrderForm()
if request.method == 'POST':
form = OrderForm(request.POST)
if form.is_valid():
new_order = form.save()
if new_order.buy is True:
sellOrder = Order.objects.filter(sell=True, execute=False,
price__lte=new_order.price).first().update(execute=True)
new_order.execute = True
sellOrder.save()
else:
buyOrder = Order.objects.filter(buy=True,
execute=False,price__gte=new_order.price).first().update(execute=True)
new_order.execute = True
buyOrder.save()
new_order.profile = request.user
new_order.save()
return redirect('home')
else:
form = OrderForm()
contex = {'form': form}
return render(request, 'app/new_order.html', contex)
models.py
class Profile(models.Model):
_id = ObjectIdField()
user = models.ForeignKey(User, on_delete=models.CASCADE)
wallet = models.FloatField()
class Order(models.Model):
_id = ObjectIdField()
profile = models.ForeignKey(User, on_delete=models.CASCADE)
datetime = models.DateTimeField(auto_now_add=True)
buy = models.BooleanField(blank=True)
sell = models.BooleanField(blank=True)
price = models.FloatField()
quantity = models.FloatField()
execute = models.BooleanField(blank=True)
But something goes wrong. This is the error:
AttributeError at /new_order/
'NoneType' object has no attribute 'update'
sellOrder returns a count of updated rows, not the object updated
sellOrder = Order.objects.filter(sell=True, execute=False,
price__lte=new_order.price).first().update(execute=True)
instead try
sellOrder = Order.objects.filter(sell=True, execute=False,
price__lte=new_order.price).first()
new_order.execute = True
sellOrder.execute = True
sellOrder.save()

Editing a topic and its sub entries at the same time

I want to edit an entry and it's child at the same time.
So I have a Price model which has Entry (another model) as it's foreign key.
class Price(models.Model):
price = models.ForeignKey(Entry, on_delete = models.CASCADE)
ptext = models.FloatField(blank = True, null = True)
date_added = models.DateTimeField(auto_now_add = True)
class Meta:
verbose_name_plural = 'prices'
def __str__(self):
return self.ptext[:50] + "..." `
How would I pull the price from the entry model?
I can only modify data inside the entry model, but not the price model. The instance part is giving a problem in particular. I don't know what to put for the PriceForm instance.
def edit_entry(request, entry_id):
entry = Entry.objects.get(id = entry_id)
price = entry.price_set.get.all()
topic = entry.topic
check_topic_owner(topic.owner, request.user)
if request.method != 'POST':
form = EntryForm(instance = entry)
form2 = PriceForm(instance = price)
else:
form = EntryForm(instance=entry, data = request.POST)
form2 = PriceForm(instance=price, data = request.POST)
if form.is_valid() and form2.is_valid():
form.save()
form2.save()
return HttpResponseRedirect(reverse('learning_logs:topics'))
context = {'entry': entry, 'topic': topic, 'form': form, 'form2':form2}
return render(request, 'learning_logs/edit_entry.html', context)
To get all the price objects from the entry object, you should use
price = entry.price_set.all()
instead of
price = entry.price_set.get.all()