Demo Website: IREC
Demo account (only view permission in admin page):
email: [email protected] password: demo123456
NOTE: USE TEST CREDIT CARD TO MAKE PAYMENT 4242 4242 4242 4242
Check here for more info.
This is a simple ecommerce project built mainly by Django Framework + few Javascript/jquery, using Bootstrap 4 template with Django template language.
As a hands-on project for a newbee developer (myself), if your are tired of writing those helloworld crap, looking for something more challenging to make use of your Django and overall web development skills, hope this project could be helpful as your reference.
Since I am exploring the right way to impelement those features, I am pretty sure there are many other better approaches. Please feel free to share your ideas and indicate my mistakes, which would be really really appreciated.
- Home - searching, category, trending items
- Shop list - list items, sorting, searching, categorizing
- Item detail - add shopping cart, add wishlist, check reviews, related products
- Shopping cart - item crud operation
- Checkout - select payment method, edit or add address
- Guest checkout - add shipping address on checkout
- Find order - guest retrieving order data, making payment/return item
- Account center - change profile and password, list watch history in watched order
- Account center orders - order status management, pay/refund/return etc, order detail, write review
- Account center - shipping address management
- Account wishlist - list wishlisted items
- Account activation email - also use for changing account email and sending order status update to customer
- Admin page - appearance, actions
-
account center
- account registration with email activation (also used in changing email address)
- login with email address
- remember login
- change profile and password (based on ajax request)
- manage recipient addresses (based on ajax request)
- order management
- write review and rate stars for ordered items
- google recaptcha for login and register (django-recaptcha)
-
shop
- list and detail view for items
- add/remove item to/from wishlist
- save watch history
- show related item on detail page
- fulltext search (postgresql)
- item list view filter by sorting, category and tags
- item tags (django-taggit)
- recursive category (django-mptt)
-
shopping cart
- add item to shopping cart
- CRUD operation on shopping cart page (based on ajax request)
- guest checkout
-
order and payment
- payment with Stripe Checkout
- status management (django-fsm) (NOTE: this package is going to be deprecated soon, will transit to viewflow in the future)
-
customized admin
- use modern admin theme(django-simpleui)
- custom views and actions (shipping, cancel order, refund)
- autocomplete search (easy-select2)
-
others
- testing with factory_boy and faker
- rich text editor in admin page (django-ckeditor)
- use Sentry for monitoring
- deployment on EC2
-
Django (>=3.1)
-
PostgresSQL
-
Redis
- web site caching
- login session cache
- message queue broker
- shopping cart, watch history, wishlist database
-
AWS S3
- media file storage
-
AWS SES (prod env only)
-
Celery
- async tasks
- periodic tasks / cron jobs
-
Docker
The project is deployed in an EC2 instance, and makes use of other AWS services such as S3 bucket for media file storage, RDS for postgres database, and SES for email sending.
For details on deployment please refer to this tutorial:
NOTE All (except Category and User) models inherit from a base model which has 3 fields: created_at, updated_up, is_deleted
The relationship between Order and Payment could be 1to1 which is easier to manage, while on some EC sites there is an option to pay multiple orders together, here just leave as it is.
Other models such as Invoice, CancelRecord, RefundRecord are not implemented as those could be acheived on the Stripe dashboard.
The states of order is quite complecated, and varies depending on projects and developer. It was really a headache for me.
This chart is created based on some references and my trials and errors, might work for a small project, but definately could be improved and better.
The core idea is that the status of order and status of payment should be seperated as 2 fields (instead of 1 status field in the Order model, which did not work well), meanwhile intertwined with each other (dot line arrows), since the state of payment or order could be the signal or criteria to make actions to change either order or payment's state. To acheive those transitions between different states, works could be done by a user, an admin, or the system.
It is not necessary to add every ongoing state or every perfect tense state (which confused me a lot at the beginning), instead it should be decided based on a simple question: Do I need an action to make the transition here? In other words, if you found that you need 2 steps to acheive the next state, that probably means there should be one more state in the middle.
First clone the repository:
$ git clone https://github.com/convers39/IR-ecommerce.git
Setup your local env file, in my example, the project folder tree looks as below, the env file located in core folder. The default location recognized by docker-compose file is the same directory with docker-compose (in this case the root dir), make sure you set the right file path for env file.
.
├── LICENSE
├── README.md
├── _samples
├── apps
│ ├── __init__.py
│ ├── account
│ ├── cart
│ ├── order
│ └── shop
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── context_processors.py
│ ├── managers.py
│ ├── migrations
│ ├── models.py
│ ├── signals.py
│ ├── tasks.py
│ ├── templatetags
│ ├── tests
│ │ ├── __init__.py
│ │ ├── factory.py
│ │ ├── test_models.py
│ │ ├── test_urls.py
│ │ └── test_views.py
│ ├── urls.py
│ └── views.py
├── core
│ ├── __init__.py
│ ├── asgi.py
│ ├── celery.py
│ ├── env
│ │ ├── env.local
│ │ ├── env.prod
│ │ ├── env.prod.proxy-companion
│ │ ├── env.staging
│ │ ├── env.staging.proxy-companion
│ ├── settings
│ │ ├── __init__.py
│ │ ├── base.py
│ │ ├── local.py
│ │ ├── prod.py
│ │ └── testing.py
│ ├── urls.py
│ └── wsgi.py
├── db
│ ├── __init__.py
│ └── base_model.py
├── docker-compose.yml
├── dockerfile
├── manage.py
├── media
├── requirements.txt
├── static
│ ├── css
│ ├── icons
│ ├── img
│ ├── js
│ └── vendor
└── templates
├── account
├── base.html
├── cart
├── index.html
├── order
└── shop
Then you will need to write down credentials of database, mail server, AWS s3 bucket and Stripe API keys in your env file, and in your settings you can obtain those values, for instance:
# core/settings/base.py
# ...
# Mail server settings will be different depending on which mail service you use
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = os.environ.get('EMAIL_HOST')
EMAIL_PORT = os.environ.get('EMAIL_PORT')
EMAIL_USE_TLS = os.environ.get('EMAIL_USE_TLS')
EMAIL_HOST_USER = os.environ.get('EMAIL_HOST_USER')
EMAIL_FROM = os.environ.get('EMAIL_FROM')
EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_HOST_PASSWORD')
# Use postgresql as database, SQLite is not tested, and fulltext search is not supported
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.environ.get('DB_NAME'),
'USER': os.environ.get('DB_USER'),
'PASSWORD': os.environ.get('DB_PASSWORD'),
'HOST': os.environ.get('DB_HOST'),
'PORT': os.environ.get('DB_PORT'),
}
}
# AWS setting
AWS_ACCESS_KEY_ID = os.environ.get('AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY')
AWS_STORAGE_BUCKET_NAME = os.environ.get('AWS_STORAGE_BUCKET_NAME')
AWS_S3_REGION_NAME = os.environ.get('AWS_S3_REGION_NAME') # change to your region
AWS_S3_SIGNATURE_VERSION = os.environ.get('AWS_S3_SIGNATURE_VERSION')
AWS_S3_FILE_OVERWRITE = True # either true or false is ok
# stripe key
STRIPE_SECRET_KEY = os.environ.get('STRIPE_SECRET_KEY')
STRIPE_PUBLIC_KEY = os.environ.get('STRIPE_PUBLIC_KEY')
WEBHOOK_SECRET = os.environ.get('WEBHOOK_SECRET')
Now build the image and compose up the containers, add --build
flag to compose up when rebuild is needed.
$ docker build .
$ docker-compose -f docker-compose.yml up
Start an empowered interactive shell in django container (provided by django-extensions), use the container name (django in this project)
$ docker exec -it <django> bash
$ python manage.py shell_plus
Access to Postgresql and Redis (Postgresql container is removed in prod setup as using AWS RDS for DB)
$ docker exec -it <pgdb> psql -U <username> <password>
$ docker exec -it <redis> sh
$ redis-cli
To run a test, specify a setting file (might run to errors with debug toolbar if not using testing settings, which forces to turn off DEBUG)
$ python manage.py test <appname> --settings=core.settings.testing
Currently on plan:
- guest shopping cart and checkout
- deployment a demo site + deployment setup
- image resize on upload
- language support for Chinese and Japanese
- filters on shop item list and account center
- third party Oauth login
- coupon apply on shopping cart page