Project Structure Of Online Shopping Cart Using Python(Django) -Part 1-Code

Rashmi Mishra
0

 



Project Structure Of Online Shopping Cart

 Using Python(Django) 

── online_shopping_cart/                 # Main  project directory

   ── __init__.py                       # Initializes the Django app

   ── settings.py                       # Configuration for the Django project

   ── urls.py                           # Main URL routing for the project

   ── asgi.py                           # ASGI application configuration

   ── wsgi.py                           # WSGI application configuration

   └── manage.py                         # Django management script

── cart/                                 # Django app for shopping cart functionality

   ── __init__.py

   ── admin.py                          # Admin interface for cart app

   ── apps.py                           # Configuration for the cart app

   ── migrations/                       # Database migration files

   ── models.py                         # Database models (Product, Cart, Order, etc.)

   ── views.py                          # Views for cart-related actions (add to cart, checkout)

   ── urls.py                           # URLs for cart app (URL routing for cart)

   ── templates/                        # HTML templates for the cart app

      └── cart/

          ── cart_detail.html          # Cart detail page

          ── checkout.html             # Checkout page

          ── product_list.html         # Product listing page

          └── order_confirmation.html   # Order confirmation page

   ── static/                           # Static files (CSS, JS)

      ── css/

         └── styles.css                # Main CSS file

      └── js/

          └── cart.js                   # JavaScript for cart functionality (add/remove items)

   └── __init__.py

── products/                             # Django app for product management

   ── __init__.py

   ── admin.py                          # Admin interface for managing products

   ── apps.py                           # Configuration for the products app

   ── migrations/                       # Database migrations for products

   ── models.py                         # Database models for products (e.g., Product, Category)

   ── views.py                          # Views for displaying products, handling product search

   ── urls.py                           # URL routing for the products app

   ── templates/                        # HTML templates for products

      └── products/

          ── product_detail.html       # Product detail page

          └── product_list.html         # Product listing page

   └── __init__.py

── users/                                # Django app for user management (customer, admin)

   ── __init__.py

   ── admin.py                          # Admin interface for managing users

   ── apps.py                           # Configuration for the users app

   ── migrations/                       # Database migration files

   ── models.py                         # User model (extends Django User model)

   ── views.py                          # Views for registration, login, and user profile

   ── urls.py                           # URL routing for user-related pages (login, register)

   ── templates/                        # HTML templates for user-related functionality

      └── users/

          ── login.html                # Login page

          ── register.html             # Registration page

          └── profile.html              # User profile page

   └── __init__.py

── orders/                               # Django app for handling orders

   ── __init__.py

   ── admin.py                          # Admin interface for managing orders

   ── apps.py                           # Configuration for the orders app

   ── migrations/                       # Database migration files for orders

   ── models.py                         # Order models (Order, OrderItem, Payment)

   ── views.py                          # Views for handling order checkout, order history

   ── urls.py                           # URL routing for order-related actions

   ── templates/                        # HTML templates for orders

      └── orders/

          ── order_history.html        # User's order history page

          ── checkout.html             # Checkout page

          └── order_confirmation.html   # Order confirmation page

   └── __init__.py

── static/                               # Static files for the entire project (CSS, JS)

   ── images/

      └── logo.png                      # Logo image

   └── css/

       └── main.css                      # Global CSS

── media/                                # Directory for uploaded files (e.g., product images)

   └── products/

       └── product_image.jpg              # Example product image

└── templates/                            # Global templates for the entire project

    └── base.html                         # Base template for the entire site (header, footer)

Explanation of the Project Structure:

1.   online_shopping_cart/:

o    This is the root directory of the Django project containing the settings.py, urls.py, and other project-level files. It also contains configuration files for managing the Django project.

2.   cart/:

o    This app handles the core functionality of the shopping cart, including adding/removing products, managing the cart, and checking out. It includes views for the cart detail, checkout, and product list.

3.   products/:

o    The products app manages the products and categories. It allows admins to add/edit/remove products, and customers can browse and search for products on the frontend.

4.   users/:

o    This app handles user authentication, registration, and profile management. It also includes views for login, logout, and user registration.

5.   orders/:

o    This app handles the creation of orders, the payment process, and viewing order history. It manages the order process from checkout to confirmation and updates the order status.

6.   static/:

o    Contains all static files (CSS, JavaScript, images) for the frontend part of the website. Static files are served to users without dynamic processing.

7.   media/:

o    This directory stores user-uploaded files, such as product images, which can be served dynamically.

8.   templates/:

o    Contains global templates like base.html, which is extended by other templates for common layout elements like the header, footer, etc.


Code In Detail:

 __init__.py 

The __init__.py file in the online_shopping_cart directory is typically used to initialize the directory as a Python package. For a Django project, this file is usually empty.

The __init__.py file in a Django project or app typically remains empty unless specific initializations are needed for the package. However, if you want to include something in the file, you can add comments or basic configurations.

 __init__.py

"""

Initialization file for the online_shopping_cart project package.

This file is used to indicate that this directory is a Python package.

You can add package-level initializations here if needed.

"""

# You can add project-level imports or initializations here if required.

 This file is generally kept blank unless there is a special requirement to define package-level logic, imports, or configurations.

 

settings.py

"""

Django settings for online_shopping_cart project.

"""

 

import os

from pathlib import Path

 

# Build paths inside the project like this: BASE_DIR / 'subdir'.

BASE_DIR = Path(__file__).resolve().parent.parent

 

# SECURITY WARNING: keep the secret key used in production secret!

SECRET_KEY = 'your-secret-key-here'  # Replace with a strong secret key.

 

# SECURITY WARNING: don't run with debug turned on in production!

DEBUG = True

 

ALLOWED_HOSTS = []  # Update this for production (e.g., ['example.com']).

 

# Application definition

INSTALLED_APPS = [

    'django.contrib.admin',

    'django.contrib.auth',

    'django.contrib.contenttypes',

    'django.contrib.sessions',

    'django.contrib.messages',

    'django.contrib.staticfiles',

    'cart',       # Shopping cart app

    'products',   # Products management app

    'users',      # User management app

    'orders',     # Orders handling app

]

 

MIDDLEWARE = [

    'django.middleware.security.SecurityMiddleware',

    'django.contrib.sessions.middleware.SessionMiddleware',

    'django.middleware.common.CommonMiddleware',

    'django.middleware.csrf.CsrfViewMiddleware',

    'django.contrib.auth.middleware.AuthenticationMiddleware',

    'django.contrib.messages.middleware.MessageMiddleware',

    'django.middleware.clickjacking.XFrameOptionsMiddleware',

]

 

ROOT_URLCONF = 'online_shopping_cart.urls'

 

TEMPLATES = [

    {

        'BACKEND': 'django.template.backends.django.DjangoTemplates',

        'DIRS': [os.path.join(BASE_DIR, 'templates')],  # Global templates directory

        'APP_DIRS': True,

        'OPTIONS': {

            'context_processors': [

                'django.template.context_processors.debug',

                'django.template.context_processors.request',

                'django.contrib.auth.context_processors.auth',

                'django.contrib.messages.context_processors.messages',

            ],

        },

    },

]

 

WSGI_APPLICATION = 'online_shopping_cart.wsgi.application'

 

# Database

# https://docs.djangoproject.com/en/4.2/ref/settings/#databases

DATABASES = {

    'default': {

        'ENGINE': 'django.db.backends.postgresql',  # Use PostgreSQL

        'NAME': 'shopping_cart_db',                # Replace with your database name

        'USER': 'your_db_user',                    # Replace with your database user

        'PASSWORD': 'your_db_password',            # Replace with your database password

        'HOST': 'localhost',                       # Replace with your database host

        'PORT': '5432',                            # Replace with your database port

    }

}

 

# Password validation

# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [

    {

        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',

    },

    {

        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',

    },

    {

        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',

    },

    {

        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',

    },

]

 

# Internationalization

# https://docs.djangoproject.com/en/4.2/topics/i18n/

LANGUAGE_CODE = 'en-us'

 

TIME_ZONE = 'UTC'

 

USE_I18N = True

 

USE_L10N = True

 

USE_TZ = True

 

# Static files (CSS, JavaScript, Images)

# https://docs.djangoproject.com/en/4.2/howto/static-files/

STATIC_URL = '/static/'

STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]

STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')  # For production

 

# Media files (Uploaded files)

MEDIA_URL = '/media/'

MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

 

# Default primary key field type

# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

 

# Authentication settings

LOGIN_REDIRECT_URL = 'cart:cart_detail'  # Redirect after login

LOGOUT_REDIRECT_URL = 'users:login'     # Redirect after logout

 

# Email configuration (for user notifications, password resets, etc.)

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'

EMAIL_HOST = 'smtp.gmail.com'

EMAIL_PORT = 587

EMAIL_USE_TLS = True

EMAIL_HOST_USER = 'your-email@example.com'  # Replace with your email

EMAIL_HOST_PASSWORD = 'your-email-password'  # Replace with your email password

 


Key Highlights:

1.   Database Configuration:

o    The database is set to PostgreSQL. Replace it with your database credentials or change to SQLite for development (ENGINE: 'django.db.backends.sqlite3').

2.   Static and Media Files:

o    STATIC_URL and MEDIA_URL define the URLs for static and media files.

o    STATICFILES_DIRS includes global static files, while STATIC_ROOT is for production.

3.   Template Settings:

o    Includes DIRS for a global templates folder for base templates like base.html.

4.   Email Backend:

o    Configured for SMTP using Gmail. Replace with your email service provider's settings.

5.   Authentication Redirects:

o    LOGIN_REDIRECT_URL and LOGOUT_REDIRECT_URL ensure users are redirected to relevant pages after login/logout.


 urls.py

This file includes route definitions for the admin panel, as well as individual apps such as cart, products, users, and orders.


urls.py

"""

URL configuration for online_shopping_cart project.

"""

 

from django.contrib import admin

from django.urls import path, include

from django.conf import settings

from django.conf.urls.static import static

 

urlpatterns = [

    # Admin Panel

    path('admin/', admin.site.urls),

 

    # App URLs

    path('cart/', include('cart.urls', namespace='cart')),       # Shopping cart routes

    path('products/', include('products.urls', namespace='products')),  # Product management routes

    path('users/', include('users.urls', namespace='users')),    # User authentication and management

    path('orders/', include('orders.urls', namespace='orders')), # Order handling routes

 

    # Home Page (default landing page)

    path('', include('products.urls', namespace='home')),        # Redirect to product listing

]

 

# Serve media files during development

if settings.DEBUG:

    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

    urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

 


Key Points:

1.   Admin Panel:

o    The admin interface is accessible at /admin/.

2.   App-Specific Routes:

o    Each app (cart, products, users, and orders) has its own urls.py file for modular routing.

o    The namespace argument ensures that each app's URL names remain unique.

3.   Default Home Page:

o    The root URL ('/') redirects to the products app for a default product listing page. You can customize this to redirect to any desired view.

4.   Static and Media Files in Development:

o    When DEBUG = True, static and media files are served via Django's built-in static() function.

o    This setup is for development purposes only; in production, a web server (e.g., Nginx, Apache) should serve static

 asgi.py

This file sets up the ASGI application for the Django project, enabling asynchronous features and supporting protocols like WebSockets if needed in the future.


asgi.py

"""

ASGI config for online_shopping_cart project.

 

It exposes the ASGI callable as a module-level variable named ``application``.

 

For more information on this file, see

https://docs.djangoproject.com/en/stable/howto/deployment/asgi/

"""

 

import os

from django.core.asgi import get_asgi_application

# Set the default settings module for the 'asgi' application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'online_shopping_cart.settings')

 

# Get the default ASGI application

application = get_asgi_application()

 

# Optional: Adding WebSocket support or other async features

# Uncomment and extend this section if you use Django Channels or similar libraries

# from channels.routing import ProtocolTypeRouter, URLRouter

# from channels.auth import AuthMiddlewareStack

# import myapp.routing

 

# application = ProtocolTypeRouter({

#     "http": get_asgi_application(),

#     "websocket": AuthMiddlewareStack(

#         URLRouter(

#             myapp.routing.websocket_urlpatterns

#         )

#     ),

# })


Explanation of the Code:

1.   ASGI Configuration:

o    get_asgi_application() provides the standard ASGI application for serving the project.

o    ASGI (Asynchronous Server Gateway Interface) is the successor to WSGI, supporting both synchronous and asynchronous requests.

2.   Environment Variable:

o    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'online_shopping_cart.settings') ensures that Django knows which settings module to use.

3.   Optional WebSocket Support:

o    The commented-out section demonstrates how to extend the asgi.py file to support WebSockets using channels. This is useful for real-time features like notifications or live chat in the shopping cart system.

4.   Modular Design:

o    The application variable is the entry point for ASGI servers like Daphne, Uvicorn, or Hypercorn to serve your Django application.


Usage:

  • This file will automatically be used by your ASGI server when starting the project.
  • If you plan to implement real-time features like live updates in the shopping cart or order status, you can extend this file with Django Channels or similar libraries.

 wsgi.py

This file serves as the entry point for WSGI-compatible web servers (like Gunicorn or uWSGI) to serve the Django application.


wsgi.py

"""

WSGI config for online_shopping_cart project.

 

It exposes the WSGI callable as a module-level variable named ``application``.

 

For more information on this file, see

https://docs.djangoproject.com/en/stable/howto/deployment/wsgi/

"""

 

import os

from django.core.wsgi import get_wsgi_application

 

# Set the default settings module for the WSGI application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'online_shopping_cart.settings')

 

# Get the WSGI application

application = get_wsgi_application()

 


Explanation of the Code:

1.   WSGI Configuration:

o    The WSGI (Web Server Gateway Interface) standard is used for synchronous Python web applications.

o    get_wsgi_application() creates the WSGI application object that your WSGI server uses to communicate with your Django application.

2.   Environment Variable:

o    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'online_shopping_cart.settings') sets the default configuration module for the Django project.

3.   The application Variable:

o    The application variable is a callable that WSGI servers (like Gunicorn or uWSGI) use to forward requests to your Django application.

o    It acts as the entry point for your application in a production environment.

4.   Production-Ready:

o    This file is used in production deployments to serve the Django application via WSGI-compatible servers.


Usage in Deployment:

1.   Server Setup:

o    The wsgi.py file is pointed to by your WSGI server configuration (e.g., Gunicorn command: gunicorn online_shopping_cart.wsgi:application).

2.   Scalability:

o    For better performance, use a reverse proxy server like Nginx in front of your WSGI server.

3.   Integration:

o    Ensure that this file works alongside other deployment configurations (e.g., database, static files) for a smooth production setup.

 This file is a command-line utility that allows you to interact with your Django project, such as running the development server, applying migrations, creating superusers, and more.


manage.py

#!/usr/bin/env python

"""

Django's command-line utility for administrative tasks.

"""

 

import os

import sys

 

 

def main():

    """

    The main entry point for Django's command-line utilities.

    """

    # Set the default settings module for the Django project

    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'online_shopping_cart.settings')

   

    try:

        # Import and execute Django's command-line utility

        from django.core.management import execute_from_command_line

    except ImportError as exc:

        # Handle ImportError for missing Django

        raise ImportError(

            "Couldn't import Django. Are you sure it's installed and "

            "available on your PYTHONPATH environment variable? Did you "

            "forget to activate a virtual environment?"

        ) from exc

   

    # Execute the command-line arguments

    execute_from_command_line(sys.argv)

 

 

if __name__ == '__main__':

    main()


Explanation of the Code:

1.   Shebang Line (#!/usr/bin/env python):

o    Ensures that the script uses the correct Python interpreter when executed directly from the command line.

2.   Setting Default Settings Module:

o    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'online_shopping_cart.settings') specifies the settings module to use for the project.

3.   Command-Line Execution:

o    execute_from_command_line(sys.argv) processes the command-line arguments (e.g., runserver, migrate) and runs the appropriate Django commands.

4.   Error Handling:

o    The try...except block gracefully handles the case where Django is not installed or configured correctly. It provides a helpful error message.

5.   Main Entry Point:

o    The if __name__ == '__main__': block ensures that the main() function is called when the script is executed directly.


Usage of manage.py:

1.   Development Server:

bash

Copy code

python manage.py runserver

2.   Database Migrations:

bash

Copy code

python manage.py makemigrations

python manage.py migrate

3.   Create a Superuser:

bash

Copy code

python manage.py createsuperuser

4.   Check for Issues:

bash

Copy code

python manage.py check

5.   Run Tests:

bash

Copy code

python manage.py test

6.   Collect Static Files (for production):

bash

Copy code

python manage.py collectstatic


Key Notes:

  • This file is automatically generated by Django when starting a new project.
  • It serves as a centralized utility for managing your Django project through the command line.
  • Always use manage.py commands from the root of your Django project directory.

 

The __init__.py file is essential for marking a directory as a Python package, allowing it to be imported by other parts of the application. In the case of the cart app in your Django online shopping cart project, the __init__.py file is typically kept empty or may contain initialization code that will be executed when the app is loaded. This is particularly important for organizing the app structure.

Here’s the detailed code for the online_shopping_cart/cart/__init__.py file for your online shopping cart project:


__init__.py

# This file is used to mark the "cart" directory as a Python package.

# It can be left empty or used for initialization code when the app is loaded.

 

# In Django, the __init__.py file is usually kept empty, but it can include code

# that needs to run when the package is imported or initialized.

 

# For example, you could initialize signals or import necessary modules.

 

# Example: You could initialize signals for this app here (if needed).

# from . import signals

 


Explanation of the Code:

1.   Marking the Directory as a Package:

o    By default, the __init__.py file is required to mark a directory as a Python package. This enables Django to recognize the cart directory as an app within the project.

2.   Empty File:

o    In most cases, __init__.py is left empty if no specific initialization is required. It simply serves as a placeholder to indicate that the directory is a Python package.

3.   Possible Customization:

o    If your app requires initialization tasks (such as setting up signals or custom imports), this is the place to add the necessary code. For example, you might want to import models, configure app signals, or set up configurations when the app is initialized.

o    Example: If you had custom signals for the cart app (e.g., when an item is added to the cart), you could import a signals.py file in __init__.py to set them up:

from . import signals

4.   Importing Modules:

o    If you have defined additional helper functions, models, or configurations that need to be initialized or imported when the app starts, you can import them here.


When to Modify __init__.py:

  • Signals: If your app has custom Django signals, they would be imported in this file to ensure they are ready to be used when the app is loaded.
  • App-Specific Configuration: If you need to run specific code when the cart app is initialized (e.g., configuring some variables or settings), you can add that logic here.

However, for a basic Django app like the cart app in your online shopping cart project, it is usually safe to leave this file empty unless you have specific initialization requirements.

 


The admin.py file in a Django app is used to define how models are displayed and interacted with in the Django Admin interface. In the case of your cart app in the online shopping cart project, you'll use this file to register models related to the shopping cart functionality, such as Product, Cart, Order, etc.

Here's the detailed code for online_shopping_cart/cart/admin.py:


admin.py

from django.contrib import admin

from .models import Cart, CartItem, Order, OrderItem, Product

 

# Register your models here.

 

class CartItemInline(admin.TabularInline):

    """

    Inline admin for CartItem, which will be shown inside Cart.

    """

    model = CartItem

    extra = 1  # The number of empty CartItems to display by default

    fields = ['product', 'quantity', 'price', 'total']

 

class CartAdmin(admin.ModelAdmin):

    """

    Admin configuration for Cart model.

    """

    list_display = ('user', 'created_at', 'updated_at', 'get_cart_total')

    search_fields = ('user__username',)

    inlines = [CartItemInline]

 

    def get_cart_total(self, obj):

        """

        Method to calculate and display the total price of the cart.

        """

        total = sum(item.total for item in obj.cartitem_set.all())

        return total

    get_cart_total.short_description = 'Cart Total'

 

class OrderItemInline(admin.TabularInline):

    """

    Inline admin for OrderItem, which will be shown inside Order.

    """

    model = OrderItem

    extra = 1

    fields = ['product', 'quantity', 'price', 'total']

 

class OrderAdmin(admin.ModelAdmin):

    """

    Admin configuration for Order model.

    """

    list_display = ('user', 'order_date', 'status', 'get_order_total')

    search_fields = ('user__username',)

    inlines = [OrderItemInline]

 

    def get_order_total(self, obj):

        """

        Method to calculate and display the total price of the order.

        """

        total = sum(item.total for item in obj.orderitem_set.all())

        return total

    get_order_total.short_description = 'Order Total'

 

class ProductAdmin(admin.ModelAdmin):

    """

    Admin configuration for Product model.

    """

    list_display = ('name', 'price', 'stock', 'created_at', 'updated_at')

    search_fields = ('name',)

    list_filter = ('category',)

 

# Register models with their respective admin classes.

admin.site.register(Cart, CartAdmin)

admin.site.register(Order, OrderAdmin)

admin.site.register(Product, ProductAdmin)

 


Explanation of the Code:

1.   Import Statements:

o    The necessary models from the models.py file are imported, such as Cart, CartItem, Order, OrderItem, and Product.

2.   Inline Models (TabularInline):

o    CartItemInline: This inline admin interface is used to display CartItem models inside the Cart model. It uses a tabular layout, which displays a list of CartItem objects with fields for product, quantity, price, and total.

o    OrderItemInline: This is similar to CartItemInline, but for OrderItem. It will be displayed inside the Order model in the Django Admin interface.

3.   Admin Classes (ModelAdmin):

o    CartAdmin: The admin configuration for the Cart model. This includes:

§  list_display: Specifies which fields should be shown in the list view of carts (e.g., user, created_at, updated_at, and the custom get_cart_total method).

§  search_fields: Allows searching by the user's username in the admin interface.

§  inlines: Adds the inline CartItemInline for managing items within the cart directly in the Cart admin view.

§  get_cart_total: A custom method to calculate the total price of all items in the cart.

o    OrderAdmin: The admin configuration for the Order model. This includes:

§  list_display: Displays the user, order_date, status, and the total price of the order in the list view.

§  inlines: Adds the inline OrderItemInline for managing items within the order directly in the Order admin view.

§  get_order_total: A custom method to calculate the total price of all items in the order.

o    ProductAdmin: The admin configuration for the Product model. This includes:

§  list_display: Shows name, price, stock, created_at, and updated_at fields in the product list.

§  search_fields: Allows searching for products by their name.

§  list_filter: Adds filtering options by category in the admin interface.

4.   Model Registration:

o    Each model (Cart, Order, Product) is registered with Django’s admin interface using admin.site.register(), and the appropriate custom admin class is passed to control how the model is displayed and managed in the admin panel.


Key Notes:

  • Inlines: TabularInline is used to display related models (e.g., CartItem or OrderItem) directly within the parent model (Cart or Order) in the Django admin.
  • Custom Methods: Methods like get_cart_total and get_order_total allow you to calculate and display totals in the admin panel, providing useful insights into the cart and order.
  • Search and Filters: Fields like search_fields and list_filter enhance the usability of the admin interface by enabling search functionality and filtering based on certain fields (like category or username).

Usage:

  • After you define this admin.py, you'll be able to manage Cart, Order, and Product models directly from the Django admin interface.
  • To access the Django admin panel, you need to have an admin user. You can create one by running:

python manage.py createsuperuser

  • Then, visit http://127.0.0.1:8000/admin/ to log in to the Django Admin panel and manage the carts, orders, and products.

This setup gives you an easy and powerful way to manage the core functionality of the shopping cart, products, and orders through Django's built-in admin interface.

 

apps.py

The apps.py file in a Django application defines the configuration for the app. In the context of the cart app in your online shopping cart project, the CartConfig class will be defined here to register the app and provide configurations related to it.

apps.py

from django.apps import AppConfig

 

class CartConfig(AppConfig):

    """

    Cart app configuration class that inherits from AppConfig.

    This class is used to configure the 'cart' app in the Django project.

    """

    name = 'cart'  # The name of the app

    verbose_name = 'Shopping Cart'  # A human-readable name for the app (optional)

 

    def ready(self):

        """

        The ready method is called when the app is fully loaded.

        You can use this method to import signal handlers or do other startup tasks.

        """

        # Import signals (if any)

        # Example:

        # from . import signals

        pass


Explanation of the Code:

1.   Imports:

o    AppConfig is imported from django.apps. This is a built-in class used to configure a Django app. You inherit from AppConfig to define your app's configuration.

2.   CartConfig Class:

o    The class CartConfig inherits from AppConfig and serves as the configuration for the cart app in the Django project.

3.   name:

o    The name attribute is a string representing the Python path to the app. In this case, it is set to 'cart', which matches the name of the app directory. This ensures that Django can correctly locate the app when it is included in the project.

4.   verbose_name (Optional):

o    The verbose_name attribute is an optional human-readable name for the app. It will be used in the Django Admin interface or anywhere that the app is displayed in a user-friendly manner. In this case, it's set to 'Shopping Cart'.

5.   ready() Method:

o    The ready() method is a special method in Django's app configuration. It is called when the app is loaded, and it is a place to include any initialization code that needs to run once the app is ready.

o    In this method, you might import signals or perform other startup tasks like connecting signals or configuring app-level resources. The pass statement is used here as a placeholder, but this method can be extended as needed. For example, if you had signal handlers in the app, you would import them here.


Example of Signal Import (Optional):

If you need to use Django signals in your app (for example, to update inventory when a product is added to a cart), you would import them in the ready() method like this:

def ready(self):

    """

    The ready method is called when the app is fully loaded.

    You can use this method to import signal handlers or do other startup tasks.

    """

    # Import signals for cart operations (e.g., after adding an item to the cart)

    from . import signals

This is just an example of how to import signals if you choose to implement them.


Where to Use the apps.py:

The apps.py file is automatically used by Django when you define it, but you must also ensure that the app is listed in the INSTALLED_APPS list within the settings.py file of the project.

Here’s an example of how the cart app should be added in INSTALLED_APPS in settings.py:

INSTALLED_APPS = [

    # Other apps...

    'cart',  # The cart app should be listed here

]

Summary:

The apps.py file in the cart app is responsible for configuring the app within the Django project. It provides a place to set attributes like the app's name, verbose name, and any initialization logic needed when the app is loaded, such as importing signals. The file is an integral part of the Django app configuration system.

 

The models.py file in the cart app is where you define the database models for the shopping cart functionality. These models represent the structure of your database tables and define how the data is stored. In this case, we will need models to handle the cart items, orders, and the relationship between products and users.


models.py

from django.db import models

from django.contrib.auth.models import User

from products.models import Product

 

class Cart(models.Model):

    """

    This model represents a shopping cart for a user. A cart contains many cart items.

    """

    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='cart')

    created_at = models.DateTimeField(auto_now_add=True)

    updated_at = models.DateTimeField(auto_now=True)

 

    def __str__(self):

        return f"Cart for {self.user.username}"

 

class CartItem(models.Model):

    """

    This model represents an item in the shopping cart.

    A cart item is associated with a product and a cart.

    """

    cart = models.ForeignKey(Cart, on_delete=models.CASCADE, related_name='items')

    product = models.ForeignKey(Product, on_delete=models.CASCADE)

    quantity = models.PositiveIntegerField(default=1)

    added_at = models.DateTimeField(auto_now_add=True)

 

    def __str__(self):

        return f"{self.quantity} x {self.product.name} in cart for {self.cart.user.username}"

 

    def total_price(self):

        """

        Calculates the total price of the cart item (product price * quantity).

        """

        return self.product.price * self.quantity

 

class Order(models.Model):

    """

    This model represents a completed order. It is related to the user who placed the order.

    """

    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='orders')

    created_at = models.DateTimeField(auto_now_add=True)

    updated_at = models.DateTimeField(auto_now=True)

    status = models.CharField(max_length=50, default='Pending')

    shipping_address = models.TextField()

    total_amount = models.DecimalField(max_digits=10, decimal_places=2, default=0)

 

    def __str__(self):

        return f"Order {self.id} for {self.user.username}"

 

    def update_total_amount(self):

        """

        Updates the total amount for the order based on the cart items.

        """

        total = sum(item.total_price() for item in self.items.all())

        self.total_amount = total

        self.save()

 

    def add_items_from_cart(self, cart):

        """

        Adds items from the cart to the order.

        This method is typically called when an order is placed.

        """

        for cart_item in cart.items.all():

            OrderItem.objects.create(

                order=self,

                product=cart_item.product,

                quantity=cart_item.quantity

            )

 

class OrderItem(models.Model):

    """

    This model represents a product in an order.

    An order can have multiple items, and each item corresponds to a product.

    """

    order = models.ForeignKey(Order, on_delete=models.CASCADE, related_name='items')

    product = models.ForeignKey(Product, on_delete=models.CASCADE)

    quantity = models.PositiveIntegerField(default=1)

 

    def __str__(self):

        return f"{self.quantity} x {self.product.name} in order {self.order.id}"

 

    def total_price(self):

        """

        Calculates the total price of the order item (product price * quantity).

        """

        return self.product.price * self.quantity

 


Explanation of the Code:

1.   Imports:

o    models is imported from django.db to define the database models.

o    User is imported from django.contrib.auth.models to associate the cart and orders with a specific user.

o    Product is imported from the products.models file to establish a relationship with the products in the cart and orders.

2.   Cart Model:

o    The Cart model represents a shopping cart associated with a specific user (OneToOneField to User).

o    It includes fields like created_at and updated_at to track when the cart was created and updated.

o    The __str__() method provides a human-readable representation of the cart for debugging.

3.   CartItem Model:

o    The CartItem model represents an individual product added to a cart.

o    It has a ForeignKey to the Cart model, linking each cart item to a specific cart.

o    The quantity field represents the number of units of the product in the cart.

o    The total_price() method calculates the total price of a cart item based on the product’s price and the quantity.

o    The __str__() method returns a string that describes the cart item.

4.   Order Model:

o    The Order model represents a completed order that is associated with a user (ForeignKey to User).

o    Fields include created_at, updated_at, status, shipping_address, and total_amount (which is updated when the order’s total price is calculated).

o    The update_total_amount() method calculates the total amount of the order by summing the total price of each item in the order.

o    The add_items_from_cart() method allows adding items from the cart to the order when the user proceeds to checkout.

5.   OrderItem Model:

o    The OrderItem model represents a product included in a specific order.

o    It has a ForeignKey to the Order model and a ForeignKey to the Product model to link each item in the order to a product.

o    The quantity field represents how many units of the product are included in the order.

o    The total_price() method calculates the total price of the order item based on the product's price and the quantity.

o    The __str__() method returns a string representation of the order item.


Relationships Between Models:

  • Cart and CartItem:
    • A cart can have multiple items, but each cart item belongs to one cart.
    • This relationship is established by the ForeignKey from CartItem to Cart.
  • Order and OrderItem:
    • An order can have multiple items (products), and each order item belongs to one order.
    • This relationship is established by the ForeignKey from OrderItem to Order.
  • Product and CartItem / OrderItem:
    • Each CartItem and OrderItem is related to a Product, meaning each cart or order item is linked to a specific product.

Example Usage:

When a user adds products to their cart, the Cart and CartItem models will be used to store that data. Once the user proceeds to checkout, an Order is created, and the items from the cart are transferred into the OrderItem model. The total amount of the order is then calculated based on the items in the order.


Migrations:

After defining these models, you will need to run Django’s migration commands to create the corresponding database tables:

1.   Create migration files:

python manage.py makemigrations

2.   Apply migrations to update the database:

python manage.py migrate


 

The views.py file in the cart app will handle the logic for displaying the shopping cart, adding/removing items, and processing the checkout and order creation. In a typical e-commerce shopping cart, you'll need views for:

  • Displaying the shopping cart with items.
  • Adding items to the cart.
  • Removing items from the cart.
  • Updating quantities of cart items.
  • Proceeding to checkout and creating an order.

views.py

from django.shortcuts import render, redirect, get_object_or_404

from django.contrib.auth.decorators import login_required

from django.http import HttpResponse

from .models import Cart, CartItem, Order, OrderItem

from products.models import Product

from django.contrib import messages

 

@login_required

def view_cart(request):

    """

    View the shopping cart.

    Displays all items in the cart and the total price.

    """

    try:

        cart = Cart.objects.get(user=request.user)

        cart_items = cart.items.all()

        total_price = sum(item.total_price() for item in cart_items)

    except Cart.DoesNotExist:

        cart_items = []

        total_price = 0

 

    return render(request, 'cart/view_cart.html', {

        'cart_items': cart_items,

        'total_price': total_price

    })

 

 

@login_required

def add_to_cart(request, product_id):

    """

    Add a product to the cart. If the product is already in the cart,

    the quantity is updated; otherwise, a new CartItem is created.

    """

    product = get_object_or_404(Product, id=product_id)

 

    try:

        cart = Cart.objects.get(user=request.user)

    except Cart.DoesNotExist:

        cart = Cart.objects.create(user=request.user)

 

    cart_item, created = CartItem.objects.get_or_create(cart=cart, product=product)

 

    if not created:

        cart_item.quantity += 1  # If item already in cart, increase quantity

        cart_item.save()

    else:

        cart_item.quantity = 1  # If new item, set quantity to 1

        cart_item.save()

 

    messages.success(request, f'{product.name} added to your cart.')

    return redirect('cart:view_cart')

 

 

@login_required

def remove_from_cart(request, cart_item_id):

    """

    Remove an item from the cart.

    """

    cart_item = get_object_or_404(CartItem, id=cart_item_id)

 

    if cart_item.cart.user == request.user:

        cart_item.delete()

        messages.success(request, 'Item removed from your cart.')

    else:

        messages.error(request, 'You cannot remove items from another user\'s cart.')

 

    return redirect('cart:view_cart')

 

 

@login_required

def update_cart(request, cart_item_id):

    """

    Update the quantity of a product in the cart.

    """

    cart_item = get_object_or_404(CartItem, id=cart_item_id)

 

    if cart_item.cart.user == request.user:

        quantity = request.POST.get('quantity')

 

        if quantity.isdigit() and int(quantity) > 0:

            cart_item.quantity = int(quantity)

            cart_item.save()

            messages.success(request, 'Cart updated successfully.')

        else:

            messages.error(request, 'Invalid quantity.')

 

    else:

        messages.error(request, 'You cannot update items in another user\'s cart.')

 

    return redirect('cart:view_cart')

 

 

@login_required

def checkout(request):

    """

    Handle the checkout process: create an order and transfer items from the cart to the order.

    """

    try:

        cart = Cart.objects.get(user=request.user)

        cart_items = cart.items.all()

    except Cart.DoesNotExist:

        cart_items = []

 

    if not cart_items:

        messages.error(request, 'Your cart is empty.')

        return redirect('cart:view_cart')

 

    # Create an order

    order = Order.objects.create(user=request.user, shipping_address=request.POST.get('shipping_address'))

 

    # Add items to the order

    for cart_item in cart_items:

        OrderItem.objects.create(

            order=order,

            product=cart_item.product,

            quantity=cart_item.quantity

        )

 

    # Update total amount

    order.update_total_amount()

 

    # Empty the cart after checkout

    cart.items.all().delete()

 

    messages.success(request, 'Your order has been placed successfully.')

    return redirect('cart:view_order', order_id=order.id)

 

 

@login_required

def view_order(request, order_id):

    """

    View the details of an order.

    """

    order = get_object_or_404(Order, id=order_id, user=request.user)

 

    return render(request, 'cart/view_order.html', {

        'order': order

    })

 


Explanation of the Views:

1. view_cart:

  • This view is responsible for displaying the contents of the shopping cart. It checks if the user has a cart, and if so, retrieves all the cart items. The total price of all cart items is calculated and passed to the template for rendering.
  • If the user does not have a cart, it will show an empty cart.

2. add_to_cart:

  • This view adds a product to the shopping cart. If the user already has a cart, the product is either added to the cart (if it doesn’t exist) or the quantity of the existing cart item is incremented.
  • If the cart item does not exist in the cart, a new entry is created.
  • A success message is shown to the user, and they are redirected back to the cart view.

3. remove_from_cart:

  • This view allows a user to remove an item from their cart. If the cart item belongs to the current user's cart, it is deleted from the database.
  • A success or error message is displayed to the user depending on the action.

4. update_cart:

  • This view allows the user to update the quantity of an item in their cart. The user submits the new quantity via a POST request, and the cart item’s quantity is updated accordingly.
  • It checks for a valid quantity and provides feedback to the user.

5. checkout:

  • This view handles the checkout process. It checks if the user has any items in the cart, creates an Order for the user, and transfers all cart items into the OrderItem model. It also updates the total amount of the order.
  • After the order is placed, the items in the cart are deleted, and a success message is shown to the user.

6. view_order:

  • This view allows the user to view the details of a specific order, such as the products they ordered, the quantity, and the total price. It fetches the order using the order_id and ensures that the order belongs to the logged-in user.

URL Patterns:

urls.py

To ensure that these views are accessible, you'll need to define URL patterns in the urls.py file of the cart app:


from django.urls import path

from . import views

 

app_name = 'cart'

 

urlpatterns = [

    path('', views.view_cart, name='view_cart'),

    path('add/<int:product_id>/', views.add_to_cart, name='add_to_cart'),

    path('remove/<int:cart_item_id>/', views.remove_from_cart, name='remove_from_cart'),

    path('update/<int:cart_item_id>/', views.update_cart, name='update_cart'),

    path('checkout/', views.checkout, name='checkout'),

    path('order/<int:order_id>/', views.view_order, name='view_order'),

]


 

 Notes:

1.   messages Framework:

o    The messages.success() and messages.error() methods are used to provide feedback to the user about actions performed in the cart, like adding items, updating quantities, or checking out.

2.   Redirects:

o    After each action (adding/removing/updating items or checking out), the user is redirected to the appropriate page, such as the cart view or order details.

3.   Security:

o    The login_required decorator ensures that only authenticated users can access the cart-related views. If a user is not logged in, they will be redirected to the login page.

4.   get_object_or_404():

o    This method is used to fetch the cart, cart items, or orders from the database, ensuring that the requested object exists. If not, it raises a 404 error.


Templates:

You'll need to create templates to render the views, such as view_cart.html, view_order.html, etc. These templates will be responsible for displaying the cart items, order details, and handling the user interface for adding, removing, or updating items.

This setup provides the core functionality of a shopping cart, allowing users to add, remove, and update items, view their cart, and place orders.

 

The urls.py file in the cart app will define the routes (URLs) for the cart-related views in the online shopping cart project. This includes views for displaying the cart, adding/removing products, updating quantities, and handling the checkout process.


urls.py

from django.urls import path

from . import views 

app_name = 'cart' 

urlpatterns = [

    # View the cart (display items and total price)

    path('', views.view_cart, name='view_cart'),

 

    # Add a product to the cart (by product ID)

    path('add/<int:product_id>/', views.add_to_cart, name='add_to_cart'), 

    # Remove a product from the cart (by cart item ID)

    path('remove/<int:cart_item_id>/', views.remove_from_cart, name='remove_from_cart'), 

    # Update the quantity of a product in the cart (by cart item ID)

    path('update/<int:cart_item_id>/', views.update_cart, name='update_cart'), 

    # Proceed to checkout and place the order

    path('checkout/', views.checkout, name='checkout'), 

    # View details of a specific order (by order ID)

    path('order/<int:order_id>/', views.view_order, name='view_order'),

]

 


Explanation of the URL patterns:

1.   path('', views.view_cart, name='view_cart'):

o    This is the root URL for the cart page.

o    It maps to the view_cart view, which displays all the products currently in the cart, along with the total price.

2.   path('add/<int:product_id>/', views.add_to_cart, name='add_to_cart'):

o    This URL allows users to add a product to their cart.

o    The <int:product_id> part of the URL captures the ID of the product being added to the cart.

o    It maps to the add_to_cart view, where the product with the given ID is added to the user's cart.

3.   path('remove/<int:cart_item_id>/', views.remove_from_cart, name='remove_from_cart'):

o    This URL allows users to remove a product from their cart.

o    The <int:cart_item_id> part of the URL captures the ID of the specific cart item to be removed.

o    It maps to the remove_from_cart view, which deletes the specified cart item from the user's cart.

4.   path('update/<int:cart_item_id>/', views.update_cart, name='update_cart'):

o    This URL allows users to update the quantity of a specific product in their cart.

o    The <int:cart_item_id> part of the URL captures the ID of the cart item to be updated.

o    It maps to the update_cart view, where the quantity of the cart item can be changed.

5.   path('checkout/', views.checkout, name='checkout'):

o    This URL allows users to proceed to checkout.

o    It maps to the checkout view, where the user can review their cart and place the order.

o    The view will create an Order for the user and transfer items from the cart to the order.

6.   path('order/<int:order_id>/', views.view_order, name='view_order'):

o    This URL displays the details of a specific order.

o    The <int:order_id> part of the URL captures the ID of the order to be viewed.

o    It maps to the view_order view, where the user can see the details of their placed order.


How it works:

  • app_name = 'cart':
    • This line defines the namespace for the URL patterns of the cart app. This allows you to use reverse URL lookups with the format cart:view_cart, cart:add_to_cart, etc.
  • URL Parameterization:
    • The URLs for adding, removing, and updating items include dynamic parameters such as <int:product_id> and <int:cart_item_id>, which allow the views to handle specific instances of products or cart items based on their IDs.

Example URL Usage:

1.   View Cart:

o    URL: /cart/

o    This will load the cart page showing all items in the user's cart.

2.   Add to Cart:

o    URL: /cart/add/1/

o    This will add the product with ID 1 to the cart.

3.   Remove from Cart:

o    URL: /cart/remove/1/

o    This will remove the cart item with ID 1 from the cart.

4.   Update Cart:

o    URL: /cart/update/1/

o    This will update the quantity of the cart item with ID 1.

5.   Checkout:

o    URL: /cart/checkout/

o    This will initiate the checkout process.

6.   View Order:

o    URL: /cart/order/1/

o    This will display the details of the order with ID 1.


Next Steps:

  • After creating the urls.py file, you should ensure that it is included in the main project’s urls.py file. Typically, this would look like:

from django.contrib import admin

from django.urls import path, include

urlpatterns = [

    path('admin/', admin.site.urls),

    path('cart/', include('cart.urls')),  # Include cart app URLs

    # other app URLs

]


Conclusion:

The urls.py file in the cart app defines the URL routes for cart management, including adding/removing products, updating quantities, checking out, and viewing orders. With these URL patterns, users can interact with their cart and orders on the website.

The cart_detail.html template is responsible for displaying the user's shopping cart in a detailed view. It typically includes information about the items in the cart, such as the product name, quantity, price, and the total cost. Users should also be able to update the quantity, remove items, and proceed to checkout.


cart_detail.html

{% extends 'base_generic.html' %}

{% block content %}

<div class="container">

    <h2>Your Shopping Cart</h2> 

    {% if cart_items %}

        <table class="table table-bordered">

            <thead>

                <tr>

                    <th>Product</th>

                    <th>Price</th>

                    <th>Quantity</th>

                    <th>Total</th>

                    <th>Action</th>

                </tr>

            </thead>

            <tbody>

                {% for item in cart_items %}

                    <tr>

                        <td>{{ item.product.name }}</td>

                        <td>${{ item.product.price }}</td>

                        <td>

                            <form action="{% url 'cart:update_cart' item.id %}" method="post">

                                {% csrf_token %}

                                <input type="number" name="quantity" value="{{ item.quantity }}" min="1" class="form-control" style="width: 60px;">

                                <button type="submit" class="btn btn-warning btn-sm">Update</button>

                            </form>

                        </td>

                        <td>${{ item.product.price * item.quantity }}</td>

                        <td>

                            <a href="{% url 'cart:remove_from_cart' item.id %}" class="btn btn-danger btn-sm">Remove</a>

                        </td>

                    </tr>

                {% endfor %}

            </tbody>

        </table>

 

        <div class="row">

            <div class="col-md-8">

                <a href="{% url 'cart:view_cart' %}" class="btn btn-secondary">Continue Shopping</a>

            </div>

            <div class="col-md-4 text-right">

                <h4>Total: ${{ total_price }}</h4>

                <a href="{% url 'cart:checkout' %}" class="btn btn-primary">Proceed to Checkout</a>

            </div>

        </div>

    {% else %}

        <p>Your cart is empty. Start shopping now!</p>

        <a href="{% url 'cart:view_cart' %}" class="btn btn-primary">Start Shopping</a>

    {% endif %}

</div>

{% endblock %}

 


Explanation of the cart_detail.html Template:

1.   Extending the Base Template:

{% extends 'base_generic.html' %}

o    This line tells Django to extend a base template called base_generic.html. The base template usually includes common elements such as the header, footer, and navigation bar.

2.   Block Content:

{% block content %}

...

{% endblock %}

o    The block content section is where the specific content of this page is inserted. In this case, it contains the shopping cart's HTML structure.

3.   Displaying Cart Items:

{% if cart_items %}

<table class="table table-bordered">

...

</table>

{% else %}

<p>Your cart is empty. Start shopping now!</p>

{% endif %}

o    The cart_items is a list of the items in the user's cart. The {% if cart_items %} block checks if there are any items in the cart. If there are, it displays them in a table. Otherwise, a message is shown informing the user that their cart is empty.

4.   Table for Cart Items:

o    The table contains columns for:

§  Product: Displays the product name.

§  Price: Displays the price of each product.

§  Quantity: Displays a form where users can update the quantity of each item in their cart. This form sends a POST request to update the cart.

§  Total: Displays the total cost for the item (product price * quantity).

§  Action: A button to remove the item from the cart.

For each cart_item, it displays the product name, price, and quantity. Additionally, it calculates the total price for each item based on the price and quantity.

5.   Form for Updating Quantity:

<form action="{% url 'cart:update_cart' item.id %}" method="post">

    {% csrf_token %}

    <input type="number" name="quantity" value="{{ item.quantity }}" min="1" class="form-control" style="width: 60px;">

    <button type="submit" class="btn btn-warning btn-sm">Update</button>

</form>

o    This form allows the user to update the quantity of the product in the cart. It sends a POST request to the URL defined for the update_cart view, which processes the new quantity.

o    The form includes a CSRF token for security, an input field for changing the quantity, and a button to submit the form.

6.   Removing an Item:

<a href="{% url 'cart:remove_from_cart' item.id %}" class="btn btn-danger btn-sm">Remove</a>

o    This link allows users to remove a product from the cart by clicking the "Remove" button. It sends a request to the remove_from_cart view, which deletes the item from the cart.

7.   Total Price and Checkout:

<div class="col-md-4 text-right">

    <h4>Total: ${{ total_price }}</h4>

    <a href="{% url 'cart:checkout' %}" class="btn btn-primary">Proceed to Checkout</a>

</div>

o    This section shows the total price for all items in the cart and provides a button that links to the checkout page (checkout view). The total_price is passed from the view and represents the sum of all cart item totals.

8.   Empty Cart Message:

<p>Your cart is empty. Start shopping now!</p>

<a href="{% url 'cart:view_cart' %}" class="btn btn-primary">Start Shopping</a>

o    If there are no items in the cart, this message is displayed, with a link to continue shopping.


How the Template Works:

  • The template displays the products in the user's cart, showing the product name, price, quantity, and total cost.
  • Users can update the quantity of each product in their cart, remove items, or proceed to checkout.
  • The total price of the cart is dynamically calculated and displayed at the bottom of the page.
  • If the cart is empty, users are prompted to start shopping.

Next Steps:

  • View Logic: The view_cart view should retrieve the cart items and calculate the total_price, passing them to the template.
  • Form Handling: The forms for updating the cart quantity and removing items should be connected to the corresponding views that handle these actions (e.g., update_cart, remove_from_cart).

Conclusion:

This cart_detail.html template provides a user-friendly interface for managing the shopping cart. It allows users to view, update, and remove products in their cart, while also calculating and displaying the total price.

 checkout.html

The checkout.html template is crucial for providing users with a final step before completing their purchase in an online shopping cart system. It allows the user to review their cart, input shipping information, choose a payment method, and proceed with the checkout process.


checkout.html

{% extends 'base_generic.html' %}

{% block content %}

<div class="container">

    <h2>Checkout</h2>

 

    {% if cart_items %}

        <!-- Cart Details Section -->

        <div class="row">

            <div class="col-md-8">

                <h3>Your Cart</h3>

                <table class="table table-bordered">

                    <thead>

                        <tr>

                            <th>Product</th>

                            <th>Price</th>

                            <th>Quantity</th>

                            <th>Total</th>

                        </tr>

                    </thead>

                    <tbody>

                        {% for item in cart_items %}

                            <tr>

                                <td>{{ item.product.name }}</td>

                                <td>${{ item.product.price }}</td>

                                <td>{{ item.quantity }}</td>

                                <td>${{ item.product.price * item.quantity }}</td>

                            </tr>

                        {% endfor %}

                    </tbody>

                </table>

                <h4>Total: ${{ total_price }}</h4>

            </div>

 

            <!-- Shipping Information Section -->

            <div class="col-md-4">

                <h3>Shipping Information</h3>

                <form action="{% url 'cart:process_checkout' %}" method="post">

                    {% csrf_token %}

                   

                    <!-- User Address Input Fields -->

                    <div class="form-group">

                        <label for="address">Shipping Address</label>

                        <input type="text" class="form-control" id="address" name="address" required>

                    </div>

                    <div class="form-group">

                        <label for="city">City</label>

                        <input type="text" class="form-control" id="city" name="city" required>

                    </div>

                    <div class="form-group">

                        <label for="postal_code">Postal Code</label>

                        <input type="text" class="form-control" id="postal_code" name="postal_code" required>

                    </div>

                    <div class="form-group">

                        <label for="country">Country</label>

                        <input type="text" class="form-control" id="country" name="country" required>

                    </div>

 

                    <!-- Payment Method -->

                    <div class="form-group">

                        <label for="payment_method">Payment Method</label>

                        <select class="form-control" id="payment_method" name="payment_method" required>

                            <option value="credit_card">Credit Card</option>

                            <option value="paypal">PayPal</option>

                            <option value="bank_transfer">Bank Transfer</option>

                        </select>

                    </div>

 

                    <!-- Place Order Button -->

                    <button type="submit" class="btn btn-success btn-lg">Place Order</button>

                </form>

            </div>

        </div>

    {% else %}

        <p>Your cart is empty. Please add items to your cart before proceeding with checkout.</p>

        <a href="{% url 'cart:view_cart' %}" class="btn btn-primary">Go to Cart</a>

    {% endif %}

</div>

{% endblock %}


Explanation of the checkout.html Template:

1.   Extending the Base Template:

{% extends 'base_generic.html' %}

o    This line indicates that checkout.html extends from a base template (base_generic.html), which likely contains common elements like navigation menus, headers, and footers.

2.   Block Content:

{% block content %}

...

{% endblock %}

o    This is where the content specific to the checkout page is placed.

3.   Cart Details Section:

<div class="col-md-8">

    <h3>Your Cart</h3>

    <table class="table table-bordered">

        <thead>

            <tr>

                <th>Product</th>

                <th>Price</th>

                <th>Quantity</th>

                <th>Total</th>

            </tr>

        </thead>

        <tbody>

            {% for item in cart_items %}

                <tr>

                    <td>{{ item.product.name }}</td>

                    <td>${{ item.product.price }}</td>

                    <td>{{ item.quantity }}</td>

                    <td>${{ item.product.price * item.quantity }}</td>

                </tr>

            {% endfor %}

        </tbody>

    </table>

    <h4>Total: ${{ total_price }}</h4>

</div>

o    This section displays the contents of the cart, including each product’s name, price, quantity, and total price for each product (price * quantity). The total price of all items in the cart is also displayed at the bottom.

4.   Shipping Information Section:

<div class="col-md-4">

    <h3>Shipping Information</h3>

    <form action="{% url 'cart:process_checkout' %}" method="post">

        {% csrf_token %}

        <!-- Address Fields -->

        <div class="form-group">

            <label for="address">Shipping Address</label>

            <input type="text" class="form-control" id="address" name="address" required>

        </div>

        <div class="form-group">

            <label for="city">City</label>

            <input type="text" class="form-control" id="city" name="city" required>

        </div>

        <div class="form-group">

            <label for="postal_code">Postal Code</label>

            <input type="text" class="form-control" id="postal_code" name="postal_code" required>

        </div>

        <div class="form-group">

            <label for="country">Country</label>

            <input type="text" class="form-control" id="country" name="country" required>

        </div>

        <!-- Payment Method Selection -->

        <div class="form-group">

            <label for="payment_method">Payment Method</label>

            <select class="form-control" id="payment_method" name="payment_method" required>

                <option value="credit_card">Credit Card</option>

                <option value="paypal">PayPal</option>

                <option value="bank_transfer">Bank Transfer</option>

            </select>

        </div>

        <!-- Submit Button -->

        <button type="submit" class="btn btn-success btn-lg">Place Order</button>

    </form>

</div>

o    This form allows the user to provide shipping details such as the shipping address, city, postal code, and country. The form also includes a dropdown to select a payment method, which could be Credit Card, PayPal, or Bank Transfer.

o    The form is submitted to the process_checkout view, which handles the checkout logic.

5.   Empty Cart Message:

<p>Your cart is empty. Please add items to your cart before proceeding with checkout.</p>

<a href="{% url 'cart:view_cart' %}" class="btn btn-primary">Go to Cart</a>

o    If the cart is empty (i.e., cart_items is not available), this message is shown to inform the user to add items to the cart before proceeding with the checkout.


How the Template Works:

1.   Cart Overview:

o    Displays all items currently in the shopping cart, including the name, price, quantity, and total price for each item. The overall total price of the cart is also displayed.

2.   Shipping Form:

o    Users can enter their shipping information, which includes their shipping address, city, postal code, and country. The form also allows the user to select their preferred payment method.

3.   Checkout Process:

o    After filling in the necessary shipping information and selecting a payment method, the user can place the order by submitting the form. The form will send the data to the process_checkout view, which will handle the actual purchase logic (e.g., payment processing, order creation, etc.).

4.   Empty Cart Handling:

o    If the user tries to access the checkout page without any items in the cart, they are informed that the cart is empty and are given a link to go back to the cart to add items.


Next Steps:

  • View Logic: The process_checkout view should handle the submission of the form, process the payment, and finalize the order.
  • Order Model: You may want to create an Order model to save the details of each completed order (shipping address, products, total price, etc.).

Conclusion:

The checkout.html template allows users to review their cart, provide shipping details, choose a payment method, and place their order. It integrates seamlessly with the backend to complete the purchase process and ensures that users can easily navigate through the checkout flow.

 The product_list.html template displays a list of available products that customers can view, select, and add to their shopping cart. It typically includes product images, names, prices, descriptions, and an option to add each product to the cart.


product_list.html

{% extends 'base_generic.html' %}

{% block content %}

<div class="container">

    <h2>Available Products</h2>

 

    <!-- Displaying products -->

    <div class="row">

        {% for product in products %}

            <div class="col-md-4">

                <div class="card mb-4">

                    <img src="{{ product.image.url }}" class="card-img-top" alt="{{ product.name }}">

                    <div class="card-body">

                        <h5 class="card-title">{{ product.name }}</h5>

                        <p class="card-text">{{ product.description|slice:":150" }}...</p>

                        <p class="card-text"><strong>${{ product.price }}</strong></p>

 

                        <!-- Add to Cart Form -->

                        <form action="{% url 'cart:add_to_cart' product.id %}" method="post">

                            {% csrf_token %}

                            <div class="form-group">

                                <label for="quantity">Quantity</label>

                                <input type="number" id="quantity" name="quantity" value="1" min="1" class="form-control" required>

                            </div>

                            <button type="submit" class="btn btn-primary">Add to Cart</button>

                        </form>

                    </div>

                </div>

            </div>

        {% empty %}

            <p>No products available at the moment. Please check back later.</p>

        {% endfor %}

    </div>

</div>

{% endblock %}


Explanation of the product_list.html Template:

1.   Extending the Base Template:

{% extends 'base_generic.html' %}

o    This line indicates that this template extends from a base template (base_generic.html), which likely contains common elements such as the header, footer, and navigation bar.

2.   Block Content:

{% block content %}

...

{% endblock %}

o    The content block is where the main content of the page is placed, specifically for displaying the list of products.

3.   Product List:

<div class="row">

    {% for product in products %}

        <div class="col-md-4">

            <div class="card mb-4">

                <img src="{{ product.image.url }}" class="card-img-top" alt="{{ product.name }}">

                <div class="card-body">

                    <h5 class="card-title">{{ product.name }}</h5>

                    <p class="card-text">{{ product.description|slice:":150" }}...</p>

                    <p class="card-text"><strong>${{ product.price }}</strong></p>

 

                    <form action="{% url 'cart:add_to_cart' product.id %}" method="post">

                        {% csrf_token %}

                        <div class="form-group">

                            <label for="quantity">Quantity</label>

                            <input type="number" id="quantity" name="quantity" value="1" min="1" class="form-control" required>

                        </div>

                        <button type="submit" class="btn btn-primary">Add to Cart</button>

                    </form>

                </div>

            </div>

        </div>

    {% empty %}

        <p>No products available at the moment. Please check back later.</p>

    {% endfor %}

</div>

o    Product Iteration:

§  This block iterates over a products context variable, which contains the list of products available in the database.

§  For each product, the template displays a card that contains an image, name, description (shortened to 150 characters), and price.

o    Product Image: The image for each product is displayed using {{ product.image.url }}. Ensure that the product model has an image field and is properly set up to handle images in Django.

o    Description: The product description is truncated to the first 150 characters using the slice filter to make the content look cleaner.

o    Add to Cart: Each product has an Add to Cart button with a form where the user can specify the quantity they want to purchase. The form sends a POST request to the add_to_cart view, which adds the product to the shopping cart. The csrf_token is included for security.

4.   Empty State:

{% empty %}

    <p>No products available at the moment. Please check back later.</p>

{% endfor %}

o    If no products are available in the products context, the template will display a message informing the user that there are no products at the moment.

5.   Bootstrap Grid Layout:

o    The col-md-4 class from Bootstrap is used to ensure that each product is displayed in a responsive grid layout with three products per row on medium and larger screens. You can adjust the number based on how many products you want per row by changing the col-md-4 class (e.g., col-md-6 for two per row).


How This Template Works:

  • The product list is dynamically generated by iterating through the products context variable, which is passed from the Django view to the template. Each product will have its details (image, name, description, and price) displayed inside a Bootstrap card for a clean and responsive layout.
  • Users can add a product to their shopping cart by entering the quantity they wish to purchase and clicking the Add to Cart button. This triggers a POST request to the add_to_cart view, which will process the addition of the product to the cart.
  • If there are no products available in the database, the user will be shown a message telling them that there are no products at the moment.

Possible Improvements and Extensions:

1.   Product Pagination:

o    If there are many products, it would be helpful to implement pagination to avoid showing too many products at once. Django’s Paginator can be used to paginate the products in the view and pass the paginated products to the template.

2.   Product Search and Filters:

o    You can add search functionality and filters (e.g., filter by category, price range, etc.) to allow users to find products more easily. This could involve adding a search form and handling the search logic in the view.

3.   Product Details Page:

o    Adding a "View Details" button or link for each product can lead to a separate page with more information about the product, including detailed descriptions, reviews, and more.

4.   Product Ratings and Reviews:

o    Displaying user ratings and reviews for each product can provide additional value to customers. This can be implemented by adding a rating system in the product model and showing the average rating in the template.


Conclusion:

The product_list.html template is a crucial part of the online shopping cart application, as it presents all available products to the user. It allows customers to explore, choose, and add products to their cart for further checkout. This template can be extended and enhanced with additional features like product search, filtering, pagination, and ratings to improve the user experience.

 The order_confirmation.html template is shown to the user after completing their purchase. It typically includes an order summary, confirmation message, order ID, and details of the purchased products, including quantity, price, and the total amount.


order_confirmation.html

{% extends 'base_generic.html' %}

{% block content %}

<div class="container">

    <h2>Order Confirmation</h2>

    <!-- Order Confirmation Message -->

    <div class="alert alert-success" role="alert">

        <h4 class="alert-heading">Thank you for your order!</h4>

        <p>Your order has been successfully placed. Below are the details of your order:</p>

    </div>

    <!-- Order Summary -->

    <h4>Order ID: {{ order.id }}</h4>

    <p><strong>Date:</strong> {{ order.created_at|date:"F j, Y" }}</p>

    <hr>

    <!-- Order Items Table -->

    <h5>Items in your order:</h5>

    <table class="table">

        <thead>

            <tr>

                <th>Product</th>

                <th>Quantity</th>

                <th>Price</th>

                <th>Total</th>

            </tr>

        </thead>

        <tbody>

            {% for item in order.items.all %}

                <tr>

                    <td>{{ item.product.name }}</td>

                    <td>{{ item.quantity }}</td>

                    <td>${{ item.product.price }}</td>

                    <td>${{ item.total_price }}</td>

                </tr>

            {% endfor %}

        </tbody>

    </table>

    <hr>

    <!-- Order Totals -->

    <h5>Order Total:</h5>

    <p><strong>Subtotal:</strong> ${{ order.subtotal }}</p>

    <p><strong>Tax:</strong> ${{ order.tax }}</p>

    <p><strong>Shipping:</strong> ${{ order.shipping_cost }}</p>

    <p><strong>Total Amount:</strong> ${{ order.total_amount }}</p>

 

    <hr>

    <!-- Shipping Information -->

    <h5>Shipping Information:</h5>

    <p><strong>Shipping Address:</strong> {{ order.shipping_address }}</p>

    <p><strong>Contact:</strong> {{ order.contact_number }}</p>

    <hr>

    <!-- Call to Action -->

    <div class="text-center">

        <a href="{% url 'cart:home' %}" class="btn btn-primary">Return to Shop</a>

        <a href="{% url 'cart:order_history' %}" class="btn btn-secondary">View Order History</a>

    </div>

</div>

{% endblock %}


Explanation of the order_confirmation.html Template:

1.   Extending the Base Template:

{% extends 'base_generic.html' %}

o    The template extends from base_generic.html, which would include the common structure for the website, like the header, footer, and navigation.

2.   Block Content:

{% block content %}

...

{% endblock %}

o    The content block is where the main content of the order confirmation page is inserted.

3.   Order Confirmation Message:

<div class="alert alert-success" role="alert">

    <h4 class="alert-heading">Thank you for your order!</h4>

    <p>Your order has been successfully placed. Below are the details of your order:</p>

</div>

o    This is a success message that congratulates the user on placing the order. It uses Bootstrap’s alert class to display a prominent, green-colored message.

4.   Order Summary:

<h4>Order ID: {{ order.id }}</h4>

<p><strong>Date:</strong> {{ order.created_at|date:"F j, Y" }}</p>

o    The order ID is displayed using {{ order.id }}, and the order creation date is formatted using Django’s date filter to make it user-friendly.

5.   Order Items Table:

<h5>Items in your order:</h5>

<table class="table">

    <thead>

        <tr>

            <th>Product</th>

            <th>Quantity</th>

            <th>Price</th>

            <th>Total</th>

        </tr>

    </thead>

    <tbody>

        {% for item in order.items.all %}

            <tr>

                <td>{{ item.product.name }}</td>

                <td>{{ item.quantity }}</td>

                <td>${{ item.product.price }}</td>

                <td>${{ item.total_price }}</td>

            </tr>

        {% endfor %}

    </tbody>

</table>

o    This section lists the products included in the order. It iterates over all items in the order and displays the product name, quantity, price, and total price for each product.

o    The order.items.all fetches all products associated with the current order, and their respective details are displayed in a table.

6.   Order Totals:

<h5>Order Total:</h5>

<p><strong>Subtotal:</strong> ${{ order.subtotal }}</p>

<p><strong>Tax:</strong> ${{ order.tax }}</p>

<p><strong>Shipping:</strong> ${{ order.shipping_cost }}</p>

<p><strong>Total Amount:</strong> ${{ order.total_amount }}</p>

o    These values show the breakdown of the order, including the subtotal, tax, shipping cost, and the total amount.

o    The order.subtotal, order.tax, order.shipping_cost, and order.total_amount represent the corresponding fields in the Order model (or whichever model you use to store order details).

7.   Shipping Information:

<h5>Shipping Information:</h5>

<p><strong>Shipping Address:</strong> {{ order.shipping_address }}</p>

<p><strong>Contact:</strong> {{ order.contact_number }}</p>

o    The shipping details such as the shipping address and contact number are displayed here.

8.   Call to Action (CTA) Buttons:

<div class="text-center">

    <a href="{% url 'cart:home' %}" class="btn btn-primary">Return to Shop</a>

    <a href="{% url 'cart:order_history' %}" class="btn btn-secondary">View Order History</a>

</div>

o    The user can return to the shop or view their order history with the buttons provided. The links are directed to specific views (e.g., cart:home for the homepage and cart:order_history for order history). These URLs need to be defined in your urls.py.


How This Template Works:

  • Dynamic Content Rendering: The order object is passed to the template, containing all the necessary details about the order, such as the ID, products, quantities, pricing, totals, and shipping information.
  • Order Details: The template shows a summary of the order with key details, including product names, quantities, and prices. This helps the customer review the items they purchased and confirms that everything is correct.
  • Confirmation: The user sees a success message to confirm that the order was placed successfully, along with the unique order ID and date.
  • Actionable Options: After seeing the confirmation, the user can either return to shopping or view their order history for past orders.

Possible Improvements and Extensions:

1.   Order Status Tracking:

o    You could include order status information (e.g., "Processing", "Shipped", "Delivered") in the confirmation page, so users know the current status of their order.

2.   Order Summary Email:

o    You can send an order confirmation email to the user with all the details displayed on this page. This could be implemented using Django’s email functionality.

3.   Payment Information:

o    If the order is part of a payment flow, you might want to include payment information (e.g., "Payment Successful" message) on the confirmation page.

4.   Review Options:

o    After receiving the order, users could be encouraged to leave reviews or feedback about the products they purchased.


Conclusion:

The order_confirmation.html template is essential for providing users with an overview of their completed purchase, confirming their order, and offering useful next steps (e.g., returning to the shop or viewing order history). It enhances the user experience by making the shopping process transparent and allowing users to verify the details of their transaction.

online_shopping_cart/static/css/styles.css  directory.

This CSS file includes styles for the layout, buttons, navigation bar, product listings, cart details, and other common elements in the project.

/* styles.css */

 

/* General Reset */

body, h1, h2, h3, h4, h5, h6, p, ul, ol, figure, blockquote {

    margin: 0;

    padding: 0;

    box-sizing: border-box;

}

 

body {

    font-family: Arial, sans-serif;

    line-height: 1.6;

    color: #333;

    background-color: #f9f9f9;

    margin: 0;

    padding: 0;

}

 

/* Container */

.container {

    width: 90%;

    max-width: 1200px;

    margin: 0 auto;

}

 

/* Header Styles */

header {

    background-color: #007bff;

    color: white;

    padding: 1rem 0;

}

 

header .logo {

    font-size: 1.5rem;

    font-weight: bold;

    text-align: center;

}

 

header nav {

    margin-top: 1rem;

    text-align: center;

}

 

header nav ul {

    list-style: none;

    padding: 0;

}

 

header nav ul li {

    display: inline;

    margin: 0 15px;

}

 

header nav ul li a {

    color: white;

    text-decoration: none;

    font-size: 1rem;

    transition: color 0.3s;

}

 

header nav ul li a:hover {

    color: #ffd700;

}

 

/* Footer Styles */

footer {

    background-color: #333;

    color: white;

    text-align: center;

    padding: 1rem 0;

    margin-top: 2rem;

}

 

footer p {

    margin: 0;

}

 

/* Buttons */

button, .btn {

    display: inline-block;

    padding: 0.5rem 1rem;

    font-size: 1rem;

    border: none;

    border-radius: 5px;

    cursor: pointer;

    transition: background-color 0.3s, color 0.3s;

}

 

.btn-primary {

    background-color: #007bff;

    color: white;

}

 

.btn-primary:hover {

    background-color: #0056b3;

}

 

.btn-secondary {

    background-color: #6c757d;

    color: white;

}

 

.btn-secondary:hover {

    background-color: #5a6268;

}

 

/* Product List */

.products {

    display: flex;

    flex-wrap: wrap;

    gap: 2rem;

    margin-top: 2rem;

}

 

.product {

    background: white;

    border: 1px solid #ddd;

    border-radius: 8px;

    padding: 1rem;

    text-align: center;

    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);

    transition: box-shadow 0.3s;

    flex: 1 1 calc(25% - 2rem);

}

 

.product:hover {

    box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);

}

 

.product img {

    width: 100%;

    height: auto;

    border-radius: 5px;

    margin-bottom: 1rem;

}

 

.product h3 {

    font-size: 1.2rem;

    margin-bottom: 0.5rem;

}

 

.product p {

    font-size: 1rem;

    color: #555;

}

 

.product .price {

    font-size: 1.1rem;

    font-weight: bold;

    color: #007bff;

    margin-top: 0.5rem;

}

 

/* Cart Styles */

.cart {

    margin-top: 2rem;

}

 

.cart table {

    width: 100%;

    border-collapse: collapse;

    margin-top: 1rem;

}

 

.cart table th, .cart table td {

    border: 1px solid #ddd;

    padding: 0.8rem;

    text-align: left;

}

 

.cart table th {

    background-color: #007bff;

    color: white;

}

 

.cart table td {

    color: #555;

}

 

.cart .total {

    text-align: right;

    font-size: 1.2rem;

    font-weight: bold;

    margin-top: 1rem;

}

 

/* Forms */

form {

    margin-top: 2rem;

    padding: 1rem;

    background-color: white;

    border: 1px solid #ddd;

    border-radius: 5px;

}

 

form label {

    display: block;

    margin-bottom: 0.5rem;

    font-weight: bold;

}

 

form input, form select, form textarea {

    width: 100%;

    padding: 0.8rem;

    margin-bottom: 1rem;

    border: 1px solid #ddd;

    border-radius: 5px;

    font-size: 1rem;

}

 

form button {

    width: 100%;

}

 

/* Utility Classes */

.text-center {

    text-align: center;

}

 

.text-right {

    text-align: right;

}

 

.mt-1 {

    margin-top: 1rem;

}

 

.mt-2 {

    margin-top: 2rem;

}

 

.mb-1 {

    margin-bottom: 1rem;

}

 

.mb-2 {

    margin-bottom: 2rem;

}

 

online_shopping_cart/static/js/cart.js

This JavaScript file includes functions for adding items to the cart, updating the quantity of items, removing items from the cart, and calculating the total cost dynamically.

// cart.js

 

// Object to store cart items and their quantities

let cart = {};

 

// Utility function to update the cart display

function updateCartDisplay() {

    const cartTableBody = document.querySelector("#cart-items");

    const cartTotal = document.querySelector("#cart-total");

    cartTableBody.innerHTML = ""; // Clear current cart items

    let total = 0;

 

    for (let productId in cart) {

        const item = cart[productId];

        const row = document.createElement("tr");

 

        // Create table row for each item

        row.innerHTML = `

            <td>${item.name}</td>

            <td>${item.price.toFixed(2)}</td>

            <td>

                <input type="number" value="${item.quantity}" min="1" class="quantity-input" data-id="${productId}" />

            </td>

            <td>${(item.price * item.quantity).toFixed(2)}</td>

            <td><button class="remove-btn" data-id="${productId}">Remove</button></td>

        `;

 

        cartTableBody.appendChild(row);

        total += item.price * item.quantity;

    }

 

    cartTotal.textContent = total.toFixed(2); // Update total amount

    attachEventListeners();

}

 

// Add item to cart

function addToCart(productId, name, price) {

    if (cart[productId]) {

        // If item already in cart, increase quantity

        cart[productId].quantity += 1;

    } else {

        // Otherwise, add new item

        cart[productId] = {

            name: name,

            price: price,

            quantity: 1,

        };

    }

    updateCartDisplay();

}

 

// Remove item from cart

function removeFromCart(productId) {

    delete cart[productId];

    updateCartDisplay();

}

 

// Update item quantity

function updateItemQuantity(productId, quantity) {

    if (cart[productId] && quantity > 0) {

        cart[productId].quantity = quantity;

    } else if (quantity <= 0) {

        removeFromCart(productId);

    }

    updateCartDisplay();

}

 

// Attach event listeners to dynamically created elements

function attachEventListeners() {

    // Handle quantity change

    document.querySelectorAll(".quantity-input").forEach(input => {

        input.addEventListener("change", event => {

            const productId = event.target.dataset.id;

            const quantity = parseInt(event.target.value);

            updateItemQuantity(productId, quantity);

        });

    });

 

    // Handle item removal

    document.querySelectorAll(".remove-btn").forEach(button => {

        button.addEventListener("click", event => {

            const productId = event.target.dataset.id;

            removeFromCart(productId);

        });

    });

}

 

// Example: Add to cart buttons (should be dynamically attached to product elements)

document.querySelectorAll(".add-to-cart-btn").forEach(button => {

    button.addEventListener("click", event => {

        const productId = event.target.dataset.id;

        const name = event.target.dataset.name;

        const price = parseFloat(event.target.dataset.price);

        addToCart(productId, name, price);

    });

});

 

// Initialize cart display on page load

document.addEventListener("DOMContentLoaded", () => {

    updateCartDisplay();

});

 

 Explanation:

1.   Cart Storage:

o    The cart object stores items in the format { productId: { name, price, quantity } }.

2.   addToCart Function:

o    Adds an item to the cart or increases its quantity if it already exists.

3.   removeFromCart Function:

o    Removes an item from the cart.

4.   updateItemQuantity Function:

o    Updates the quantity of an item or removes it if the quantity is set to 0.

5.   updateCartDisplay Function:

o    Dynamically updates the cart table in the UI, showing the product name, price, quantity, and total cost for each item.

o    Also updates the total cart value.

6.   Event Listeners:

o    Dynamically attach listeners to "Add to Cart," "Remove," and quantity input fields.

o    Updates cart when items are added, removed, or quantities are modified.

7.   Integration:

o    Ensure buttons for "Add to Cart" have data-id, data-name, and data-price attributes in the HTML for this JavaScript to work.

Example Integration in HTML:

<button class="add-to-cart-btn" data-id="1" data-name="Product A" data-price="50.00">Add to Cart</button>

<button class="add-to-cart-btn" data-id="2" data-name="Product B" data-price="30.00">Add to Cart</button>

<table id="cart-table">

    <thead>

        <tr>

            <th>Product</th>

            <th>Price</th>

            <th>Quantity</th>

            <th>Total</th>

            <th>Action</th>

        </tr>

    </thead>

    <tbody id="cart-items"></tbody>

</table>

<div>Total: $<span id="cart-total">0.00</span></div>

This script provides a dynamic and interactive shopping cart experience for your online shopping project.

online_shopping_cart/static/__init__.py

The __init__.py file is typically used to indicate that the directory it resides in should be treated as a Python package. For the static directory in a Django project, a __init__.py file is not required or necessary because static files are not Python modules or packages—they are assets like CSS, JavaScript, and images.

If you attempt to add a __init__.py file to the static directory, it will not serve any meaningful purpose because Django does not process static files as Python code.

However, if you wish to include one for organizational purposes, you might add a comment explaining why the file exists, though it won't impact the functionality of your project. Here's an example of what it might look like:

online_shopping_cart/static/__init__.py

"""

This file is intentionally left blank.

 Purpose:

- The `__init__.py` file marks this directory as a Python package.

- However, the `static` directory in a Django project is primarily used for serving static assets (CSS, JS, images) and does not require Python package functionality.

Note:

- This file can be safely removed or ignored as it has no functional impact on the project.

"""

 

 Key Points:

  • Not Necessary: The static directory doesn't need to be treated as a Python package.
  • No Impact: Including this file won't affect the project behavior.
  • Django-Specific Behavior: Django handles static files separately using its STATICFILES_DIRS and collectstatic features, unrelated to Python packaging.

Recommendation:

Remove or skip adding __init__.py in the static directory unless you have a specific reason or your project setup dictates otherwise.

online_shopping_cart/products/__init__.py

In a Django project, the __init__.py file within the products app marks the directory as a Python package. While it typically remains empty, you can use it to define shared logic or import frequently used components to simplify imports across your app.

Here’s an example of what the __init__.py file in the products app could look like for your online shopping cart project:

online_shopping_cart/products/__init__.py

"""

Initialization file for the 'products' app in the online shopping cart project.

 

This file marks the 'products' directory as a Python package and allows for app-wide constants,

utility functions, or shared imports to be defined here.

 

Purpose:

- Simplify imports across the app by centralizing common imports or configurations.

- Serve as a starting point for app-specific initializations if needed.

Usage:

- Import shared constants, utilities, or models directly from 'products' without needing

  to specify the full module path.

Example:

  from products import Product, Category

"""

 

# Import commonly used models or utilities to simplify imports

from .models import Product, Category

# Define app-wide constants (if necessary)

PRODUCT_STATUS_ACTIVE = "active"

PRODUCT_STATUS_INACTIVE = "inactive"

PRODUCT_STATUSES = [PRODUCT_STATUS_ACTIVE, PRODUCT_STATUS_INACTIVE]

# Add shared utility functions or initializations

def get_active_products():

    """Returns a queryset of active products."""

    return Product.objects.filter(status=PRODUCT_STATUS_ACTIVE)

 

 

                                                                                                                                                                  Explanation:

1.   Import Common Components:

o    Import frequently used models or utilities (e.g., Product, Category) to simplify imports in other modules of your project.

o    For example, instead of from products.models import Product, you can use from products import Product.

2.   Define App-Wide Constants:

o    Define constants that are shared across the app (e.g., status values for products).

3.   Shared Functions:

o    Include utility functions that are commonly used in your app (e.g., get_active_products).

4.   Documentation:

o    Add a docstring explaining the purpose and usage of the __init__.py file.

Example Usage:

In other parts of your products app or project, you can now simplify imports like this:

# Simplified imports

from products import Product, get_active_products, PRODUCT_STATUS_ACTIVE

# Use imported components

active_products = get_active_products()

print(f"Number of active products: {active_products.count()}")

online_shopping_cart/products/admin.py

The admin.py file in Django is used to define how the models in your app will appear in the Django Admin interface. For the products app in your online shopping cart project, you can customize it to manage the product-related data effectively.

Here’s an example of a detailed admin.py for the products app:


online_shopping_cart/products/admin.py

from django.contrib import admin

from .models import Product, Category

 

@admin.register(Category)

class CategoryAdmin(admin.ModelAdmin):

    """

    Admin interface for managing product categories.

    """

    list_display = ('name', 'created_at', 'updated_at')  # Columns to display in the admin list view

    search_fields = ('name',)  # Search bar for filtering by name

    list_filter = ('created_at', 'updated_at')  # Filters by creation and update timestamps

    ordering = ('name',)  # Default ordering of categories by name

 

@admin.register(Product)

class ProductAdmin(admin.ModelAdmin):

    """

    Admin interface for managing products.

    """

    list_display = ('name', 'category', 'price', 'stock', 'status', 'created_at')  # Displayed columns

    list_filter = ('category', 'status', 'created_at', 'updated_at')  # Sidebar filters

    search_fields = ('name', 'description')  # Search fields for product name and description

    ordering = ('name',)  # Default ordering by name

    prepopulated_fields = {'slug': ('name',)}  # Auto-generate slug from name

    list_editable = ('price', 'stock', 'status')  # Allow inline editing of these fields

    date_hierarchy = 'created_at'  # Adds a date-based navigation by creation date

    fieldsets = (

        (None, {  # General fields

            'fields': ('name', 'slug', 'category', 'description', 'image')

        }),

        ('Pricing and Inventory', {  # Grouped fields for pricing and stock

            'fields': ('price', 'stock', 'status')

        }),

        ('Timestamps', {  # Timestamps for admin display (read-only)

            'fields': ('created_at', 'updated_at'),

            'classes': ('collapse',),

        }),

    )

    readonly_fields = ('created_at', 'updated_at')  # Prevent changes to these fields

 


 

                                                                                                                                                                  

Explanation:

1.   Category Admin:

o    list_display: Specifies which fields appear in the admin list view for categories.

o    search_fields: Allows searching categories by name.

o    list_filter: Adds filtering options for creation and update timestamps.

o    ordering: Orders categories by their name.

2.   Product Admin:

o    list_display: Defines columns to show for products in the list view.

o    list_filter: Adds filters for category, status, and timestamps.

o    search_fields: Enables search functionality for products based on name and description.

o    ordering: Orders products by name.

o    prepopulated_fields: Automatically fills the slug field based on the product name.

o    list_editable: Allows editing specific fields directly in the list view.

o    date_hierarchy: Adds date-based navigation for creation date.

o    fieldsets: Groups fields into logical sections for better UI organization.

o    readonly_fields: Prevents editing of created_at and updated_at fields.

Example in Admin Panel:

Category Admin:

  • List View: Displays the category name and timestamps with search and filter options.

Product Admin:

  • List View: Shows product name, category, price, stock, and status with inline editing.
  • Detail View: Organizes fields into sections for better clarity, such as general details, pricing, and timestamps.

Benefits:

  • Customizing the admin interface enhances usability for managing products and categories.
  • Inline editing (list_editable) saves time for frequent updates like stock and price.
  • Grouping fields into sections improves the user experience for administrators.

This approach ensures your admin.py file is optimized for managing the products app efficiently. 

online_shopping_cart/products/apps.py

The apps.py file in Django is used to configure the app within the project. For the products app in your online shopping cart project, this file can include metadata about the app and additional configuration.

online_shopping_cart/products/apps.py

from django.apps import AppConfig

 class ProductsConfig(AppConfig):

    """

    Configuration class for the 'products' app in the online shopping cart project.

    """

    default_auto_field = 'django.db.models.BigAutoField'  # Default primary key field type

    name = 'products'  # Name of the app

    verbose_name = 'Product Management'  # Human-readable name for the admin panel

    def ready(self):

        """

        This method is called when the app is ready for use.

        Use it to include app-specific signals or other initialization logic.

        """

        import products.signals  # Import signals for the products app


 

 

                                                                                                                                                                  Explanation:

1.   default_auto_field:

o    Sets the default field type for primary keys. The BigAutoField is typically used for scalability in production databases.

2.   name:

o    Specifies the Python path for the app. In this case, it’s simply 'products' since it is directly in the project directory.

3.   verbose_name:

o    Provides a human-readable name for the app that appears in the Django admin interface. For example, instead of showing "products," it will display "Product Management."

4.   ready Method:

o    Called when the app is loaded and ready for use.

o    Commonly used to import and initialize signals for the app.

o    In this example, it imports products.signals to handle any custom signal logic (e.g., sending notifications when a new product is added or stock is updated).


Benefits:

  • Human-Readable Names: Using verbose_name improves clarity for admin users by providing a descriptive label for the app.
  • Signals Integration: The ready method ensures that app-specific signals are properly initialized when the app is loaded.

Example Signals (Optional):

If you want to add signals for actions like notifying when a new product is created, you can define them in products/signals.py. Here’s a simple example:

online_shopping_cart/products/signals.py:

from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import Product 
@receiver(post_save, sender=Product)
def notify_admin_on_product_creation(sender, instance, created, **kwargs):
    if created:
        print(f"New product added: {instance.name}")

 

 

 

                                                                                                                                                                  Final
Notes:

This configuration ensures that your products app is well-integrated within the online_shopping_cart project and ready for additional customization as needed.

online_shopping_cart/products/models.py

In Django, the models.py file within the products app contains the database models that define the structure of the data for the application. Below is a detailed example of how you can structure models.py for the products app in your online shopping cart project.

online_shopping_cart/products/models.py

from django.db import models

from django.utils.text import slugify

from django.utils.translation import gettext_lazy as _

 class Category(models.Model):

    """

    Represents a category for products.

    """

    name = models.CharField(max_length=255, unique=True, verbose_name=_("Category Name"))

    slug = models.SlugField(max_length=255, unique=True, editable=False, verbose_name=_("Slug"))

     class Meta:

        verbose_name = _("Category")

        verbose_name_plural = _("Categories")

        ordering = ["name"]

 

    def save(self, *args, **kwargs):

        # Automatically generate slug from the category name

        if not self.slug:

            self.slug = slugify(self.name)

        super().save(*args, **kwargs)

 

    def __str__(self):

        return self.name

 

 

class Product(models.Model):

    """

    Represents a product in the shopping cart.

    """

    name = models.CharField(max_length=255, verbose_name=_("Product Name"))

    slug = models.SlugField(max_length=255, unique=True, editable=False, verbose_name=_("Slug"))

    description = models.TextField(blank=True, null=True, verbose_name=_("Description"))

    category = models.ForeignKey(

        Category,

        on_delete=models.CASCADE,

        related_name="products",

        verbose_name=_("Category")

    )

    price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name=_("Price"))

    stock = models.PositiveIntegerField(default=0, verbose_name=_("Stock"))

    created_at = models.DateTimeField(auto_now_add=True, verbose_name=_("Created At"))

    updated_at = models.DateTimeField(auto_now=True, verbose_name=_("Updated At"))

    image = models.ImageField(upload_to='products/', blank=True, null=True, verbose_name=_("Product Image"))

 

    class Meta:

        verbose_name = _("Product")

        verbose_name_plural = _("Products")

        ordering = ["-created_at"]

 

    def save(self, *args, **kwargs):

        # Automatically generate slug from the product name

        if not self.slug:

            self.slug = slugify(self.name)

        super().save(*args, **kwargs)

 

    def __str__(self):

        return self.name

 

 

class Review(models.Model):

    """

    Represents a review for a product.

    """

    product = models.ForeignKey(

        Product,

        on_delete=models.CASCADE,

        related_name="reviews",

        verbose_name=_("Product")

    )

    user = models.CharField(max_length=255, verbose_name=_("User Name"))

    rating = models.PositiveIntegerField(

        choices=[(i, i) for i in range(1, 6)],  # Rating from 1 to 5

        verbose_name=_("Rating")

    )

    comment = models.TextField(blank=True, null=True, verbose_name=_("Comment"))

    created_at = models.DateTimeField(auto_now_add=True, verbose_name=_("Created At"))

 

    class Meta:

        verbose_name = _("Review")

        verbose_name_plural = _("Reviews")

        ordering = ["-created_at"]

 

    def __str__(self):

        return f"Review for {self.product.name} by {self.user}"


 

                                                                                                                                                                  Explanation:

1.   Category Model:

o    Defines categories for products.

o    Includes a slug field that is auto-generated from the name for SEO-friendly URLs.

2.   Product Model:

o    Represents individual products.

o    Includes fields for name, description, price, stock, and image.

o    The category field establishes a foreign key relationship with the Category model, allowing products to be grouped by category.

o    A slug field is auto-generated from the name for use in URLs.

3.   Review Model:

o    Represents user reviews for products.

o    Includes a rating system (1 to 5 stars), a comment, and metadata about when the review was created.

4.   Automatic Slug Generation:

o    Both Category and Product models automatically generate slugs from their respective names.

5.   Meta Options:

o    verbose_name and verbose_name_plural provide human-readable names in the admin interface.

o    ordering specifies the default order for querysets.

6.   Image Handling:

o    The image field in the Product model allows for uploading product images to the media/products/ directory.


Additional Notes:

  • You need to have Pillow installed to handle image fields. Install it using:

pip install pillow

  • To use translations (gettext_lazy), you need to configure your project for internationalization.

This setup provides a robust structure for managing categories, products, and reviews in your online shopping cart application.

online_shopping_cart/products/views.py

In Django, the views.py file is used to define the logic that handles requests and responses for your application. Below is a detailed example of how you can implement the views.py for the products app in your online shopping cart project.


online_shopping_cart/products/views.py

from django.shortcuts import render, get_object_or_404

from django.http import JsonResponse

from django.core.paginator import Paginator

from django.db.models import Q

from .models import Product, Category, Review

 

 

def product_list(request):

    """

    Displays a list of all products with optional filtering by category or search query.

    """

    category_slug = request.GET.get('category', None)

    search_query = request.GET.get('search', None)

    products = Product.objects.all()

 

    # Filter by category if provided

    if category_slug:

        products = products.filter(category__slug=category_slug)

 

    # Filter by search query if provided

    if search_query:

        products = products.filter(

            Q(name__icontains=search_query) | Q(description__icontains=search_query)

        )

 

    # Pagination

    paginator = Paginator(products, 10)  # 10 products per page

    page_number = request.GET.get('page')

    page_obj = paginator.get_page(page_number)

 

    context = {

        'products': page_obj,

        'categories': Category.objects.all(),

    }

    return render(request, 'products/product_list.html', context)

 

 

def product_detail(request, slug):

    """

    Displays detailed information about a single product.

    """

    product = get_object_or_404(Product, slug=slug)

    reviews = product.reviews.all()

 

    context = {

        'product': product,

        'reviews': reviews,

    }

    return render(request, 'products/product_detail.html', context)

 

 

def add_review(request, slug):

    """

    Allows users to submit a review for a product.

    """

    product = get_object_or_404(Product, slug=slug)

 

    if request.method == "POST":

        user = request.POST.get('user')

        rating = int(request.POST.get('rating', 0))

        comment = request.POST.get('comment', '')

 

        # Validate input

        if rating < 1 or rating > 5:

            return JsonResponse({'error': 'Invalid rating value'}, status=400)

 

        # Save review

        review = Review.objects.create(

            product=product,

            user=user,

            rating=rating,

            comment=comment,

        )

        return JsonResponse({'message': 'Review added successfully'}, status=201)

 

    return JsonResponse({'error': 'Invalid request method'}, status=405)

 

 

def category_list(request):

    """

    Displays a list of all product categories.

    """

    categories = Category.objects.all()

    context = {'categories': categories}

    return render(request, 'products/category_list.html', context)


 

 

                                                                                                                                                                  Explanation:

1.   product_list View:

o    Retrieves and displays a paginated list of products.

o    Filters products based on the selected category (category_slug) or a search query (search_query).

o    Uses pagination to limit the number of products displayed on each page.

2.   product_detail View:

o    Retrieves and displays details for a specific product using its slug.

o    Includes related reviews for the product.

3.   add_review View:

o    Handles the submission of a review for a product.

o    Accepts POST requests with user, rating, and comment data.

o    Validates the rating to ensure it is between 1 and 5.

o    Saves the review to the database and returns a JSON response.

4.   category_list View:

o    Retrieves and displays a list of all product categories.


Templates:

To render the views, you will need corresponding HTML templates in the products/templates/products/ directory:

  • product_list.html: For listing products.
  • product_detail.html: For displaying product details.
  • category_list.html: For listing categories.

Example Template Snippets:

product_list.html

{% for product in products %}
    <div>
        <h2><a href="{% url 'product_detail' product.slug %}">{{ product.name }}</a></h2>
        <p>{{ product.description }}</p>
        <p>Price: ${{ product.price }}</p>
    </div>
{% endfor %}

 

                                                                                                                                                                  

product_detail.html

<h1>{{ product.name }}</h1>

<p>{{ product.description }}</p>

<p>Price: ${{ product.price }}</p>

<h3>Reviews:</h3>

{% for review in reviews %}

    <div>

        <strong>{{ review.user }}</strong>

        <p>Rating: {{ review.rating }}</p>

        <p>{{ review.comment }}</p>

    </div>

{% empty %}

    <p>No reviews yet.</p>

{% endfor %}


 

                                                                                                                                                                  

online_shopping_cart/products/urls.py:

URL Configuration:

Define URLs for these views in online_shopping_cart/products/urls.py:

from django.urls import path
from . import views
 
urlpatterns = [
    path('', views.product_list, name='product_list'),
    path('category/', views.category_list, name='category_list'),
    path('<slug:slug>/', views.product_detail, name='product_detail'),
    path('<slug:slug>/add-review/', views.add_review, name='add_review'),
]

 

 

                                                                                                                                                                  This
setup ensures your views.py is complete and functional for
managing products and categories in the online shopping cart.

In a Django project, the urls.py file maps URL patterns to specific views in your application. Below is a detailed implementation for the urls.py file in the products app of your online shopping cart project.


online_shopping_cart/products/urls.py

from django.urls import path

from . import views

 

urlpatterns = [

    # URL for the product list and search functionality

    path('', views.product_list, name='product_list'),

 

    # URL for listing all categories

    path('categories/', views.category_list, name='category_list'),

 

    # URL for detailed product view

    path('<slug:slug>/', views.product_detail, name='product_detail'),

 

    # URL for adding a review to a specific product

    path('<slug:slug>/add-review/', views.add_review, name='add_review'),

]


 

 

                                                                                                                                                                  

Explanation of Each URL Pattern:

1.   path('', views.product_list, name='product_list'):

o    Maps the base URL of the products app to the product_list view.

o    This view displays a paginated list of all products and handles search or category filtering.

2.   path('categories/', views.category_list, name='category_list'):

o    Maps the URL categories/ to the category_list view.

o    This view displays a list of all product categories.

3.   path('<slug:slug>/', views.product_detail, name='product_detail'):

o    Maps a dynamic URL pattern with a slug parameter (e.g., /product-name/) to the product_detail view.

o    This view displays detailed information about a specific product identified by its slug.

4.   path('<slug:slug>/add-review/', views.add_review, name='add_review'):

o    Maps the URL pattern <slug:slug>/add-review/ to the add_review view.

o    This view allows users to submit a review for a specific product.


Registering the URLs in the Project's urls.py

To ensure these URLs are accessible, include them in your project-level urls.py file (online_shopping_cart/urls.py) like this:

from django.contrib import admin
from django.urls import path, include
 
urlpatterns = [
    path('admin/', admin.site.urls),
    path('products/', include('products.urls')),  # Include the products app URLs
]

Testing the URLs

Example URLs:

  • /products/ → Displays the list of all products.
  • /products/categories/ → Displays the list of all categories.
  • /products/product-name/ → Displays detailed information about the product with the slug product-name.
  • /products/product-name/add-review/ → Allows users to add a review for the product with the slug product-name.

Steps to Test:

1.   Start the Django development server using python manage.py runserver.

2.   Navigate to the above URLs in your browser.

3.   Verify that the corresponding views and templates render correctly.

This urls.py file ensures proper routing for the products app in your online shopping cart project.

online_shopping_cart/products/templates/products/product_detail.html

This template will display detailed information about a specific product, including product details, price, description, and an option for users to add the product to their cart.

{% extends "base.html" %}

 

{% block content %}

    <div class="container mt-5">

        <div class="row">

            <div class="col-md-6">

                <!-- Product Image -->

                <img src="{{ product.image.url }}" alt="{{ product.name }}" class="img-fluid">

            </div>

            <div class="col-md-6">

                <h2>{{ product.name }}</h2>

                <p><strong>Price:</strong> ${{ product.price }}</p>

                <p><strong>Description:</strong> {{ product.description }}</p>

 

                <!-- Category and Tags -->

                <p><strong>Category:</strong> {{ product.category.name }}</p>

 

                <!-- Add to Cart Button -->

                <form action="{% url 'cart:add_to_cart' product.id %}" method="POST">

                    {% csrf_token %}

                    <div class="form-group">

                        <label for="quantity">Quantity:</label>

                        <input type="number" id="quantity" name="quantity" class="form-control" value="1" min="1">

                    </div>

                    <button type="submit" class="btn btn-primary mt-3">Add to Cart</button>

                </form>

 

                <!-- Product Review Section -->

                <div class="mt-4">

                    <h4>Reviews</h4>

                    <ul class="list-unstyled">

                        {% for review in product.reviews.all %}

                            <li class="media">

                                <div class="media-body">

                                    <h5 class="mt-0 mb-1">{{ review.user.username }}</h5>

                                    <p>{{ review.comment }}</p>

                                    <small class="text-muted">Rating: {{ review.rating }} stars</small>

                                </div>

                            </li>

                        {% empty %}

                            <p>No reviews yet. Be the first to review this product!</p>

                        {% endfor %}

                    </ul>

                   

                    <!-- Review Form -->

                    <h5>Leave a Review</h5>

                    <form action="{% url 'products:add_review' product.slug %}" method="POST">

                        {% csrf_token %}

                        <div class="form-group">

                            <label for="rating">Rating (1-5 stars):</label>

                            <input type="number" id="rating" name="rating" class="form-control" min="1" max="5" required>

                        </div>

                        <div class="form-group">

                            <label for="comment">Comment:</label>

                            <textarea id="comment" name="comment" class="form-control" rows="4" required></textarea>

                        </div>

                        <button type="submit" class="btn btn-success mt-3">Submit Review</button>

                    </form>

                </div>

            </div>

        </div>

    </div>

{% endblock %}


 

 

 

                                                                                                                                                                  Explanation of the Template

1.   Extending the Base Template (base.html):

o    {% extends "base.html" %}: This line ensures that this product detail page uses the layout defined in base.html. The content of base.html will be displayed, and the product_detail.html content will be inserted where the {% block content %} tag is located.

2.   Product Image:

o    The product's image is displayed using the URL stored in the product.image.url field. It uses the img-fluid class from Bootstrap to make the image responsive.

3.   Product Information:

o    The product name, price, and description are displayed in a structured way. The product object contains these attributes (name, price, and description), and they are rendered dynamically.

4.   Category:

o    The category.name field is used to display the category of the product. This assumes that the product model has a category ForeignKey relationship to the Category model.

5.   Add to Cart Form:

o    The form allows users to select the quantity and add the product to the cart.

o    The action of the form is directed to the URL for adding a product to the cart, passing the product ID. This URL is defined in urls.py for the cart app.

o    {% csrf_token %} is included to protect against Cross-Site Request Forgery (CSRF) attacks.

o    The user can adjust the quantity of the product they wish to add to their cart.

6.   Product Reviews:

o    This section loops over all the reviews of the current product (product.reviews.all). Each review is displayed with the reviewer's username, their comment, and the rating they gave.

o    If no reviews exist, a message encourages users to be the first to leave a review.

7.   Leave a Review Form:

o    A form is provided for users to submit their reviews. They can rate the product between 1 and 5 stars and provide a comment.

o    The form sends a POST request to the add_review view, which will handle saving the review.


Product Model Assumptions

This template assumes that your Product model is structured in a way that supports product details, including a category field, image field, and reviews. 

Below is an example of how your Product model might look:

from django.db import models

 

class Category(models.Model):

    name = models.CharField(max_length=255)

   

    def __str__(self):

        return self.name

 

class Product(models.Model):

    name = models.CharField(max_length=255)

    description = models.TextField()

    price = models.DecimalField(max_digits=10, decimal_places=2)

    image = models.ImageField(upload_to='products/')

    category = models.ForeignKey(Category, related_name='products', on_delete=models.CASCADE)

    slug = models.SlugField(unique=True)

 

    def __str__(self):

        return self.name

 

class Review(models.Model):

    product = models.ForeignKey(Product, related_name='reviews', on_delete=models.CASCADE)

    user = models.ForeignKey(User, on_delete=models.CASCADE)

    rating = models.PositiveIntegerField(default=5)

    comment = models.TextField()

    created_at = models.DateTimeField(auto_now_add=True)

 

    def __str__(self):

        return f'Review for {self.product.name} by {self.user.username}'


 

                                                                                                                                                                  Important Notes:

  • Images: Ensure your MEDIA_URL and MEDIA_ROOT settings are correctly configured in settings.py to serve product images.
  • Form Handling: The add_to_cart and add_review forms are set to send POST requests, so ensure these views exist and handle the logic for adding items to the cart and submitting reviews.
  • Static and Media Files: Don't forget to configure Django to serve media files correctly, especially if you're using product images.

This product_detail.html template provides a comprehensive and user-friendly page for viewing a product, reviewing it, and adding it to the shopping cart.

 online_shopping_cart/products/templates/products/product_detail.html

Below is a detailed implementation of the product_detail.html template for your online shopping cart project. This template will display detailed information about a specific product, including product details, price, description, and an option for users to add the product to their cart.

{% extends "base.html" %}

 

{% block content %}

    <div class="container mt-5">

        <div class="row">

            <div class="col-md-6">

                <!-- Product Image -->

                <img src="{{ product.image.url }}" alt="{{ product.name }}" class="img-fluid">

            </div>

            <div class="col-md-6">

                <h2>{{ product.name }}</h2>

                <p><strong>Price:</strong> ${{ product.price }}</p>

                <p><strong>Description:</strong> {{ product.description }}</p>

 

                <!-- Category and Tags -->

                <p><strong>Category:</strong> {{ product.category.name }}</p>

 

                <!-- Add to Cart Button -->

                <form action="{% url 'cart:add_to_cart' product.id %}" method="POST">

                    {% csrf_token %}

                    <div class="form-group">

                        <label for="quantity">Quantity:</label>

                        <input type="number" id="quantity" name="quantity" class="form-control" value="1" min="1">

                    </div>

                    <button type="submit" class="btn btn-primary mt-3">Add to Cart</button>

                </form>

 

                <!-- Product Review Section -->

                <div class="mt-4">

                    <h4>Reviews</h4>

                    <ul class="list-unstyled">

                        {% for review in product.reviews.all %}

                            <li class="media">

                                <div class="media-body">

                                    <h5 class="mt-0 mb-1">{{ review.user.username }}</h5>

                                    <p>{{ review.comment }}</p>

                                    <small class="text-muted">Rating: {{ review.rating }} stars</small>

                                </div>

                            </li>

                        {% empty %}

                            <p>No reviews yet. Be the first to review this product!</p>

                        {% endfor %}

                    </ul>

                   

                    <!-- Review Form -->

                    <h5>Leave a Review</h5>

                    <form action="{% url 'products:add_review' product.slug %}" method="POST">

                        {% csrf_token %}

                        <div class="form-group">

                            <label for="rating">Rating (1-5 stars):</label>

                            <input type="number" id="rating" name="rating" class="form-control" min="1" max="5" required>

                        </div>

                        <div class="form-group">

                            <label for="comment">Comment:</label>

                            <textarea id="comment" name="comment" class="form-control" rows="4" required></textarea>

                        </div>

                        <button type="submit" class="btn btn-success mt-3">Submit Review</button>

                    </form>

                </div>

            </div>

        </div>

    </div>

{% endblock %}


 

                                                                                                                                                                  Explanation of the Template

1.   Extending the Base Template (base.html):

o    {% extends "base.html" %}: This line ensures that this product detail page uses the layout defined in base.html. The content of base.html will be displayed, and the product_detail.html content will be inserted where the {% block content %} tag is located.

2.   Product Image:

o    The product's image is displayed using the URL stored in the product.image.url field. It uses the img-fluid class from Bootstrap to make the image responsive.

3.   Product Information:

o    The product name, price, and description are displayed in a structured way. The product object contains these attributes (name, price, and description), and they are rendered dynamically.

4.   Category:

o    The category.name field is used to display the category of the product. This assumes that the product model has a category ForeignKey relationship to the Category model.

5.   Add to Cart Form:

o    The form allows users to select the quantity and add the product to the cart.

o    The action of the form is directed to the URL for adding a product to the cart, passing the product ID. This URL is defined in urls.py for the cart app.

o    {% csrf_token %} is included to protect against Cross-Site Request Forgery (CSRF) attacks.

o    The user can adjust the quantity of the product they wish to add to their cart.

6.   Product Reviews:

o    This section loops over all the reviews of the current product (product.reviews.all). Each review is displayed with the reviewer's username, their comment, and the rating they gave.

o    If no reviews exist, a message encourages users to be the first to leave a review.

7.   Leave a Review Form:

o    A form is provided for users to submit their reviews. They can rate the product between 1 and 5 stars and provide a comment.

o    The form sends a POST request to the add_review view, which will handle saving the review.


Product Model Assumptions

This template assumes that your Product model is structured in a way that supports product details, including a category field, image field, and reviews. Below is an example of how your Product model might look:


from django.db import models

 

class Category(models.Model):

    name = models.CharField(max_length=255)

   

    def __str__(self):

        return self.name

 

class Product(models.Model):

    name = models.CharField(max_length=255)

    description = models.TextField()

    price = models.DecimalField(max_digits=10, decimal_places=2)

    image = models.ImageField(upload_to='products/')

    category = models.ForeignKey(Category, related_name='products', on_delete=models.CASCADE)

    slug = models.SlugField(unique=True)

 

    def __str__(self):

        return self.name

 

class Review(models.Model):

    product = models.ForeignKey(Product, related_name='reviews', on_delete=models.CASCADE)

    user = models.ForeignKey(User, on_delete=models.CASCADE)

    rating = models.PositiveIntegerField(default=5)

    comment = models.TextField()

    created_at = models.DateTimeField(auto_now_add=True)

 

    def __str__(self):

        return f'Review for {self.product.name} by {self.user.username}'


Important Notes:

  • Images: Ensure your MEDIA_URL and MEDIA_ROOT settings are correctly configured in settings.py to serve product images.
  • Form Handling: The add_to_cart and add_review forms are set to send POST requests, so ensure these views exist and handle the logic for adding items to the cart and submitting reviews.
  • Static and Media Files: Don't forget to configure Django to serve media files correctly, especially if you're using product images.

This product_detail.html template provides a comprehensive and user-friendly page for viewing a product, reviewing it, and adding it to the shopping cart.

 Below is a detailed implementation of the product_list.html template for your online shopping cart project. This template will display a list of all available products, allowing users to view product details or add products directly to the cart.

online_shopping_cart/products/templates/products/product_list.html

html

Copy code

{% extends "base.html" %}

 

{% block content %}

    <div class="container mt-5">

        <h1 class="mb-4">Available Products</h1>

        <div class="row">

            {% for product in products %}

                <div class="col-md-4">

                    <div class="card mb-4 shadow-sm">

                        <!-- Product Image -->

                        <img src="{{ product.image.url }}" class="card-img-top" alt="{{ product.name }}">

 

                        <div class="card-body">

                            <!-- Product Name -->

                            <h5 class="card-title">{{ product.name }}</h5>

                            <!-- Product Price -->

                            <p class="card-text"><strong>Price:</strong> ${{ product.price }}</p>

                            <!-- Product Short Description -->

                            <p class="card-text text-muted">{{ product.description|truncatechars:100 }}</p>

 

                            <!-- View Details Button -->

                            <a href="{% url 'products:product_detail' product.id %}" class="btn btn-outline-primary btn-sm">

                                View Details

                            </a>

 

                            <!-- Add to Cart Form -->

                            <form action="{% url 'cart:add_to_cart' product.id %}" method="POST" class="d-inline">

                                {% csrf_token %}

                                <input type="hidden" name="quantity" value="1">

                                <button type="submit" class="btn btn-primary btn-sm">

                                    Add to Cart

                                </button>

                            </form>

                        </div>

                    </div>

                </div>

            {% empty %}

                <p class="text-center">No products are available at the moment. Please check back later!</p>

            {% endfor %}

        </div>

    </div>

{% endblock %}


Explanation of the Template

1.   Extending the Base Template:

o    {% extends "base.html" %}: This ensures that the layout defined in the base.html template is used for the product list page.

o    The content inside {% block content %} replaces the content block in base.html.

2.   Heading:

o    A heading (<h1>) is added at the top of the page for clarity, stating the purpose of the page.

3.   Product Loop:

o    {% for product in products %}: Loops through all products passed to the template. The variable products should be provided in the context from the view.

o    {% empty %}: If no products are available, a message is displayed to the user.

4.   Bootstrap Card Layout:

o    Each product is displayed in a Bootstrap card component for a clean, responsive design.

o    The col-md-4 class ensures that three products are displayed per row on medium-sized screens and larger.

5.   Product Image:

o    Displays the product's image using product.image.url. Ensure your media settings in Django are configured correctly.

6.   Product Information:

o    The product's name, price, and a truncated description are displayed.

o    The truncatechars:100 filter ensures that the description is shortened to 100 characters to maintain consistency in layout.

7.   View Details Button:

o    Provides a link to the product's detail page using the URL name products:product_detail and passing the product.id.

8.   Add to Cart Form:

o    Users can directly add a product to their cart with a default quantity of 1.

o    The form sends a POST request to the cart:add_to_cart view with the product.id and includes a CSRF token for security.


Assumptions

1.   View Context:

o    The product_list view passes a context variable named products that contains a queryset of all available products.

Example product_list view:

python

Copy code

from django.shortcuts import render

from .models import Product

 

def product_list(request):

    products = Product.objects.all()

    return render(request, 'products/product_list.html', {'products': products})

2.   Product Model:

o    The Product model includes fields like name, description, price, and image.

3.   URLs Configuration:

o    The products:product_detail and cart:add_to_cart URL names should be defined in your urls.py.


Notes for Styling and Features

1.   Responsive Design:

o    Bootstrap ensures the page layout adjusts dynamically for different screen sizes.

o    Images use the card-img-top class for proper alignment.

2.   Dynamic Filtering:

o    You could enhance this template by adding filters (e.g., by category or price range) to allow users to narrow down the list of products.

3.   Empty State:

o    The {% empty %} tag ensures a user-friendly message is displayed when no products are available.


This product_list.html template creates an intuitive and visually appealing product listing page, allowing users to browse products, view details, and add items to their cart directly.

The __init__.py file is used to indicate that the products directory is a Python package. For most Django applications, this file is typically empty unless you want to include specific initialization code for your package.

Here’s an example of a detailed __init__.py file for the products app in the online_shopping_cart project. This file will include optional initialization logic, such as logging setup or signals registration, making it useful for advanced scenarios.


online_shopping_cart/products/__init__.py

python
# online_shopping_cart/products/__init__.py
 
"""
This is the initialization file for the 'products' app in the online shopping cart project.
 
The products app handles the management of product information, including:
- Product listing
- Product categories (if applicable)
- Product-specific features such as images, descriptions, and pricing
"""
 
# Import and register signals
from . import signals
 
# Optional: Import and configure logging (if needed)
import logging
 
# Create a logger for the 'products' app
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
 
# Example logging setup
if not logger.handlers:
    # Console handler
    console_handler = logging.StreamHandler()
    console_handler.setLevel(logging.INFO)
 
    # Formatter for the console handler
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    console_handler.setFormatter(formatter)
 
    # Add the console handler to the logger
    logger.addHandler(console_handler)
 
logger.info("The 'products' app has been initialized.")

Explanation

1.   Docstring:

o    Provides a high-level overview of the products app and its purpose.

2.   Signals Registration:

o    The file imports and registers signals from the signals.py file (assumed to exist in the products app). This is useful if your app uses Django signals for event-driven functionality, such as updating inventory when an order is placed.

3.   Logging Setup:

o    A logger is created specifically for the products app.

o    Console logging is set up to display informational messages. This is helpful for debugging during development or monitoring the app in production.

4.   Optional Initialization Code:

o    Any setup that is specific to the products app (e.g., configuration of third-party libraries or custom middleware) can be included here.


When to Use Detailed __init__.py

While it’s common for __init__.py files to remain empty in Django projects, adding logic like the above is useful in scenarios where:

  • You need app-specific logging.
  • You want to centralize the registration of signals.
  • You want to execute setup code when the app is loaded.

Example Signal Registration (signals.py)

If you decide to register signals, ensure you have a signals.py file in your products app. For example:

signals.py

python
from django.db.models.signals import pre_save
from django.dispatch import receiver
from .models import Product
 
@receiver(pre_save, sender=Product)
def update_product_price(sender, instance, **kwargs):
    """
    Example signal to handle product price updates before saving.
    """
    if instance.discount_price:
        instance.final_price = instance.discount_price
    else:
        instance.final_price = instance.price

The __init__.py file ensures this signals.py is imported and ready to use when the products app is initialized.

This approach makes your app modular and ready for advanced functionality while remaining easy to maintain.

The __init__.py file for the users app in your online_shopping_cart project can include optional logic for initializing specific functionalities, such as signal registrations or logging for user-related events. Below is a detailed example:


online_shopping_cart/users/__init__.py

python
# online_shopping_cart/users/__init__.py
 
"""
This is the initialization file for the 'users' app in the online shopping cart project.
 
The users app handles:
- User registration
- Authentication and authorization
- Profile management
- Role-based access control (e.g., admin vs. customer)
"""
 
# Import and register signals
from . import signals
 
# Optional: Import and configure logging for the 'users' app
import logging
 
# Set up logger for the 'users' app
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
 
# Configure logging (console handler)
if not logger.handlers:
    console_handler = logging.StreamHandler()
    console_handler.setLevel(logging.INFO)
 
    # Formatter for log messages
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    console_handler.setFormatter(formatter)
 
    # Add the console handler to the logger
    logger.addHandler(console_handler)
 
logger.info("The 'users' app has been initialized.")

Explanation of Components

1.   Docstring:

o    Provides a high-level overview of the purpose of the users app.

2.   Signal Registration:

o    Imports the signals.py file (assumed to exist in the users app). This ensures any custom Django signals related to user events, like profile creation upon registration, are automatically registered when the app is loaded.

3.   Logging Setup:

o    A logger is created for the users app, making it easy to track user-related activities such as logins, failed attempts, or profile updates.

o    Configures console logging for development purposes. You can extend this to include file handlers for production environments.

4.   Modular Initialization:

o    Centralizes the setup code for the users app. This structure ensures maintainability and extensibility for future enhancements.


Optional Signals Example (signals.py)

If you use signals in your users app, ensure you have a signals.py file. For example:

signals.py

python
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.contrib.auth.models import User
from .models import Profile
 
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
    """
    Automatically create a user profile when a new user is registered.
    """
    if created:
        Profile.objects.create(user=instance)
        instance.profile.save()

Benefits of a Detailed __init__.py

  • Centralized Configuration: Handles app-specific setup, such as signals or logging.
  • Improved Debugging: Logging helps monitor app initialization and track issues in user management workflows.
  • Extensibility: Easy to add more features like third-party authentication setup or role-based access initialization.

This approach ensures your users app is robust, modular, and ready for advanced functionality.

  Below is a detailed example of how admin.py for the users app in your online_shopping_cart project might look. This file registers the models related to user management in Django's admin interface and customizes their display.


online_shopping_cart/users/admin.py

python
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
from .models import Profile
 
# Define an inline admin descriptor for Profile model
# which acts a bit like a singleton
class ProfileInline(admin.StackedInline):
    """
    Inline admin descriptor for the Profile model.
    Allows editing of user profiles directly from the User admin page.
    """
    model = Profile
    can_delete = False
    verbose_name_plural = 'Profiles'
    fk_name = 'user'
 
# Customize the User admin class to include Profile
class CustomUserAdmin(UserAdmin):
    """
    Customizes the User admin to include profile-related fields.
    """
    inlines = (ProfileInline,)
    list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff', 'get_phone', 'get_address')
    list_select_related = ('profile',)
 
    def get_phone(self, instance):
        """
        Retrieves the phone number from the user's profile.
        """
        return instance.profile.phone
 
    get_phone.short_description = 'Phone'
 
    def get_address(self, instance):
        """
        Retrieves the address from the user's profile.
        """
        return instance.profile.address
 
    get_address.short_description = 'Address'
 
    def get_inline_instances(self, request, obj=None):
        """
        Ensures the Profile inline is only displayed if the User has a Profile.
        """
        if not obj:
            return []
        return super().get_inline_instances(request, obj)
 
# Unregister the default User admin and register the custom one
admin.site.unregister(User)
admin.site.register(User, CustomUserAdmin)
 
# Register the Profile model for standalone management
@admin.register(Profile)
class ProfileAdmin(admin.ModelAdmin):
    """
    Admin class for standalone Profile management.
    """
    list_display = ('user', 'phone', 'address', 'date_of_birth')
    search_fields = ('user__username', 'user__email', 'phone')
    list_filter = ('date_of_birth',)
    ordering = ('user',)

Explanation of Components

1.   ProfileInline:

o    Adds a profile section directly within the admin interface for a user.

o    Uses StackedInline to display profile fields in a stacked layout.

2.   CustomUserAdmin:

o    Enhances the default Django UserAdmin to include profile-related data in the list_display and make it editable via inlines.

o    Includes methods like get_phone and get_address to display additional information from the Profile model in the user list.

3.   Unregistering Default User Admin:

o    The default User admin is unregistered and replaced with CustomUserAdmin for better integration with the Profile model.

4.   Standalone ProfileAdmin:

o    Registers the Profile model separately to manage profiles directly if needed.

o    Includes search fields and filters for easier management.


Benefits

  • User-Friendly Interface: Admins can view and edit user details and associated profiles in one place.
  • Customization: Extends Django's default admin to meet project-specific requirements.
  • Scalability: Allows easy addition of fields or features related to user profiles.

This implementation ensures the admin panel is both powerful and intuitive for managing users and their associated data.

You said:

online_shopping_cart/users/apps.py python Copy code

ChatGPT said:

ChatGPT

Below is a detailed example of the apps.py file for the users app in your online_shopping_cart project. This file defines the configuration for the users app.


online_shopping_cart/users/apps.py

python
from django.apps import AppConfig
 
class UsersConfig(AppConfig):
    """
    Configuration class for the 'users' app.
    """
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'users'
    verbose_name = 'User Management'
 
    def ready(self):
        """
        Method called when the app is ready.
        Can be used to perform startup tasks such as signal registration.
        """
        import users.signals  # Import signals to connect them with their handlers

Explanation of Components

1.   UsersConfig Class:

o    name: Specifies the full Python path to the app (users).

o    verbose_name: Provides a human-readable name for the app. This will appear in the Django admin.

o    default_auto_field: Specifies the default primary key field type (BigAutoField is used for auto-incrementing primary keys).

2.   ready Method:

o    Executes code when the app is loaded and ready.

o    Typically used to import and connect signal handlers (e.g., for extending user functionality).

3.   Signal Import:

o    The import users.signals statement ensures signal handlers are registered when the app starts.

o    For example, you might have signals to create or update a Profile instance whenever a User is created or updated.


Example Use Case for Signals

If you have a Profile model associated with User, you can create a signal in users/signals.py that automatically creates a Profile when a new User is added:

python
# users/signals.py
from django.db.models.signals import post_save
from django.contrib.auth.models import User
from django.dispatch import receiver
from .models import Profile
 
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
    if created:
        Profile.objects.create(user=instance)
 
@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
    instance.profile.save()

This signal ensures that every User has an associated Profile.


Why Use ready for Signals?

By importing signals in the ready method:

  • The signals are registered only when the app is loaded.
  • This avoids potential circular import issues.

This approach ensures your users app is well-configured and extensible for handling user-related functionality.

You said:

online_shopping_cart/users/migrations/models.py

ChatGPT said:

ChatGPT

Here’s an example of how the models.py file in the users app of your online_shopping_cart project might look. This file defines the database models related to user management, such as extending the default User model with additional fields using a Profile model.


online_shopping_cart/users/models.py

python
from django.db import models
from django.contrib.auth.models import User
from django.utils.timezone import now
 
class Profile(models.Model):
    """
    Profile model to extend the built-in User model with additional fields.
    """
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')
    address = models.TextField(blank=True, null=True, verbose_name="Address")
    phone_number = models.CharField(max_length=15, blank=True, null=True, verbose_name="Phone Number")
    profile_image = models.ImageField(upload_to='profiles/', blank=True, null=True, verbose_name="Profile Image")
    date_of_birth = models.DateField(blank=True, null=True, verbose_name="Date of Birth")
    created_at = models.DateTimeField(default=now, verbose_name="Created At")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="Updated At")
 
    def __str__(self):
        return f"{self.user.username}'s Profile"
 
class Address(models.Model):
    """
    Address model for storing multiple addresses for a user.
    """
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='addresses')
    address_line1 = models.CharField(max_length=255, verbose_name="Address Line 1")
    address_line2 = models.CharField(max_length=255, blank=True, null=True, verbose_name="Address Line 2")
    city = models.CharField(max_length=100, verbose_name="City")
    state = models.CharField(max_length=100, verbose_name="State")
    postal_code = models.CharField(max_length=20, verbose_name="Postal Code")
    country = models.CharField(max_length=100, verbose_name="Country")
    is_default = models.BooleanField(default=False, verbose_name="Default Address")
    created_at = models.DateTimeField(default=now, verbose_name="Created At")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="Updated At")
 
    def __str__(self):
        return f"{self.user.username} - {self.address_line1}, {self.city}, {self.country}"

Explanation of Models

Profile Model

  • Extends the User model to store additional information such as:
    • address: A text field for the user's address.
    • phone_number: A field for storing a contact number.
    • profile_image: An optional image field for user avatars.
    • date_of_birth: Stores the user's date of birth.
  • created_at and updated_at: Timestamps for when the profile was created and last updated.

Address Model

  • Enables storing multiple addresses for a user:
    • address_line1, city, state, etc., represent parts of an address.
    • is_default: A flag to indicate the default address for a user.
  • Foreign key relationship with User allows a user to have multiple addresses.

Integrating with the User Model

1.   Signals: Use signals to automatically create a Profile for each new user:

python
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.contrib.auth.models import User
 
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
    if created:
        Profile.objects.create(user=instance)
 
@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
    instance.profile.save()

2.   Admin Integration: Add the Profile and Address models to the admin interface for management.


Admin Example

python
from django.contrib import admin
from .models import Profile, Address
 
@admin.register(Profile)
class ProfileAdmin(admin.ModelAdmin):
    list_display = ('user', 'phone_number', 'date_of_birth', 'created_at')
 
@admin.register(Address)
class AddressAdmin(admin.ModelAdmin):
    list_display = ('user', 'address_line1', 'city', 'state', 'country', 'is_default')

This implementation provides flexibility for user management, supporting additional user information and multiple addresses.

You said:

online_shopping_cart/users/migrations/views.py

ChatGPT said:

ChatGPT

Here’s an example of how you might structure a views.py file for the users app in the online_shopping_cart project. This file typically handles user-related views such as registration, login, profile management, and password changes.


online_shopping_cart/users/views.py

from django.shortcuts import render, redirect
from django.contrib.auth import login, authenticate, logout
from django.contrib.auth.forms import AuthenticationForm, PasswordChangeForm
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from .forms import UserRegistrationForm, UserProfileForm
from .models import Profile
 
def register(request):
    """
    User registration view.
    """
    if request.method == 'POST':
        form = UserRegistrationForm(request.POST)
        if form.is_valid():
            user = form.save()
            Profile.objects.create(user=user)  # Automatically create a profile for the user
            login(request, user)
            messages.success(request, "Registration successful!")
            return redirect('products:product_list')
        else:
            messages.error(request, "Registration failed. Please check the form for errors.")
    else:
        form = UserRegistrationForm()
    return render(request, 'users/register.html', {'form': form})
 
def user_login(request):
    """
    User login view.
    """
    if request.method == 'POST':
        form = AuthenticationForm(request, data=request.POST)
        if form.is_valid():
            username = form.cleaned_data.get('username')
            password = form.cleaned_data.get('password')
            user = authenticate(request, username=username, password=password)
            if user is not None:
                login(request, user)
                messages.success(request, f"Welcome back, {user.username}!")
                return redirect('products:product_list')
            else:
                messages.error(request, "Invalid username or password.")
        else:
            messages.error(request, "Invalid username or password.")
    else:
        form = AuthenticationForm()
    return render(request, 'users/login.html', {'form': form})
 
@login_required
def user_logout(request):
    """
    User logout view.
    """
    logout(request)
    messages.success(request, "You have successfully logged out.")
    return redirect('users:login')
 
@login_required
def profile(request):
    """
    User profile view and update.
    """
    profile = request.user.profile
    if request.method == 'POST':
        form = UserProfileForm(request.POST, request.FILES, instance=profile)
        if form.is_valid():
            form.save()
            messages.success(request, "Your profile has been updated.")
            return redirect('users:profile')
        else:
            messages.error(request, "There was an error updating your profile.")
    else:
        form = UserProfileForm(instance=profile)
    return render(request, 'users/profile.html', {'form': form})
 
@login_required
def change_password(request):
    """
    User password change view.
    """
    if request.method == 'POST':
        form = PasswordChangeForm(user=request.user, data=request.POST)
        if form.is_valid():
            form.save()
            messages.success(request, "Your password has been successfully updated.")
            return redirect('users:profile')
        else:
            messages.error(request, "There was an error changing your password.")
    else:
        form = PasswordChangeForm(user=request.user)
    return render(request, 'users/change_password.html', {'form': form})

Explanation of the Views

1.   register View:

o    Handles user registration with a custom form.

o    Automatically creates a Profile object for the new user.

o    Logs in the user after successful registration.

2.   user_login View:

o    Uses Django's built-in AuthenticationForm for user login.

o    Authenticates the user and logs them in if the credentials are valid.

3.   user_logout View:

o    Logs out the currently logged-in user.

o    Redirects to the login page.

4.   profile View:

o    Allows logged-in users to view and update their profiles.

o    Supports updating fields in the Profile model (e.g., address, phone number).

5.   change_password View:

o    Allows users to change their passwords using Django's PasswordChangeForm.

o    Validates the form and updates the password if valid.


Templates

Ensure you create corresponding templates for the views. Examples:

  • users/register.html
  • users/login.html
  • users/profile.html
  • users/change_password.html

Example URLs for Views

In users/urls.py:

python
from django.urls import path
from . import views
 
app_name = 'users'
 
urlpatterns = [
    path('register/', views.register, name='register'),
    path('login/', views.user_login, name='login'),
    path('logout/', views.user_logout, name='logout'),
    path('profile/', views.profile, name='profile'),
    path('change-password/', views.change_password, name='change_password'),
]

This setup provides a robust user management system for the online_shopping_cart project.

You said:

online_shopping_cart/users/migrations/urls.py

ChatGPT said:

ChatGPT

In a Django project, migrations typically do not include URLs because they are meant to manage changes in the database schema. However, if you are referring to creating a urls.py file under the users app (not specifically under migrations), here's how it might look.


online_shopping_cart/users/urls.py

This file defines the URL patterns for the users app, linking them to the views we previously discussed.

python
from django.urls import path
from . import views
 
app_name = 'users'
 
urlpatterns = [
    path('register/', views.register, name='register'),
    path('login/', views.user_login, name='login'),
    path('logout/', views.user_logout, name='logout'),
    path('profile/', views.profile, name='profile'),
    path('change-password/', views.change_password, name='change_password'),
]

Explanation of the URL Patterns

1.   register/: Routes to the user registration view.

2.   login/: Routes to the login view for user authentication.

3.   logout/: Routes to the logout view, which logs out the user.

4.   profile/: Routes to the profile view where users can update their information.

5.   change-password/: Routes to the change password view for updating user passwords.


Integrating URLs into the Project

To use these URLs in the main project, include them in the project's urls.py file:

python
from django.contrib import admin
from django.urls import path, include
 
urlpatterns = [
    path('admin/', admin.site.urls),
    path('users/', include('users.urls')),
    path('', include('products.urls')),  # Assuming the products app handles the homepage
]

This setup ensures that the users app has its own namespace and routes for all user-related functionalities.

You said:

online_shopping_cart/users/templates/users/login.html

ChatGPT said:

ChatGPT

Here’s a detailed implementation of the login.html template for the users app. This template uses Bootstrap for styling and provides a clean and user-friendly login interface.


online_shopping_cart/users/templates/users/login.html

html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Login</title>
    <link rel="stylesheet" href="{% static 'css/styles.css' %}">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <div class="container">
        <div class="row justify-content-center mt-5">
            <div class="col-md-6">
                <div class="card shadow-sm">
                    <div class="card-header text-center">
                        <h4>Login</h4>
                    </div>
                    <div class="card-body">
                        {% if messages %}
                            <div>
                                {% for message in messages %}
                                    <div class="alert alert-{{ message.tags }} alert-dismissible fade show" role="alert">
                                        {{ message }}
                                        <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
                                    </div>
                                {% endfor %}
                            </div>
                        {% endif %}
                        <form method="post" action="{% url 'users:login' %}">
                            {% csrf_token %}
                            <div class="mb-3">
                                <label for="username" class="form-label">Username</label>
                                <input type="text" name="username" id="username" class="form-control" placeholder="Enter your username" required>
                            </div>
                            <div class="mb-3">
                                <label for="password" class="form-label">Password</label>
                                <input type="password" name="password" id="password" class="form-control" placeholder="Enter your password" required>
                            </div>
                            <div class="d-grid gap-2">
                                <button type="submit" class="btn btn-primary">Login</button>
                            </div>
                        </form>
                        <div class="text-center mt-3">
                            <p>Don't have an account? <a href="{% url 'users:register' %}">Register here</a></p>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
 
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

Features of the Template

1.   Bootstrap Integration:

o    Ensures the form is responsive and visually appealing.

o    Utilizes Bootstrap classes for form layout and alert messages.

2.   CSRF Token:

o    Adds {% csrf_token %} to prevent Cross-Site Request Forgery attacks.

3.   Dynamic Messages:

o    Displays Django's messages framework output for login feedback (e.g., invalid credentials).

4.   User-friendly Design:

o    Includes a link to the registration page for new users.

o    Uses clear placeholders and labels to guide users.

5.   Responsive Layout:

o    Adjusts to different screen sizes using Bootstrap's grid system.

This template provides a professional login page while keeping the user experience seamless.

You said:

online_shopping_cart/users/templates/users/register.html

ChatGPT said:

ChatGPT

Here’s a detailed implementation of the register.html template for the users app. This template provides a user registration form styled with Bootstrap for a clean and responsive layout.


online_shopping_cart/users/templates/users/register.html

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>Register</title>

    <link rel="stylesheet" href="{% static 'css/styles.css' %}">

    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">

</head>

<body>

    <div class="container">

        <div class="row justify-content-center mt-5">

            <div class="col-md-6">

                <div class="card shadow-sm">

                    <div class="card-header text-center">

                        <h4>Register</h4>

                    </div>

                    <div class="card-body">

                        {% if messages %}

                            <div>

                                {% for message in messages %}

                                    <div class="alert alert-{{ message.tags }} alert-dismissible fade show" role="alert">

                                        {{ message }}

                                        <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>

                                    </div>

                                {% endfor %}

                            </div>

                        {% endif %}

                        <form method="post" action="{% url 'users:register' %}">

                            {% csrf_token %}

                            <div class="mb-3">

                                <label for="username" class="form-label">Username</label>

                                <input type="text" name="username" id="username" class="form-control" placeholder="Enter your username" required>

                            </div>

                            <div class="mb-3">

                                <label for="email" class="form-label">Email</label>

                                <input type="email" name="email" id="email" class="form-control" placeholder="Enter your email address" required>

                            </div>

                            <div class="mb-3">

                                <label for="password1" class="form-label">Password</label>

                                <input type="password" name="password1" id="password1" class="form-control" placeholder="Enter your password" required>

                            </div>

                            <div class="mb-3">

                                <label for="password2" class="form-label">Confirm Password</label>

                                <input type="password" name="password2" id="password2" class="form-control" placeholder="Confirm your password" required>

                            </div>

                            <div class="d-grid gap-2">

                                <button type="submit" class="btn btn-primary">Register</button>

                            </div>

                        </form>

                        <div class="text-center mt-3">

                            <p>Already have an account? <a href="{% url 'users:login' %}">Login here</a></p>

                        </div>

                    </div>

                </div>

            </div>

        </div>

    </div>

 

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>

</body>

</html>

 

 Features of the Template

1.   Bootstrap Integration:

o    Ensures a responsive and modern design.

o    Uses Bootstrap classes for form styling and layout.

2.   CSRF Token:

o    Includes {% csrf_token %} for secure form submissions.

3.   Dynamic Messages:

o    Displays Django's messages for feedback, such as error messages or successful registration.

4.   Form Fields:

o    Provides fields for username, email, password, and password confirmation.

o    Uses placeholders and labels to enhance user experience.

5.   Responsive Design:

o    Adapts to various screen sizes using Bootstrap's grid system.

6.   Navigation to Login:

o    Includes a link to the login page for users who already have an account.

online_shopping_cart/users/templates/users/profile.html

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>User Profile</title>

    <link rel="stylesheet" href="{% static 'css/styles.css' %}">

    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">

</head>

<body>

    <div class="container mt-5">

        <div class="row justify-content-center">

            <div class="col-md-8">

                <div class="card shadow-sm">

                    <div class="card-header text-center">

                        <h4>Profile</h4>

                    </div>

                    <div class="card-body">

                        {% if messages %}

                            <div>

                                {% for message in messages %}

                                    <div class="alert alert-{{ message.tags }} alert-dismissible fade show" role="alert">

                                        {{ message }}

                                        <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>

                                    </div>

                                {% endfor %}

                            </div>

                        {% endif %}

                        <form method="POST" action="{% url 'users:update_profile' %}">

                            {% csrf_token %}

                            <div class="mb-3">

                                <label for="username" class="form-label">Username</label>

                                <input type="text" name="username" id="username" class="form-control" value="{{ user.username }}" required>

                            </div>

                            <div class="mb-3">

                                <label for="email" class="form-label">Email</label>

                                <input type="email" name="email" id="email" class="form-control" value="{{ user.email }}" required>

                            </div>

                            <div class="mb-3">

                                <label for="first_name" class="form-label">First Name</label>

                                <input type="text" name="first_name" id="first_name" class="form-control" value="{{ user.first_name }}">

                            </div>

                            <div class="mb-3">

                                <label for="last_name" class="form-label">Last Name</label>

                                <input type="text" name="last_name" id="last_name" class="form-control" value="{{ user.last_name }}">

                            </div>

                            <div class="mb-3">

                                <label for="password" class="form-label">Change Password</label>

                                <input type="password" name="password" id="password" class="form-control" placeholder="Leave blank if you don't want to change your password">

                            </div>

                            <div class="mb-3">

                                <label for="confirm_password" class="form-label">Confirm New Password</label>

                                <input type="password" name="confirm_password" id="confirm_password" class="form-control" placeholder="Confirm new password">

                            </div>

                            <div class="d-grid gap-2">

                                <button type="submit" class="btn btn-primary">Update Profile</button>

                            </div>

                        </form>

                        <div class="text-center mt-3">

                            <a href="{% url 'users:change_password' %}">Change Password</a> | <a href="{% url 'users:logout' %}">Logout</a>

                        </div>

                    </div>

                </div>

            </div>

        </div>

    </div>

 

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>

</body>

</html>


 

 Features of the Template

1.   Profile Overview:

o    Displays the current user's information such as username, email, first_name, and last_name which are pre-filled from the user object.

2.   Form for Profile Update:

o    Includes form fields for users to update their profile details such as username, email, first_name, and last_name.

o    There’s also a field for changing the password, where the user can leave it blank if they don’t want to change it.

o    The user can enter and confirm a new password in the respective fields.

3.   CSRF Token:

o    The form includes {% csrf_token %} for protection against cross-site request forgery.

4.   Dynamic Messages:

o    Displays success or error messages (using Django's messaging framework) when the form is submitted, for example, after a successful profile update or password change.

5.   Password Update Option:

o    There is an option to change the user password. This is optional and users can leave it blank if they are not updating their password.

6.   Links for Additional Actions:

o    Links are provided for the user to change their password or log out of the system.

7.   Responsive Design:

o    Utilizes Bootstrap for a clean and responsive layout, ensuring that the form looks good on all screen sizes.

8.   Action URL:

o    The form’s action URL points to the profile update view ('users:update_profile'), which will handle the form submission and update the user information.

This profile template provides a user-friendly interface for the user to view and manage their profile information. It maintains security with proper CSRF protection and offers options for password management.

 

Post a Comment

0Comments

Post a Comment (0)