Displaying user orders in user's profile Django
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.