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:

  1. How to add all information from user cart (that was formed into the order) to user's profile?
  2. How to make user's data and order's/cart's data possible to change in the user's profile?
  3. 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:

  1. How to add all information from user cart (that was formed into the order) to user's profile?
  2. How to make user's data and order's/cart's data possible to change in the user's profile?
  3. 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.

Back to Top