Im fairly new to Django. Im using Django 2.
My model:
# Create your models here.
class Trade(models.Model):
quantity = models.IntegerField()
open_price = models.FloatField()
commision = models.FloatField()
exchange_rate_usdsek = models.FloatField()
stock = models.ForeignKey(Stock, on_delete=models.CASCADE)
user = models.ForeignKey(User, related_name='trades', on_delete=models.PROTECT)
open_date = models.DateTimeField(auto_now_add=True, null=True)
def get_absolute_url(self):
return reverse('trade:detail',kwargs={'pk': self.pk})
def __str__(self):
return self.stock.name
My view
class IndexView(generic.ListView):
template_name = 'trade/index.html'
context_object_name = 'all_trades'
#
def get_queryset(self):
return Trade.objects.all()
#return Order.objects.all().prefetch_related('items')
def get_context_data(self, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
return context
index.html
<h3>All stocks</h3>
<table class="table">
<thead>
<tr>
<th>Stock</th>
<th>Amount</th>
<th>Open Price</th>
<th>Commision</th>
<th>USD/SEK</th>
<th>Total sek</th>
</tr>
</thead>
{% for trade in all_trades %}
<tr>
<td>{{trade.stock.name}}</td>
<td>{{trade.quantity}}</td>
<td>{{trade.open_price}} USD</td>
<td>{{trade.commision}} SEK</td>
<td>{{trade.exchange_rate_usdsek}}</td>
<td>{{open_price * quantity * exchange_rate_usdsek}}</td>
</tr>
{% endfor %}
</table>
Now on my index.html I want to calculate and display a value.
I make a calculation like this:
total_sek = open_price * quantity * exchange_rate_usdsek
Do I have to calculate this in the views.py or in the index.html?
Also how would I do this? I searched around and found something about filters but im not sure if that is the right way to do it
The easiest way is to just define this calculation as a property on the model:
class Trade(models.Model):
# ...
#property
def total_sek(self):
return self.open_price * self.quantity * self.exchange_rate_usdsek
at which point you can simply
<td>{{ trade.total_sek }}</td>
in the template,
and trade.total_sek in Python code as required too.
Related
I'm new in Python and hope that someone can help me. I realise that this is probably not a unique question, but please be sympathetic.
I'm working on web-application (it's a bookstore). I make a cart and the proccess of forming an order. Now I'm trying to make a usr profile but unfortunately, I don't know how to display all user orders and make it possible to cahnge orders (change quantity of books for exmpl.) and how to make changable user profile information.
I realised the following logic:
User creates the cart and then create the order. After order creation cart also is in database.
To summarise the above, main questions are:
How to add all information from user cart (that was formed into the order) to user's profile?
How to make user's data and order's/cart's data possible to change in the user's profile?
How to display several user's orders in separate rows in HTML table (cause in my template all orders are in one row)?
Cart models:
User = get_user_model()
class Cart(models.Model):
customer = models.ForeignKey(
User, null=True, blank=True,
related_name="Customer",
verbose_name="Customer",
on_delete=models.PROTECT
)
#property
def total_price_cart(self):
goods = self.goods.all()
total_price_cart = 0
for good in goods:
total_price_cart += good.total_price
return total_price_cart
def __str__(self):
return str(self.pk)
class BooksInCart(models.Model):
cart = models.ForeignKey(
Cart,
related_name="goods",
on_delete=models.CASCADE,
verbose_name="Cart"
)
book = models.ForeignKey(
Book,
on_delete=models.PROTECT,
verbose_name='Book',
)
quantity = models.IntegerField(
verbose_name="Quantity",
default=1
)
price = models.DecimalField(
verbose_name='Price',
max_digits=5,
decimal_places=2,
)
#property
def total_price(self):
return self.price * self.quantity
Cart views:
class CartUpdate(View):
def post(self, request):
action = request.POST.get('submit')
if action == "save_cart":
cart_id = self.request.session.get('cart_id')
cart, created = models.Cart.objects.get_or_create(
pk=cart_id,
defaults={},
)
if created:
self.request.session['cart_id'] = cart.pk
goods = cart.goods.all()
if goods:
for key, value in request.POST.items():
if "quantityforgood_" in key:
pk = int(key.split('_')[1])
good = goods.get(pk=pk)
good.quantity = int(value)
good.save()
return HttpResponseRedirect(reverse_lazy("carts:cart_edit"))
elif action == "create_order":
return HttpResponseRedirect(reverse_lazy('order:create_order'))
else:
return HttpResponseRedirect(reverse_lazy("carts:cart_edit"))
class CartView(generic.DetailView):
template_name = 'carts/cart_edit.html'
model = models.Cart
def get_object(self, queryset=None):
cart_id = self.request.session.get('cart_id')
cart, created = models.Cart.objects.get_or_create(
pk=cart_id,
defaults={},
)
if created:
self.request.session['cart_id'] = cart.pk
book_id = self.request.GET.get('book_pk')
if book_id:
book = Book.objects.get(pk=int(book_id))
book_in_cart, flat_created = models.BooksInCart.objects.update_or_create(
cart=cart,
book=book,
defaults={
'price': book.price
}
)
if not flat_created:
q = book_in_cart.quantity + 1
book_in_cart.quantity = q
book_in_cart.price = book_in_cart.book.price * q
else:
book_in_cart.price = book.price
book_in_cart.save()
return cart
class DeleteGoodInCartView(generic.DeleteView):
model = models.BooksInCart
template_name = 'carts/delete_book_in_cart.html'
success_url = reverse_lazy("carts:cart_edit")
Order models:
User = get_user_model()
class CustomSession(Session):
cart = models.ForeignKey(
Cart,
on_delete=models.CASCADE
)
class Meta:
app_label = 'cart_id'
class Status(models.Model):
name = models.CharField(max_length=30)
def __str__(self):
return self.name
class Meta:
verbose_name = "Status"
verbose_name_plural = "Statuses"
class Order(models.Model):
user = models.ForeignKey(
User,
on_delete=models.PROTECT,
related_name='orders'
)
cart = models.OneToOneField(
Cart,
on_delete=models.PROTECT,
verbose_name="Cart"
)
status = models.ForeignKey(
Status,
on_delete=models.PROTECT
)
contact_info = models.TextField(
verbose_name="Contact info",
)
created = models.DateTimeField(
verbose_name="Created",
auto_now=False,
auto_now_add=True
)
updated = models.DateTimeField(
verbose_name="Updated",
auto_now=True,
auto_now_add=False
)
def __str__(self):
return self.contact_info
class Meta:
verbose_name = "Order"
verbose_name_plural = "Orders"
Cart views:
class CreateOrderView(generic.FormView):
form_class = forms.OrderCreateForm
template_name = 'order/create_order.html'
success_url = reverse_lazy("order:success")
def form_valid(self, form):
cart_id = self.request.session.get('cart_id')
cart, created = carts_models.Cart.objects.get_or_create(
pk=cart_id,
defaults={},
)
if created:
return HttpResponseRedirect(reverse_lazy('carts:cart_edit'))
info = form.cleaned_data.get('contact_info')
status = models.Status.objects.get(pk=1)
user = self.request.user
order = models.Order.objects.update_or_create(
cart=cart,
contact_info=info,
status=status,
user=user,
)
self.request.session.delete('cart_id')
if self.request.user.is_authenticated:
cart_id = self.request.session.get('cart_id')
customer1 = carts_models.Cart.objects.get(pk=cart_id)
customer1.customer = self.request.user
customer1.save()
return super().form_valid(form)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
cart_id = self.request.session.get('cart_id')
cart, created = carts_models.Cart.objects.get_or_create(
pk=cart_id,
defaults={},
)
context['object'] = cart
return context
def get_success_url(self) -> str:
del self.request.session['cart_id']
return super().get_success_url()
def success(requsest):
return render(requsest, 'order/success.html')
User profile views:
class ProfileView(generic.DetailView):
def get(self, request, *args, **kwargs):
user = get_object_or_404(AppUser, pk=kwargs['pk'])
return render(request, 'app_profiles/profile_view.html', context={
'user': user,
'order': Order.objects.filter(user=request.user),
})
User profile template:
<thead>
<tr>
<th scope="col">Goods</th>
<th scope="col">Quantity</th>
<th scope="col">Total price</th>
<th scope="col">Status</th>
<th scope="col">Created</th>
<th scope="col">Updated</th>
</tr>
</thead>
<tbody>
<tr>
{% for order in order.all %}
<td>{{ order.created }}</td>
<td>{{ order.updated }}</td>
<td>{{ order.status }}</td>
{% endfor %}
I'll try to answer your questions best i can based on what i think you're asking.
Your questions:
How to add all information from user cart (that was formed into the
order) to user's profile?
How to make user's data and order's/cart's data possible to change
in the user's profile?
How to display several user's orders in separate rows in HTML table
(cause in my template all orders are in one row)?
1: Make a foreign key relation from the cart to the user using Django's ORM.
Example:
# Create your models here.
class Someclass(models.Model):
user = models.CharField(max_length=255, default='none')
subject = models.CharField(max_length=255, default='none')
date = models.DateField(auto_now_add=True)
def __str__(self):
return self.subject
class Someotherclass(models.Model):
relation = models.ForeignKey(
"Someclass", on_delete=models.CASCADE, null=True, related_name='myFkRelation')
detail = models.TextField()
date = models.DateField(auto_now_add=True, null=True)
This way you can connect the a cart with a user.
2: Create a (or 2) function(s) in your views.py where you can edit the data.
Example (using 2 separate functions):
# views.py
def change(request, id):
something = Someclass.objects.get(id=id)
context = {
'something': something,
}
return render(request, 'change.html', context)
def addchange(request, id):
change = request.POST['change']
something = Someclass.objects.get(id=id)
something.subject = change
something.date = datetime.now()
something.save()
return redirect('index')
----------
# urls.py
path('view/<int:id>/change/', views.change, name='change'),
path('view/<int:id>/change/addchange/', views.addchange, name='addchange'),
# of course you can change the urls to what you want as long as you give the id with it as a parameter to the views function.
----------
# change.html
<form action="addchange/" method="post">
{% csrf_token %}
<div class="form-group">
<label for="change">Change: *</label>
<textarea rows="4" cols="100" type="text" class="form-control" id="change" name="change" required></textarea>
</div>
<br>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
3: Create a for loop within a HTML table (given the context in views, where a user has a relation with the cart)
Example:
# views.py
def index(request):
User = get_user_model()
users = User.objects.all()
context = {
'users': users
}
return render(request, "index.html", context)
----------
# index.html
<table class="table table-hover table-sm">
<thead>
<tr>
<th scope="col">Users</th>
<th scope="col">Items</th>
</tr>
</thead>
<tbody>
{% for user in users %}
<tr>
<td>{{user.name}}</td>
<td>{{user.item}}</td>
# or whatever you want
</tr>
{% endfor %}
</tbody>
</table>
Hopefully this answers some (maybe all?) of your questions.
I am new to Django and trying to group and retrieve all expenses of the same category together and retrieve them in one "link like" table raw which when clicked can then display all the expenses in that category in another form.
I have these Models:
class Category(models.Model):
name = models.CharField(max_length=50)
class Meta:
verbose_name_plural = 'Categories'
unique_together = ("name",)
def __str__(self):
return self.name
class Expense(models.Model):
amount = models.FloatField()
date = models.DateField(default=now, )
description = models.TextField()
owner = models.ForeignKey(to=User, on_delete=models.CASCADE)
category = models.CharField(max_length=50)
def __str__(self):
return self.category
class Meta:
ordering = ['-date', '-pk']
homeView:
def home(request):
categories = Category.objects.all()
expenses = Expense.objects.filter(owner=request.user)
paginator = Paginator(expenses, 5)
page_number = request.GET.get('page')
page_obj = Paginator.get_page(paginator, page_number)
currency = UserPreference.objects.filter(user=request.user) # .currency
query = Expense.objects.values('category').annotate(total=Sum(
'amount')).order_by('category')
context = {
'expenses': expenses,
'page_obj': page_obj,
'currency': currency,
'query': query
}
return render(request, 'expenses/home.html', context)
mytemplate:
<div class="app-table">
<table class="table table-stripped table-hover">
<thead>
<tr>
<th>Amount</th>
<th>Category</th>
<th>Description</th>
<th>Date</th>
<th></th>
</tr>
</thead>
<tbody>
{% for myquery in query %}
<tr class="clickable-row" data-href="https://www.mavtechplanet.com/">
<td>{{myquery.category }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
I am trying to figure out things but are not coming out clearly. Any help is highly appreciated.
your template :
{% for myquery in query %}
<tr class="clickable-row" data-href="https://www.mavtechplanet.com/">
<td>{{myquery.category}}</td>
</tr>
{% endfor %}
add url to urls.py where in yourapp like this,
from youraapp.views import showCategoryExpenses
urlpatterns=[
.
.
.
path("/categoryExpenses/<pk:categoryPk>", showCategoryExpenses, name = "showCategoryExpenses"),
# if you save categories to expense with their name, you must change the <pk:categoryPk> to <slug:categoryName>
]
and add this view to yourapp.views like this:
def showCategoryExpenses(request, categoryPk): # if you save categories to expense with their name, change categoryPk to categoryName
expenses = Expense.objects.filter(category = categoryPk) # or category = categoryName
context = {
"expenses" : expenses
}
return render(request, "expenses/categoryExpenses.html", context)
and last, add this template to your template folder.. My English skills are not good but i try the solve and explain it. Maybe this is the answer you're looking for.
If you want show sum of all expenses in the category in this template, you can do it:
def showCategoryExpenses(request, categoryPk): # if you save categories to expense with their name, change categoryPk to categoryName
expenses = Expense.objects.filter(category = categoryPk) # or category = categoryName
expensesSum = 0
for expense in expenses:
expensesSum += expense.amount
context = {
"expenses" : expenses,
"expensesSum" : expensesSum
}
return render(request, "expenses/categoryExpenses.html", context)
Once you have categoryPk, you can try this way
from django.db.models import Sum
expenses = Expense.objects.filter(category = categoryPk).annotate(category_sum = Sum('amount')).values('category','category_sum')
# {'category':'ABC','category_sum':3000}
If you don't have any pk and want to annotate all objects then
expenses = Expense.objects.values('category').annotate(category_sum = Sum('amount')).values('category','category_sum')
I am working on an E-commerce project and I got lost in the middle to generate some kind of a report to get the total no. of a sold item after payment is made.
When the order is paid ordered = models.BooleanField(default=False) become True
I have tried to add the context with the total sold but it didn't work so I kept it in the code below but commented it.
Here is the Item models.py
class Item(models.Model):
title = models.CharField(max_length=100)
def __str__(self):
return self.title
Here is the OrderItemmodels.py
class OrderItem(models.Model):
ordered = models.BooleanField(default=False)
item = models.ForeignKey(Item, on_delete=models.CASCADE)
Here is the Order
class Order(models.Model):
items = models.ManyToManyField(OrderItem)
ordered = models.BooleanField(default=False)
Here is the views.py
class DesignerOnlyPostListView(ListView):
model = Item
template_name = "designer_only_posts.html"
context_object_name = 'items'
paginate_by = 6
def get_queryset(self):
user = get_object_or_404(User, username=self.kwargs.get('username'))
return Item.objects.filter(designer=user).order_by('-timestamp')
def get_context_data(self, **kwargs):
comments = Comment.objects.all()
# total_sold = Order.objects.all()
context = super().get_context_data(**kwargs)
context["total_comments"] = comments.count()
# context["total_sold"] = total_sold.count()
return context
Here is the template
{% for item in items %}
<tr>
<td>No. of Sold:</td>
<td>{{ item.total_sold.all.count }}</td>
</tr>
{% endfor %}
Seem in your template, you want to display total sold for each "item". In my opinion, i will add a method to Item, this approaching help you add custom filters as you want, something like this:
class Item(models.Model):
# ...
def count_sold(self):
return self.order_set.filter(ordered=True).count()
And in view:
<td>{{ item.count_sold }}</td>
Hope it will help you.
I have an inline formset where I need to assign the values of a ForeignKey field sequencially and univocally to each row of the inline formset. With the select default widget of a modelchoicefield everything works but I do not want the user to select any options but to be provided with a list of the options available in the foreignfield.
My inlineformset is the following:
class ResultadoForm(forms.ModelForm):
frequencia = forms.CharField(max_length=50)
tolerancia = forms.CharField(max_length=255)
def __init__(self, *args, **kwargs):
equipamento_id = kwargs.pop('equipamento_id', None)
super (ResultadoForm, self).__init__(*args, **kwargs)
self.fields['teste'].queryset = Teste.objects.filter(equipamento=equipamento_id).order_by('grupoteste', 'numeracao')
class Meta:
model = Resultado
exclude = ['actividade']
My view that renders the form:
#login_required()
def QAView(request, equipamento_id):
form = ActividadeForm()
form1 = ResultadoForm(equipamento_id)
equipamento = Equipamento.objects.get(id=equipamento_id)
testes_list = Teste.objects.filter(equipamento=equipamento_id)
FormSet = inlineformset_factory(Actividade, Resultado, form=ResultadoForm, fields='__all__', extra=len(testes_list))
formset = FormSet(form_kwargs={'equipamento_id': equipamento_id})
context = {'equipamento_id': equipamento_id, 'data':datetime.now(), 'equipamento': equipamento, 'form': form, 'testes_list': testes_list, 'formset': formset}
template = 'SFM/Equipamento/QA.html'
return render(request, template, context)
And in my template:
{% for r in formset %}
{{ r.id }}
{% for t in r.teste.field.queryset %}
<tr>
<td>{{ t}}</td>
<td>{{ t.frequencia }}</td>
<td>{{ t.tolerancia }}</td>
<td>{{ r.conforme }}</td>
</tr>
{% endfor %}
{% endfor %}
My Resultado Model:
class Resultado(models.Model):
CONFORME_CHOICES = (
("Sim", "Sim"),
("Não", "Não"),
)
teste = models.ForeignKey(Teste, null=True, blank=True, on_delete=models.CASCADE)
conforme = models.CharField(max_length=30, choices=CONFORME_CHOICES)
actividade = models.ForeignKey(Actividade, null=True, blank=True, on_delete=models.CASCADE)
def __str__(self):
return str(self.id)
With this template I get 4 rows. I should only get two. But I have two foreign key options so I am getting the two foreign options repeated.
Is it possible to assign one and only one foreign key to each row of this inlineformset? For example for the first row automatically assign the first foreign value and to the second row the second foreign value. Please help.
Consider a model:
class TempReport(models.Model):
id = models.AutoField(primary_key=True)
cost = models.FloatField()
revenue = models.FloatField()
# Some other fields not relevant to topic
class Meta:
managed = False
db_table = 'temp_report'
unique_together = (('sale_point', 'date'), ('id', 'sale_point'),)
#property
def net_income(self):
return self.revenue - self.cost
My goal is to calculate net income = revenue - cost
The code for the template:
<tbody>
{% for repdata in reporttable %}
<tr>
<td> {{ repdata.revenue }}</td>
<td> {{ repdata.cost }}</td>
<td> {{ repdata.net_income}}</td>
</tr>
{% endfor %}
</tbody>
...and the view
def tempreport(request):
reporttable = TempReport.objects.values('id','cost','revenue')
return render_to_response('report.html',
{'reporttable': reporttable},
context_instance = RequestContext(request))
I end up with an empty net_income even if no error message is present. Any ideas why this might be caused by ?
Creating a property on the model should work. The indentation on your code is incorrect. The property should be a method of the model class, not the Meta class.
class TempReport(models.Model):
id = models.AutoField(primary_key=True)
cost = models.FloatField()
revenue = models.FloatField()
# Some other fields not relevant to topic
class Meta:
managed = False
db_table = 'temp_report'
unique_together = (('sale_point', 'date'), ('id', 'sale_point'),)
#property
def net_income(self):
return self.revenue - self.cost
In your view, don't use values(), because that will return dictionaries rather than model instances, and you won't be able to access the property.
from django.shortcuts import render
def tempreport(request):
reporttable = TempReport.objects.all()
for r in reporttable:
r.net_income = r.revenue - r.cost
return render(request, 'report.html', {'reporttable': reporttable})
Note I've also updated the view to use render instead of the obsolete render_to_response.