├── polls ├── __init__.py ├── templatetags │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-39.pyc │ │ └── poll_extras.cpython-39.pyc │ └── poll_extras.py ├── models.py ├── tests.py ├── admin.py ├── views.py ├── __pycache__ │ ├── admin.cpython-39.pyc │ ├── apps.cpython-39.pyc │ ├── models.cpython-39.pyc │ └── __init__.cpython-39.pyc └── apps.py ├── utils ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-39.pyc │ ├── convertors.cpython-39.pyc │ ├── email_service.cpython-39.pyc │ └── http_service.cpython-39.pyc ├── convertors.py ├── http_service.py └── email_service.py ├── home_module ├── __init__.py ├── models.py ├── tests.py ├── admin.py ├── __pycache__ │ ├── admin.cpython-39.pyc │ ├── apps.cpython-39.pyc │ ├── urls.cpython-39.pyc │ ├── views.cpython-39.pyc │ ├── models.cpython-39.pyc │ └── __init__.cpython-39.pyc ├── templates │ └── home_module │ │ ├── contact_page.html │ │ └── about_page.html ├── apps.py ├── urls.py └── views.py ├── site_module ├── __init__.py ├── tests.py ├── views.py ├── __pycache__ │ ├── admin.cpython-39.pyc │ ├── apps.cpython-39.pyc │ ├── models.cpython-39.pyc │ └── __init__.cpython-39.pyc ├── apps.py ├── admin.py └── models.py ├── account_module ├── __init__.py ├── tests.py ├── __pycache__ │ ├── apps.cpython-39.pyc │ ├── urls.cpython-39.pyc │ ├── admin.cpython-39.pyc │ ├── forms.cpython-39.pyc │ ├── models.cpython-39.pyc │ ├── views.cpython-39.pyc │ └── __init__.cpython-39.pyc ├── admin.py ├── apps.py ├── urls.py ├── models.py ├── templates │ └── account_module │ │ ├── forgot_password.html │ │ ├── reset_password.html │ │ ├── login.html │ │ └── register.html ├── forms.py └── views.py ├── article_module ├── __init__.py ├── tests.py ├── __pycache__ │ ├── apps.cpython-39.pyc │ ├── urls.cpython-39.pyc │ ├── admin.cpython-39.pyc │ ├── models.cpython-39.pyc │ ├── views.cpython-39.pyc │ └── __init__.cpython-39.pyc ├── apps.py ├── urls.py ├── admin.py ├── templates │ └── article_module │ │ ├── components │ │ └── article_categories_component.html │ │ ├── includes │ │ └── article_comments_partial.html │ │ ├── articles_page.html │ │ └── article_detail_page.html ├── models.py └── views.py ├── contact_module ├── __init__.py ├── tests.py ├── __pycache__ │ ├── apps.cpython-39.pyc │ ├── urls.cpython-39.pyc │ ├── admin.cpython-39.pyc │ ├── forms.cpython-39.pyc │ ├── models.cpython-39.pyc │ ├── views.cpython-39.pyc │ └── __init__.cpython-39.pyc ├── admin.py ├── apps.py ├── urls.py ├── templates │ └── contact_module │ │ ├── profiles_list_page.html │ │ ├── create_profile_page.html │ │ └── contact_us_page.html ├── models.py ├── forms.py └── views.py ├── eshop_project ├── __init__.py ├── __pycache__ │ ├── urls.cpython-39.pyc │ ├── wsgi.cpython-39.pyc │ ├── __init__.cpython-39.pyc │ └── settings.cpython-39.pyc ├── asgi.py ├── wsgi.py ├── urls.py └── settings.py ├── order_module ├── __init__.py ├── tests.py ├── __pycache__ │ ├── apps.cpython-39.pyc │ ├── urls.cpython-39.pyc │ ├── admin.cpython-39.pyc │ ├── models.cpython-39.pyc │ ├── views.cpython-39.pyc │ └── __init__.cpython-39.pyc ├── urls.py ├── admin.py ├── apps.py ├── models.py └── views.py ├── product_module ├── __init__.py ├── tests.py ├── __pycache__ │ ├── apps.cpython-39.pyc │ ├── urls.cpython-39.pyc │ ├── admin.cpython-39.pyc │ ├── models.cpython-39.pyc │ ├── views.cpython-39.pyc │ └── __init__.cpython-39.pyc ├── apps.py ├── templates │ ├── product_module │ │ ├── components │ │ │ ├── product_brands_component.html │ │ │ └── product_categories_component.html │ │ ├── product_list.html │ │ └── product_detail.html │ └── includes │ │ └── product_item_partial.html ├── urls.py ├── admin.py ├── models.py └── views.py ├── user_panel_module ├── __init__.py ├── models.py ├── tests.py ├── admin.py ├── __pycache__ │ ├── apps.cpython-39.pyc │ ├── urls.cpython-39.pyc │ ├── admin.cpython-39.pyc │ ├── forms.cpython-39.pyc │ ├── models.cpython-39.pyc │ ├── views.cpython-39.pyc │ └── __init__.cpython-39.pyc ├── apps.py ├── templates │ └── user_panel_module │ │ ├── user_basket.html │ │ ├── components │ │ └── user_panel_menu_component.html │ │ ├── user_panel_dashboard_page.html │ │ ├── edit_profile_page.html │ │ ├── change_password_page.html │ │ └── user_basket_content.html ├── urls.py ├── forms.py └── views.py ├── db.sqlite3 ├── static ├── fonts │ ├── BYekan.eot │ ├── BYekan.ttf │ ├── BYekan.woff │ ├── FontAwesome.otf │ ├── fontawesome-webfont.woff │ └── glyphicons-halflings-regular.woff ├── images │ ├── 404 │ │ └── 404.png │ ├── cart │ │ ├── one.png │ │ ├── two.png │ │ └── three.png │ ├── home │ │ ├── Map.jpg │ │ ├── map.png │ │ ├── new.png │ │ ├── Slider.psd │ │ ├── Tabs.png │ │ ├── Tabs.psd │ │ ├── girl2.jpg │ │ ├── logo.png │ │ ├── sale.png │ │ ├── Gallery.jpg │ │ ├── Gallery.psd │ │ ├── partner1.png │ │ ├── partner2.png │ │ ├── partner3.png │ │ ├── partner4.png │ │ ├── pricing.png │ │ ├── product.jpg │ │ ├── product1.psd │ │ ├── shipping.jpg │ │ ├── About-Logo.jpg │ │ ├── Slider-01.jpg │ │ ├── bg_border.png │ │ └── searchicon.png │ ├── blog │ │ ├── Customer.jpg │ │ ├── blog-one.jpg │ │ ├── blog-one.psd │ │ └── socials.png │ ├── shop │ │ ├── product.jpg │ │ └── advertisement.jpg │ └── product-details │ │ ├── 1.jpg │ │ ├── Bale.png │ │ ├── Main.psd │ │ ├── new.jpg │ │ ├── new.png │ │ ├── share.png │ │ ├── Similar.psd │ │ ├── Socials.psd │ │ ├── Soroush.png │ │ ├── rating.png │ │ ├── Instagram.png │ │ ├── Telegram.png │ │ ├── similar1.jpg │ │ ├── similar2.jpg │ │ └── similar3.jpg ├── css │ ├── custom.css │ ├── price-range.css │ └── responsive.css ├── js │ ├── contact.js │ ├── jquery.scrollUp.min.js │ ├── html5shiv.js │ ├── main.js │ └── custom.js └── lib │ └── image-lightbox │ ├── css │ └── lightbox.min.css │ └── js │ └── lightbox.min.js ├── media ├── images │ └── products │ │ ├── product.jpg │ │ ├── redmi_note11.jfif │ │ ├── redmi_watch.jfif │ │ └── surface_12.4.jfif └── cache │ ├── 94 │ └── 1b │ │ └── 941b13009bd5ae011fbe01ddeb3e3aee.jpg │ ├── b2 │ └── 97 │ │ └── b297c80c91dddc1b6c35e13cf2e0eaa5.jpg │ ├── e0 │ └── 20 │ │ └── e02002d56d4f44121a199ac771292f12.jpg │ └── ee │ └── 76 │ └── ee76a2cdb70f68737ded7741c45cb67a.jpg ├── requirements.txt ├── templates ├── base.html ├── emails │ ├── activate_account.html │ └── forgot_password.html └── shared │ ├── footer_references.html │ ├── _layout.html │ ├── header_references.html │ ├── site_footer_component.html │ └── site_header_component.html ├── README.md └── manage.py /polls/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /home_module/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /site_module/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /account_module/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /article_module/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /contact_module/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /eshop_project/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /order_module/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /product_module/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /polls/templatetags/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /user_panel_module/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /db.sqlite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/db.sqlite3 -------------------------------------------------------------------------------- /polls/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /polls/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /home_module/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /home_module/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /order_module/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /polls/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /polls/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | 3 | # Create your views here. 4 | -------------------------------------------------------------------------------- /site_module/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /account_module/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /article_module/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /contact_module/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /product_module/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /site_module/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | 3 | # Create your views here. 4 | -------------------------------------------------------------------------------- /user_panel_module/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /user_panel_module/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /home_module/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | 5 | -------------------------------------------------------------------------------- /user_panel_module/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /static/fonts/BYekan.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/fonts/BYekan.eot -------------------------------------------------------------------------------- /static/fonts/BYekan.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/fonts/BYekan.ttf -------------------------------------------------------------------------------- /static/fonts/BYekan.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/fonts/BYekan.woff -------------------------------------------------------------------------------- /static/images/404/404.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/404/404.png -------------------------------------------------------------------------------- /static/images/cart/one.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/cart/one.png -------------------------------------------------------------------------------- /static/images/cart/two.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/cart/two.png -------------------------------------------------------------------------------- /static/images/home/Map.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/home/Map.jpg -------------------------------------------------------------------------------- /static/images/home/map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/home/map.png -------------------------------------------------------------------------------- /static/images/home/new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/home/new.png -------------------------------------------------------------------------------- /static/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /static/images/cart/three.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/cart/three.png -------------------------------------------------------------------------------- /static/images/home/Slider.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/home/Slider.psd -------------------------------------------------------------------------------- /static/images/home/Tabs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/home/Tabs.png -------------------------------------------------------------------------------- /static/images/home/Tabs.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/home/Tabs.psd -------------------------------------------------------------------------------- /static/images/home/girl2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/home/girl2.jpg -------------------------------------------------------------------------------- /static/images/home/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/home/logo.png -------------------------------------------------------------------------------- /static/images/home/sale.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/home/sale.png -------------------------------------------------------------------------------- /static/images/blog/Customer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/blog/Customer.jpg -------------------------------------------------------------------------------- /static/images/blog/blog-one.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/blog/blog-one.jpg -------------------------------------------------------------------------------- /static/images/blog/blog-one.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/blog/blog-one.psd -------------------------------------------------------------------------------- /static/images/blog/socials.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/blog/socials.png -------------------------------------------------------------------------------- /static/images/home/Gallery.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/home/Gallery.jpg -------------------------------------------------------------------------------- /static/images/home/Gallery.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/home/Gallery.psd -------------------------------------------------------------------------------- /static/images/home/partner1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/home/partner1.png -------------------------------------------------------------------------------- /static/images/home/partner2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/home/partner2.png -------------------------------------------------------------------------------- /static/images/home/partner3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/home/partner3.png -------------------------------------------------------------------------------- /static/images/home/partner4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/home/partner4.png -------------------------------------------------------------------------------- /static/images/home/pricing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/home/pricing.png -------------------------------------------------------------------------------- /static/images/home/product.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/home/product.jpg -------------------------------------------------------------------------------- /static/images/home/product1.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/home/product1.psd -------------------------------------------------------------------------------- /static/images/home/shipping.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/home/shipping.jpg -------------------------------------------------------------------------------- /static/images/shop/product.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/shop/product.jpg -------------------------------------------------------------------------------- /media/images/products/product.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/media/images/products/product.jpg -------------------------------------------------------------------------------- /static/images/home/About-Logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/home/About-Logo.jpg -------------------------------------------------------------------------------- /static/images/home/Slider-01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/home/Slider-01.jpg -------------------------------------------------------------------------------- /static/images/home/bg_border.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/home/bg_border.png -------------------------------------------------------------------------------- /static/images/home/searchicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/home/searchicon.png -------------------------------------------------------------------------------- /static/images/product-details/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/product-details/1.jpg -------------------------------------------------------------------------------- /static/images/shop/advertisement.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/shop/advertisement.jpg -------------------------------------------------------------------------------- /media/images/products/redmi_note11.jfif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/media/images/products/redmi_note11.jfif -------------------------------------------------------------------------------- /media/images/products/redmi_watch.jfif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/media/images/products/redmi_watch.jfif -------------------------------------------------------------------------------- /media/images/products/surface_12.4.jfif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/media/images/products/surface_12.4.jfif -------------------------------------------------------------------------------- /polls/__pycache__/admin.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/polls/__pycache__/admin.cpython-39.pyc -------------------------------------------------------------------------------- /polls/__pycache__/apps.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/polls/__pycache__/apps.cpython-39.pyc -------------------------------------------------------------------------------- /polls/__pycache__/models.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/polls/__pycache__/models.cpython-39.pyc -------------------------------------------------------------------------------- /static/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /static/images/product-details/Bale.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/product-details/Bale.png -------------------------------------------------------------------------------- /static/images/product-details/Main.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/product-details/Main.psd -------------------------------------------------------------------------------- /static/images/product-details/new.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/product-details/new.jpg -------------------------------------------------------------------------------- /static/images/product-details/new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/product-details/new.png -------------------------------------------------------------------------------- /static/images/product-details/share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/product-details/share.png -------------------------------------------------------------------------------- /polls/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/polls/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /static/images/product-details/Similar.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/product-details/Similar.psd -------------------------------------------------------------------------------- /static/images/product-details/Socials.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/product-details/Socials.psd -------------------------------------------------------------------------------- /static/images/product-details/Soroush.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/product-details/Soroush.png -------------------------------------------------------------------------------- /static/images/product-details/rating.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/product-details/rating.png -------------------------------------------------------------------------------- /utils/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/utils/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /home_module/__pycache__/admin.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/home_module/__pycache__/admin.cpython-39.pyc -------------------------------------------------------------------------------- /home_module/__pycache__/apps.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/home_module/__pycache__/apps.cpython-39.pyc -------------------------------------------------------------------------------- /home_module/__pycache__/urls.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/home_module/__pycache__/urls.cpython-39.pyc -------------------------------------------------------------------------------- /home_module/__pycache__/views.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/home_module/__pycache__/views.cpython-39.pyc -------------------------------------------------------------------------------- /order_module/__pycache__/apps.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/order_module/__pycache__/apps.cpython-39.pyc -------------------------------------------------------------------------------- /order_module/__pycache__/urls.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/order_module/__pycache__/urls.cpython-39.pyc -------------------------------------------------------------------------------- /site_module/__pycache__/admin.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/site_module/__pycache__/admin.cpython-39.pyc -------------------------------------------------------------------------------- /site_module/__pycache__/apps.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/site_module/__pycache__/apps.cpython-39.pyc -------------------------------------------------------------------------------- /static/images/product-details/Instagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/product-details/Instagram.png -------------------------------------------------------------------------------- /static/images/product-details/Telegram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/product-details/Telegram.png -------------------------------------------------------------------------------- /static/images/product-details/similar1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/product-details/similar1.jpg -------------------------------------------------------------------------------- /static/images/product-details/similar2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/product-details/similar2.jpg -------------------------------------------------------------------------------- /static/images/product-details/similar3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/images/product-details/similar3.jpg -------------------------------------------------------------------------------- /utils/__pycache__/convertors.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/utils/__pycache__/convertors.cpython-39.pyc -------------------------------------------------------------------------------- /account_module/__pycache__/apps.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/account_module/__pycache__/apps.cpython-39.pyc -------------------------------------------------------------------------------- /account_module/__pycache__/urls.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/account_module/__pycache__/urls.cpython-39.pyc -------------------------------------------------------------------------------- /article_module/__pycache__/apps.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/article_module/__pycache__/apps.cpython-39.pyc -------------------------------------------------------------------------------- /article_module/__pycache__/urls.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/article_module/__pycache__/urls.cpython-39.pyc -------------------------------------------------------------------------------- /contact_module/__pycache__/apps.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/contact_module/__pycache__/apps.cpython-39.pyc -------------------------------------------------------------------------------- /contact_module/__pycache__/urls.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/contact_module/__pycache__/urls.cpython-39.pyc -------------------------------------------------------------------------------- /eshop_project/__pycache__/urls.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/eshop_project/__pycache__/urls.cpython-39.pyc -------------------------------------------------------------------------------- /eshop_project/__pycache__/wsgi.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/eshop_project/__pycache__/wsgi.cpython-39.pyc -------------------------------------------------------------------------------- /home_module/__pycache__/models.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/home_module/__pycache__/models.cpython-39.pyc -------------------------------------------------------------------------------- /order_module/__pycache__/admin.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/order_module/__pycache__/admin.cpython-39.pyc -------------------------------------------------------------------------------- /order_module/__pycache__/models.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/order_module/__pycache__/models.cpython-39.pyc -------------------------------------------------------------------------------- /order_module/__pycache__/views.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/order_module/__pycache__/views.cpython-39.pyc -------------------------------------------------------------------------------- /product_module/__pycache__/apps.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/product_module/__pycache__/apps.cpython-39.pyc -------------------------------------------------------------------------------- /product_module/__pycache__/urls.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/product_module/__pycache__/urls.cpython-39.pyc -------------------------------------------------------------------------------- /site_module/__pycache__/models.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/site_module/__pycache__/models.cpython-39.pyc -------------------------------------------------------------------------------- /static/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/static/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /utils/__pycache__/email_service.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/utils/__pycache__/email_service.cpython-39.pyc -------------------------------------------------------------------------------- /utils/__pycache__/http_service.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/utils/__pycache__/http_service.cpython-39.pyc -------------------------------------------------------------------------------- /account_module/__pycache__/admin.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/account_module/__pycache__/admin.cpython-39.pyc -------------------------------------------------------------------------------- /account_module/__pycache__/forms.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/account_module/__pycache__/forms.cpython-39.pyc -------------------------------------------------------------------------------- /account_module/__pycache__/models.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/account_module/__pycache__/models.cpython-39.pyc -------------------------------------------------------------------------------- /account_module/__pycache__/views.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/account_module/__pycache__/views.cpython-39.pyc -------------------------------------------------------------------------------- /article_module/__pycache__/admin.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/article_module/__pycache__/admin.cpython-39.pyc -------------------------------------------------------------------------------- /article_module/__pycache__/models.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/article_module/__pycache__/models.cpython-39.pyc -------------------------------------------------------------------------------- /article_module/__pycache__/views.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/article_module/__pycache__/views.cpython-39.pyc -------------------------------------------------------------------------------- /contact_module/__pycache__/admin.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/contact_module/__pycache__/admin.cpython-39.pyc -------------------------------------------------------------------------------- /contact_module/__pycache__/forms.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/contact_module/__pycache__/forms.cpython-39.pyc -------------------------------------------------------------------------------- /contact_module/__pycache__/models.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/contact_module/__pycache__/models.cpython-39.pyc -------------------------------------------------------------------------------- /contact_module/__pycache__/views.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/contact_module/__pycache__/views.cpython-39.pyc -------------------------------------------------------------------------------- /eshop_project/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/eshop_project/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /eshop_project/__pycache__/settings.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/eshop_project/__pycache__/settings.cpython-39.pyc -------------------------------------------------------------------------------- /home_module/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/home_module/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /order_module/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/order_module/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /product_module/__pycache__/admin.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/product_module/__pycache__/admin.cpython-39.pyc -------------------------------------------------------------------------------- /product_module/__pycache__/models.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/product_module/__pycache__/models.cpython-39.pyc -------------------------------------------------------------------------------- /product_module/__pycache__/views.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/product_module/__pycache__/views.cpython-39.pyc -------------------------------------------------------------------------------- /site_module/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/site_module/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /user_panel_module/__pycache__/apps.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/user_panel_module/__pycache__/apps.cpython-39.pyc -------------------------------------------------------------------------------- /user_panel_module/__pycache__/urls.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/user_panel_module/__pycache__/urls.cpython-39.pyc -------------------------------------------------------------------------------- /account_module/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/account_module/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /article_module/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/article_module/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /contact_module/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/contact_module/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /product_module/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/product_module/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /user_panel_module/__pycache__/admin.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/user_panel_module/__pycache__/admin.cpython-39.pyc -------------------------------------------------------------------------------- /user_panel_module/__pycache__/forms.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/user_panel_module/__pycache__/forms.cpython-39.pyc -------------------------------------------------------------------------------- /user_panel_module/__pycache__/models.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/user_panel_module/__pycache__/models.cpython-39.pyc -------------------------------------------------------------------------------- /user_panel_module/__pycache__/views.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/user_panel_module/__pycache__/views.cpython-39.pyc -------------------------------------------------------------------------------- /account_module/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from . import models 3 | 4 | # Register your models here. 5 | 6 | admin.site.register(models.User) 7 | -------------------------------------------------------------------------------- /media/cache/94/1b/941b13009bd5ae011fbe01ddeb3e3aee.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/media/cache/94/1b/941b13009bd5ae011fbe01ddeb3e3aee.jpg -------------------------------------------------------------------------------- /media/cache/b2/97/b297c80c91dddc1b6c35e13cf2e0eaa5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/media/cache/b2/97/b297c80c91dddc1b6c35e13cf2e0eaa5.jpg -------------------------------------------------------------------------------- /media/cache/e0/20/e02002d56d4f44121a199ac771292f12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/media/cache/e0/20/e02002d56d4f44121a199ac771292f12.jpg -------------------------------------------------------------------------------- /media/cache/ee/76/ee76a2cdb70f68737ded7741c45cb67a.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/media/cache/ee/76/ee76a2cdb70f68737ded7741c45cb67a.jpg -------------------------------------------------------------------------------- /polls/templatetags/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/polls/templatetags/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /user_panel_module/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/user_panel_module/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /contact_module/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from . import models 3 | 4 | # Register your models here. 5 | 6 | admin.site.register(models.ContactUs) 7 | -------------------------------------------------------------------------------- /polls/templatetags/__pycache__/poll_extras.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdiparsa76/Django-Shop/HEAD/polls/templatetags/__pycache__/poll_extras.cpython-39.pyc -------------------------------------------------------------------------------- /polls/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class PollsConfig(AppConfig): 5 | default_auto_field = 'django.db.models.BigAutoField' 6 | name = 'polls' 7 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | asgiref 2 | Django 3 | django-jalali-date 4 | django-render-partial 5 | jdatetime 6 | Pillow 7 | pytz 8 | sorl-thumbnail 9 | sqlparse 10 | typing-extensions 11 | -------------------------------------------------------------------------------- /home_module/templates/home_module/contact_page.html: -------------------------------------------------------------------------------- 1 | {% extends 'shared/_layout.html' %} 2 | 3 | {% block content %} 4 |

5 | صفحه ی تماس با ما 6 |

7 | {% endblock %} -------------------------------------------------------------------------------- /home_module/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class HomeModuleConfig(AppConfig): 5 | default_auto_field = 'django.db.models.BigAutoField' 6 | name = 'home_module' 7 | -------------------------------------------------------------------------------- /order_module/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from . import views 3 | 4 | urlpatterns = [ 5 | path('add-to-order', views.add_product_to_order, name='add_product_to_order') 6 | ] 7 | -------------------------------------------------------------------------------- /order_module/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from . import models 3 | 4 | # Register your models here. 5 | 6 | admin.site.register(models.Order) 7 | admin.site.register(models.OrderDetail) 8 | -------------------------------------------------------------------------------- /user_panel_module/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class UserPanelModuleConfig(AppConfig): 5 | default_auto_field = 'django.db.models.BigAutoField' 6 | name = 'user_panel_module' 7 | -------------------------------------------------------------------------------- /utils/convertors.py: -------------------------------------------------------------------------------- 1 | def group_list(custom_list, size=4): 2 | grouped_list = [] 3 | for i in range(0, len(custom_list), size): 4 | grouped_list.append(custom_list[i:i + size]) 5 | return grouped_list 6 | -------------------------------------------------------------------------------- /article_module/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class ArticleModuleConfig(AppConfig): 5 | default_auto_field = 'django.db.models.BigAutoField' 6 | name = 'article_module' 7 | verbose_name = 'ماژول مقالات' 8 | -------------------------------------------------------------------------------- /home_module/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from . import views 3 | 4 | urlpatterns = [ 5 | path('', views.HomeView.as_view(), name='home_page'), 6 | path('about-us', views.AboutView.as_view(), name='about_page'), 7 | ] 8 | -------------------------------------------------------------------------------- /order_module/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class OrderModuleConfig(AppConfig): 5 | default_auto_field = 'django.db.models.BigAutoField' 6 | name = 'order_module' 7 | verbose_name = 'ماژول سبد خرید' 8 | -------------------------------------------------------------------------------- /site_module/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class SiteModuleConfig(AppConfig): 5 | default_auto_field = 'django.db.models.BigAutoField' 6 | name = 'site_module' 7 | verbose_name = 'ماژول تنظیمات سایت' 8 | -------------------------------------------------------------------------------- /account_module/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class AccountModuleConfig(AppConfig): 5 | default_auto_field = 'django.db.models.BigAutoField' 6 | name = 'account_module' 7 | verbose_name = 'ماژول کاربران' 8 | -------------------------------------------------------------------------------- /contact_module/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class ContactModuleConfig(AppConfig): 5 | default_auto_field = 'django.db.models.BigAutoField' 6 | name = 'contact_module' 7 | verbose_name = 'ماژول تماس با ما' 8 | -------------------------------------------------------------------------------- /product_module/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class ProductModuleConfig(AppConfig): 5 | default_auto_field = 'django.db.models.BigAutoField' 6 | name = 'product_module' 7 | verbose_name = 'ماژول محصولات' 8 | -------------------------------------------------------------------------------- /static/css/custom.css: -------------------------------------------------------------------------------- 1 | .errorlist { 2 | padding-right: 0 !important; 3 | } 4 | 5 | .errorlist li { 6 | color: red; 7 | } 8 | 9 | ul { 10 | padding-right: 0; 11 | } 12 | 13 | .cursor-pointer { 14 | cursor: pointer; 15 | } -------------------------------------------------------------------------------- /templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {% block title %}{% endblock %} 7 | 8 | 9 | 10 | {% block content %}{% endblock %} 11 | 12 | -------------------------------------------------------------------------------- /utils/http_service.py: -------------------------------------------------------------------------------- 1 | from django.http import HttpRequest 2 | 3 | 4 | def get_client_ip(request: HttpRequest): 5 | x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') 6 | if x_forwarded_for: 7 | ip = x_forwarded_for.split(',')[0] 8 | else: 9 | ip = request.META.get('REMOTE_ADDR') 10 | return ip 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Django-Shop 2 | فروشگاه اینترنتی بر پایه فریمورک جنگو و طراحی قالب سایت با استفاده از بوت استرپ 4 3 | 4 | # ویژگی ها 5 | 6 | - جستجوی پیشرفته به کمک فیلتر قیمت 7 | - مرتب سازی بر اساس بازدید،فروش و ... 8 | - دسته بندی محصولات و نمایش محصولات مشابه 9 | - امکان مقایسه محصولات 10 | - شخصی سازی پنل ادمین 11 | - پنل کاربری و سبد خرید 12 | -------------------------------------------------------------------------------- /contact_module/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from . import views 3 | 4 | urlpatterns = [ 5 | path('', views.ContactUsView.as_view(), name='contact_us_page'), 6 | path('create-profile/', views.CreateProfileView.as_view(), name='create_profile_page'), 7 | path('profiles/', views.ProfilesView.as_view(), name='profiles_page'), 8 | ] 9 | -------------------------------------------------------------------------------- /user_panel_module/templates/user_panel_module/user_basket.html: -------------------------------------------------------------------------------- 1 | {% extends 'shared/_layout.html' %} 2 | {% load poll_extras %} 3 | 4 | {% block title %} 5 | سبد خرید 6 | {% endblock %} 7 | 8 | {% block content %} 9 |
10 | {% include 'user_panel_module/user_basket_content.html' %} 11 |
12 | {% endblock %} -------------------------------------------------------------------------------- /templates/emails/activate_account.html: -------------------------------------------------------------------------------- 1 |
2 |

فعالسازی حساب کاربری

3 |
4 |

کاربر گرامی ، جهت فعالسازی حساب کاربری خود روی لینک زیر کلیک کنید

5 |

6 | فعالسازی 7 | حساب کاربری 8 |

9 |
-------------------------------------------------------------------------------- /templates/emails/forgot_password.html: -------------------------------------------------------------------------------- 1 |
2 |

بازیابی کلمه عبور

3 |
4 |

کاربر گرامی ، جهت بازیابی کلمه عبور حساب کاربری خود روی لینک زیر کلیک کنید

5 |

6 | فعالسازی 7 | بازیابی کلمه عبور 8 |

9 |
-------------------------------------------------------------------------------- /article_module/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from . import views 3 | 4 | urlpatterns = [ 5 | path('', views.ArticlesListView.as_view(), name='articles_list'), 6 | path('cat/', views.ArticlesListView.as_view(), name='articles_by_category_list'), 7 | path('/', views.ArticleDetailView.as_view(), name='articles_detail'), 8 | path('add-article-comment', views.add_article_comment, name='add_article_comment') 9 | ] 10 | -------------------------------------------------------------------------------- /templates/shared/footer_references.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /user_panel_module/templates/user_panel_module/components/user_panel_menu_component.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /eshop_project/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for eshop_project project. 3 | 4 | It exposes the ASGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.2/howto/deployment/asgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.asgi import get_asgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'eshop_project.settings') 15 | 16 | application = get_asgi_application() 17 | -------------------------------------------------------------------------------- /eshop_project/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for eshop_project project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'eshop_project.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /product_module/templates/product_module/components/product_brands_component.html: -------------------------------------------------------------------------------- 1 |
2 |

برنـد ها

3 |
4 | 10 |
11 |
-------------------------------------------------------------------------------- /product_module/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from . import views 3 | 4 | urlpatterns = [ 5 | path('', views.ProductListView.as_view(), name='product-list'), 6 | path('cat/', views.ProductListView.as_view(), name='product-categories-list'), 7 | path('brand/', views.ProductListView.as_view(), name='product-list-by-brands'), 8 | path('product-favorite', views.AddProductFavorite.as_view(), name='product-favorite'), 9 | path('', views.ProductDetailView.as_view(), name='product-detail'), 10 | ] 11 | -------------------------------------------------------------------------------- /utils/email_service.py: -------------------------------------------------------------------------------- 1 | from django.core.mail import send_mail 2 | from django.template.loader import render_to_string 3 | from django.utils.html import strip_tags 4 | from django.conf import settings 5 | 6 | 7 | def send_email(subject, to, context, template_name): 8 | try: 9 | html_message = render_to_string(template_name, context) 10 | plain_message = strip_tags(html_message) 11 | from_email = settings.EMAIL_HOST_USER 12 | send_mail(subject, plain_message, from_email, [to], html_message=html_message) 13 | except: 14 | pass 15 | -------------------------------------------------------------------------------- /product_module/templates/product_module/components/product_categories_component.html: -------------------------------------------------------------------------------- 1 |

دسته بندی محصولات

2 |
3 | {% for category in categories %} 4 |
5 | 9 |
10 | {% endfor %} 11 |
12 | -------------------------------------------------------------------------------- /user_panel_module/templates/user_panel_module/user_panel_dashboard_page.html: -------------------------------------------------------------------------------- 1 | {% extends 'shared/_layout.html' %} 2 | {% load render_partial %} 3 | 4 | {% block title %} 5 | داشبورد 6 | {% endblock %} 7 | 8 | {% block content %} 9 |
10 |
11 |
12 | {% render_partial 'user_panel_module.views.user_panel_menu_component' %} 13 |
14 |
15 |

this is user dashboard

16 |
17 |
18 |
19 | {% endblock %} -------------------------------------------------------------------------------- /product_module/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from . import models 3 | 4 | 5 | # Register your models here. 6 | 7 | class ProductAdmin(admin.ModelAdmin): 8 | list_filter = ['category', 'is_active'] 9 | list_display = ['title', 'price', 'is_active', 'is_delete'] 10 | list_editable = ['price', 'is_active'] 11 | 12 | 13 | admin.site.register(models.Product, ProductAdmin) 14 | admin.site.register(models.ProductCategory) 15 | admin.site.register(models.ProductTag) 16 | admin.site.register(models.ProductBrand) 17 | admin.site.register(models.ProductVisit) 18 | admin.site.register(models.ProductGallery) 19 | -------------------------------------------------------------------------------- /account_module/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from . import views 3 | 4 | urlpatterns = [ 5 | path('register', views.RegisterView.as_view(), name='register_page'), 6 | path('login', views.LoginView.as_view(), name='login_page'), 7 | path('logout', views.LogoutView.as_view(), name='logout_page'), 8 | path('forget-pass', views.ForgetPasswordView.as_view(), name='forget_password_page'), 9 | path('reset-pass/', views.ResetPasswordView.as_view(), name='reset_password_page'), 10 | path('activate-account/', views.ActivateAccountView.as_view(), name='activate_account'), 11 | ] 12 | -------------------------------------------------------------------------------- /user_panel_module/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from . import views 3 | 4 | urlpatterns = [ 5 | path('', views.UserPanelDashboardPage.as_view(), name='user_panel_dashboard'), 6 | path('change-pass', views.ChangePasswordPage.as_view(), name='change_password_page'), 7 | path('edit-profile', views.EditUserProfilePage.as_view(), name='edit_profile_page'), 8 | path('user-basket', views.user_basket, name='user_basket_page'), 9 | path('remove-order-detail', views.remove_order_detail, name='remove_order_detail_ajax'), 10 | path('change-order-detail', views.change_order_detail_count, name='change_order_detail_count_ajax'), 11 | ] 12 | -------------------------------------------------------------------------------- /contact_module/templates/contact_module/profiles_list_page.html: -------------------------------------------------------------------------------- 1 | {% extends 'shared/_layout.html' %} 2 | 3 | {% block title %} 4 | لیست پروفایل ها 5 | {% endblock %} 6 | 7 | {% block content %} 8 |
9 |
10 |
11 |
    12 | {% for profile in profiles %} 13 |
  • 14 | 15 |
  • 16 | {% endfor %} 17 | 18 |
19 |
20 |
21 |
22 | {% endblock %} -------------------------------------------------------------------------------- /site_module/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from . import models 3 | 4 | 5 | class FooterLinkAdmin(admin.ModelAdmin): 6 | list_display = ['title', 'url'] 7 | 8 | 9 | class SliderAdmin(admin.ModelAdmin): 10 | list_display = ['title', 'url', 'is_active'] 11 | list_editable = ['url', 'is_active'] 12 | 13 | 14 | class SiteBannerAdmin(admin.ModelAdmin): 15 | list_display = ['title', 'url', 'position'] 16 | 17 | 18 | admin.site.register(models.SiteSetting) 19 | admin.site.register(models.FooterLinkBox) 20 | admin.site.register(models.Slider, SliderAdmin) 21 | admin.site.register(models.FooterLink, FooterLinkAdmin) 22 | admin.site.register(models.SiteBanner, SiteBannerAdmin) 23 | -------------------------------------------------------------------------------- /polls/templatetags/poll_extras.py: -------------------------------------------------------------------------------- 1 | from django import template 2 | from jalali_date import date2jalali 3 | 4 | register = template.Library() 5 | 6 | 7 | @register.filter(name='cut') 8 | def cut(value, arg): 9 | """Removes all values of arg from the given string""" 10 | return value.replace(arg, '') 11 | 12 | 13 | @register.filter(name='show_jalali_date') 14 | def show_jalali_date(value): 15 | return date2jalali(value) 16 | 17 | 18 | @register.filter(name='three_digits_currency') 19 | def three_digits_currency(value: int): 20 | return '{:,}'.format(value) + ' تومان' 21 | 22 | 23 | @register.simple_tag 24 | def multiply(quantity, price, *args, **kwargs): 25 | return three_digits_currency(quantity * price) 26 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | """Run administrative tasks.""" 9 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'eshop_project.settings') 10 | try: 11 | from django.core.management import execute_from_command_line 12 | except ImportError as exc: 13 | raise ImportError( 14 | "Couldn't import Django. Are you sure it's installed and " 15 | "available on your PYTHONPATH environment variable? Did you " 16 | "forget to activate a virtual environment?" 17 | ) from exc 18 | execute_from_command_line(sys.argv) 19 | 20 | 21 | if __name__ == '__main__': 22 | main() 23 | -------------------------------------------------------------------------------- /templates/shared/_layout.html: -------------------------------------------------------------------------------- 1 | {% load render_partial %} 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | {% block title %}{% endblock %} 10 | {% include 'shared/header_references.html' %} 11 | {% block header_references %}{% endblock %} 12 | 13 | 14 | {% render_partial 'home_module.views.site_header_component' %} 15 | {% block content %}{% endblock %} 16 | {% render_partial 'home_module.views.site_footer_component' %} 17 | {% include 'shared/footer_references.html' %} 18 | {% block footer_references %}{% endblock %} 19 | 20 | -------------------------------------------------------------------------------- /account_module/models.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.models import AbstractUser 2 | from django.db import models 3 | 4 | 5 | # Create your models here. 6 | 7 | class User(AbstractUser): 8 | avatar = models.ImageField(upload_to='images/profile', verbose_name='تصویر آواتار', null=True, blank=True) 9 | email_active_code = models.CharField(max_length=100, verbose_name='کد فعالسازی ایمیل') 10 | about_user = models.TextField(null=True, blank=True, verbose_name='درباره شخص') 11 | address = models.TextField(null=True, blank=True, verbose_name='آدرس') 12 | 13 | class Meta: 14 | verbose_name = 'کاربر' 15 | verbose_name_plural = 'کاربران' 16 | 17 | def __str__(self): 18 | if self.first_name is not '' and self.last_name is not '': 19 | return self.get_full_name() 20 | 21 | return self.email 22 | -------------------------------------------------------------------------------- /contact_module/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | 4 | # Create your models here. 5 | 6 | class ContactUs(models.Model): 7 | title = models.CharField(max_length=300, verbose_name='عنوان') 8 | email = models.EmailField(max_length=300, verbose_name='ایمیل') 9 | full_name = models.CharField(max_length=300, verbose_name='نام و نام خانوادگی') 10 | message = models.TextField(verbose_name='متن تماس با ما') 11 | created_date = models.DateTimeField(verbose_name='تاریخ ایجاد', auto_now_add=True) 12 | response = models.TextField(verbose_name='متن پاسخ تماس با ما', null=True, blank=True) 13 | is_read_by_admin = models.BooleanField(verbose_name='خوانده شده توسط ادمین', default=False) 14 | 15 | class Meta: 16 | verbose_name = 'تماس با ما' 17 | verbose_name_plural = 'لیست تماس با ما' 18 | 19 | def __str__(self): 20 | return self.title 21 | 22 | 23 | class UserProfile(models.Model): 24 | image = models.ImageField(upload_to='images') 25 | -------------------------------------------------------------------------------- /article_module/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from django.http import HttpRequest 3 | 4 | from . import models 5 | 6 | # Register your models here. 7 | from .models import Article 8 | 9 | 10 | class ArticleCategoryAdmin(admin.ModelAdmin): 11 | list_display = ['title', 'url_title', 'parent', 'is_active'] 12 | list_editable = ['url_title', 'parent', 'is_active'] 13 | 14 | 15 | class ArticleAdmin(admin.ModelAdmin): 16 | list_display = ['title', 'slug', 'is_active', 'author'] 17 | list_editable = ['is_active'] 18 | 19 | def save_model(self, request: HttpRequest, obj: Article, form, change): 20 | if not change: 21 | obj.author = request.user 22 | return super().save_model(request, obj, form, change) 23 | 24 | 25 | class ArticleCommentAdmin(admin.ModelAdmin): 26 | list_display = ['user', 'create_date', 'parent'] 27 | 28 | 29 | admin.site.register(models.ArticleCategory, ArticleCategoryAdmin) 30 | admin.site.register(models.Article, ArticleAdmin) 31 | admin.site.register(models.ArticleComment, ArticleCommentAdmin) 32 | -------------------------------------------------------------------------------- /user_panel_module/templates/user_panel_module/edit_profile_page.html: -------------------------------------------------------------------------------- 1 | {% extends 'shared/_layout.html' %} 2 | {% load render_partial %} 3 | 4 | {% block title %} 5 | ویرایش اطلاعات کاربری 6 | {% endblock %} 7 | 8 | {% block content %} 9 |
10 |
11 |
12 | {% if current_user.avatar %} 13 | 14 | 15 | 16 | {% endif %} 17 | {% render_partial 'user_panel_module.views.user_panel_menu_component' %} 18 |
19 |
20 |
21 | {% csrf_token %} 22 | {{ form.as_p }} 23 | 24 |
25 |
26 |
27 |
28 | {% endblock %} -------------------------------------------------------------------------------- /account_module/templates/account_module/forgot_password.html: -------------------------------------------------------------------------------- 1 | {% extends 'shared/_layout.html' %} 2 | 3 | {% block title %}فراموشی کلمه عبور{% endblock %} 4 | 5 | {% block content %} 6 |
7 |
8 |
9 |
10 | 23 |
24 |
25 |
26 |
27 | {% endblock %} -------------------------------------------------------------------------------- /contact_module/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | from .models import ContactUs 3 | 4 | 5 | class ContactUsModelForm(forms.ModelForm): 6 | class Meta: 7 | model = ContactUs 8 | fields = ['full_name', 'email', 'title', 'message'] 9 | widgets = { 10 | 'full_name': forms.TextInput(attrs={ 11 | 'class': 'form-control' 12 | }), 13 | 'email': forms.TextInput(attrs={ 14 | 'class': 'form-control' 15 | }), 16 | 'title': forms.TextInput(attrs={ 17 | 'class': 'form-control' 18 | }), 19 | 'message': forms.Textarea(attrs={ 20 | 'class': 'form-control', 21 | 'rows': 5, 22 | 'id': 'message' 23 | }) 24 | } 25 | 26 | labels = { 27 | 'full_name': 'نام و نام خانوادگی شما', 28 | 'email': 'ایمیل شما' 29 | } 30 | 31 | error_messages = { 32 | 'full_name': { 33 | 'required': 'نام و نام خانوادگی اجباری می باشد. لطفا وارد کنید' 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /templates/shared/header_references.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 13 | 14 | 16 | 18 | 20 | -------------------------------------------------------------------------------- /contact_module/views.py: -------------------------------------------------------------------------------- 1 | from django.views.generic import ListView 2 | 3 | from site_module.models import SiteSetting 4 | from .forms import ContactUsModelForm 5 | from django.views.generic.edit import CreateView 6 | 7 | from .models import UserProfile 8 | 9 | 10 | class ContactUsView(CreateView): 11 | form_class = ContactUsModelForm 12 | template_name = 'contact_module/contact_us_page.html' 13 | success_url = '/contact-us/' 14 | 15 | def get_context_data(self, *args, **kwargs): 16 | context = super().get_context_data(*args, **kwargs) 17 | setting: SiteSetting = SiteSetting.objects.filter(is_main_setting=True).first() 18 | context['site_setting'] = setting 19 | 20 | return context 21 | 22 | 23 | def store_file(file): 24 | with open('temp/image.jpg', "wb+") as dest: 25 | for chunk in file.chunks(): 26 | dest.write(chunk) 27 | 28 | 29 | class CreateProfileView(CreateView): 30 | template_name = 'contact_module/create_profile_page.html' 31 | model = UserProfile 32 | fields = '__all__' 33 | success_url = '/contact-us/create-profile' 34 | 35 | 36 | class ProfilesView(ListView): 37 | model = UserProfile 38 | template_name = 'contact_module/profiles_list_page.html' 39 | context_object_name = 'profiles' 40 | -------------------------------------------------------------------------------- /user_panel_module/templates/user_panel_module/change_password_page.html: -------------------------------------------------------------------------------- 1 | {% extends 'shared/_layout.html' %} 2 | {% load render_partial %} 3 | 4 | {% block title %} 5 | تغییر کلمه عبور 6 | {% endblock %} 7 | 8 | {% block content %} 9 |
10 |
11 |
12 | {% render_partial 'user_panel_module.views.user_panel_menu_component' %} 13 |
14 |
15 | {% comment %}{% if form.errors %} 16 | {% for field in form.fields %} 17 | {% for error in field.error %} 18 |
19 | {{ error|escape }} 20 |
21 | {% endfor %} 22 | 23 | {% endfor %} 24 | 25 | {% endif %}{% endcomment %} 26 |
27 | {% csrf_token %} 28 | {{ form.as_p }} 29 | 30 |
31 |
32 |
33 |
34 | {% endblock %} -------------------------------------------------------------------------------- /account_module/templates/account_module/reset_password.html: -------------------------------------------------------------------------------- 1 | {% extends 'shared/_layout.html' %} 2 | 3 | {% block title %}بازیابی کلمه عبور{% endblock %} 4 | 5 | {% block content %} 6 |
7 |
8 |
9 |
10 | 27 |
28 |
29 |
30 |
31 | {% endblock %} -------------------------------------------------------------------------------- /account_module/templates/account_module/login.html: -------------------------------------------------------------------------------- 1 | {% extends 'shared/_layout.html' %} 2 | 3 | {% block title %}ورود{% endblock %} 4 | 5 | {% block content %} 6 |
7 |
8 |
9 |
10 | 27 |
28 |
29 |
30 |
31 | {% endblock %} -------------------------------------------------------------------------------- /eshop_project/urls.py: -------------------------------------------------------------------------------- 1 | """eshop_project URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/3.2/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: path('', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.urls import include, path 14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 15 | """ 16 | from django.contrib import admin 17 | from django.urls import path, include 18 | from django.conf.urls.static import static 19 | from django.conf import settings 20 | 21 | urlpatterns = [ 22 | path('', include('home_module.urls')), 23 | path('', include('account_module.urls')), 24 | path('articles/', include('article_module.urls')), 25 | path('contact-us/', include('contact_module.urls')), 26 | path('products/', include('product_module.urls')), 27 | path('user/', include('user_panel_module.urls')), 28 | path('order/', include('order_module.urls')), 29 | path('admin/', admin.site.urls), 30 | ] 31 | 32 | urlpatterns = urlpatterns + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) 33 | -------------------------------------------------------------------------------- /order_module/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from account_module.models import User 3 | from product_module.models import Product 4 | 5 | 6 | # Create your models here. 7 | 8 | class Order(models.Model): 9 | user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='کاربر') 10 | is_paid = models.BooleanField(verbose_name='نهایی شده/نشده') 11 | payment_date = models.DateField(null=True, blank=True, verbose_name='تاریخ پرداخت') 12 | 13 | def __str__(self): 14 | return str(self.user) 15 | 16 | def calculate_total_price(self): 17 | total_amount = 0 18 | if self.is_paid: 19 | for order_detail in self.orderdetail_set.all(): 20 | total_amount += order_detail.final_price * order_detail.count 21 | else: 22 | for order_detail in self.orderdetail_set.all(): 23 | total_amount += order_detail.product.price * order_detail.count 24 | 25 | return total_amount 26 | 27 | class Meta: 28 | verbose_name = 'سبد خرید' 29 | verbose_name_plural = 'سبدهای خرید کاربران' 30 | 31 | 32 | class OrderDetail(models.Model): 33 | order = models.ForeignKey(Order, on_delete=models.CASCADE, verbose_name='سبد خرید') 34 | product = models.ForeignKey(Product, on_delete=models.CASCADE, verbose_name='محصول') 35 | final_price = models.IntegerField(null=True, blank=True, verbose_name='قیمت نهایی تکی محصول') 36 | count = models.IntegerField(verbose_name='تعداد') 37 | 38 | def get_total_price(self): 39 | return self.count * self.product.price 40 | 41 | def __str__(self): 42 | return str(self.order) 43 | 44 | class Meta: 45 | verbose_name = 'جزییات سبد خرید' 46 | verbose_name_plural = 'لیست جزییات سبدهای خرید' 47 | -------------------------------------------------------------------------------- /article_module/templates/article_module/components/article_categories_component.html: -------------------------------------------------------------------------------- 1 |

دسته بندی مقالات

2 |
3 | 4 | 5 | {% for main_category in main_categories %} 6 |
7 |
8 |

9 | {% if main_category.articlecategory_set.all %} 10 | 11 | 12 | {{ main_category.title }} 13 | 14 | 15 | {% else %} 16 | 17 | {{ main_category.title }} 18 | 19 | {% endif %} 20 |

21 |
22 | {% if main_category.articlecategory_set.all %} 23 |
24 |
25 | 31 |
32 |
33 | {% endif %} 34 |
35 | {% endfor %} 36 | 37 | 38 |
39 | -------------------------------------------------------------------------------- /account_module/templates/account_module/register.html: -------------------------------------------------------------------------------- 1 | {% extends 'shared/_layout.html' %} 2 | 3 | {% block title %}ثبت نام{% endblock %} 4 | 5 | {% block content %} 6 |
7 |
8 |
9 |
10 | 35 |
36 |
37 |
38 |
39 | {% endblock %} -------------------------------------------------------------------------------- /product_module/templates/includes/product_item_partial.html: -------------------------------------------------------------------------------- 1 | {% load thumbnail %} 2 | {% load poll_extras %} 3 | 4 |
5 |
6 |
7 |
8 | {% if product.image %} 9 | {% thumbnail product.image "268x250" quality=90 crop='center' as im %} 10 | 11 | {% endthumbnail %} 12 | {% else %} 13 | 14 | {% endif %} 15 |

{{ product.price|three_digits_currency }}

16 |

{{ product.title }}

17 | افزودن به سبـد خریـد 19 |
20 |
21 |
22 |

{{ product.price|three_digits_currency }} تومان

23 |

{{ product.title }}

24 | افزودن به سبـد خریـد 26 |
27 |
28 |
29 |
30 | 41 |
42 |
43 |
-------------------------------------------------------------------------------- /contact_module/templates/contact_module/create_profile_page.html: -------------------------------------------------------------------------------- 1 | {% extends 'shared/_layout.html' %} 2 | 3 | {% block title %} 4 | تماس با ما 5 | {% endblock %} 6 | 7 | {% block content %} 8 |
9 |
10 |
11 |
12 |
13 |

ثبت پروفایل

14 | 15 |
17 | {% csrf_token %} 18 | {{ form }} 19 |
20 | 21 |
22 |
23 |
24 |
25 |
26 |
27 |

اطلاعات تماس

28 |
29 |

گـروه تکنوگـرافی 1614

30 |

ایـران - آذربایجـان غربـی - خـوی

31 |

مجتـمع تجـاری تفریحـی شمس - طبـقه 2 - پلاک 54

32 |

تلفن تماس : 80 21 24 36 044

33 |

فکس : 80 21 24 36 044

34 |

ایمیـل : info@1614GP.ir

35 |
36 |
37 |
38 |
39 |
40 |
41 | {% endblock %} -------------------------------------------------------------------------------- /static/js/contact.js: -------------------------------------------------------------------------------- 1 | jQuery(function($) {'use strict', 2 | 3 | var form = $('.contact_module-form'); 4 | form.submit(function () {'use strict', 5 | $this = $(this); 6 | $.post("sendemail.php", $(".contact_module-form").serialize(),function(result){ 7 | if(result.type == 'success'){ 8 | $this.prev().text(result.message).fadeIn().delay(3000).fadeOut(); 9 | } 10 | }); 11 | return false; 12 | }); 13 | 14 | }); 15 | 16 | // Google Map Customization 17 | (function(){ 18 | 19 | var map; 20 | 21 | map = new GMaps({ 22 | el: '#gmap', 23 | lat: 43.1580159, 24 | lng: -77.6030777, 25 | scrollwheel:false, 26 | zoom: 14, 27 | zoomControl : false, 28 | panControl : false, 29 | streetViewControl : false, 30 | mapTypeControl: false, 31 | overviewMapControl: false, 32 | clickable: false 33 | }); 34 | 35 | var image = 'images/map-icon.png'; 36 | map.addMarker({ 37 | lat: 43.1580159, 38 | lng: -77.6030777, 39 | // icon: image, 40 | animation: google.maps.Animation.DROP, 41 | verticalAlign: 'bottom', 42 | horizontalAlign: 'center', 43 | backgroundColor: '#ffffff', 44 | }); 45 | 46 | var styles = [ 47 | 48 | { 49 | "featureType": "road", 50 | "stylers": [ 51 | { "color": "" } 52 | ] 53 | },{ 54 | "featureType": "water", 55 | "stylers": [ 56 | { "color": "#A2DAF2" } 57 | ] 58 | },{ 59 | "featureType": "landscape", 60 | "stylers": [ 61 | { "color": "#ABCE83" } 62 | ] 63 | },{ 64 | "elementType": "labels.text.fill", 65 | "stylers": [ 66 | { "color": "#000000" } 67 | ] 68 | },{ 69 | "featureType": "poi", 70 | "stylers": [ 71 | { "color": "#2ECC71" } 72 | ] 73 | },{ 74 | "elementType": "labels.text", 75 | "stylers": [ 76 | { "saturation": 1 }, 77 | { "weight": 0.1 }, 78 | { "color": "#111111" } 79 | ] 80 | } 81 | 82 | ]; 83 | 84 | map.addStyle({ 85 | styledMapName:"Styled Map", 86 | styles: styles, 87 | mapTypeId: "map_style" 88 | }); 89 | 90 | map.setStyle("map_style"); 91 | }()); -------------------------------------------------------------------------------- /static/js/jquery.scrollUp.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | scrollup v2.3.3 4 | Author: Mark Goodyear - http://markgoodyear.com 5 | Git: https://github.com/markgoodyear/scrollup 6 | 7 | Copyright 2014 Mark Goodyear. 8 | Licensed under the MIT license 9 | http://www.opensource.org/licenses/mit-license.php 10 | 11 | Twitter: @markgdyr 12 | 13 | */ 14 | !function(a,b,c){a.fn.scrollUp=function(b){a.data(c.body,"scrollUp")||(a.data(c.body,"scrollUp",!0),a.fn.scrollUp.init(b))},a.fn.scrollUp.init=function(d){var e,f=a.fn.scrollUp.settings=a.extend({},a.fn.scrollUp.defaults,d);e=f.scrollTrigger?a(f.scrollTrigger):a("",{id:f.scrollName,href:"#top"}),f.scrollTitle&&e.attr("title",f.scrollTitle),e.appendTo("body"),f.scrollImg||f.scrollTrigger||e.html(f.scrollText),e.css({display:"none",position:"fixed",zIndex:f.zIndex}),f.activeOverlay&&a("
",{id:f.scrollName+"-active"}).css({position:"absolute",top:f.scrollDistance+"px",width:"100%",borderTop:"1px dotted"+f.activeOverlay,zIndex:f.zIndex}).appendTo("body");var g,h,i,j;switch(f.animation){case"fade":g="fadeIn",h="fadeOut",i=f.animationSpeed;break;case"slide":g="slideDown",h="slideUp",i=f.animationSpeed;break;default:g="show",h="hide",i=0}j="top"===f.scrollFrom?f.scrollDistance:a(c).height()-a(b).height()-f.scrollDistance;var k=!1;scrollEvent=a(b).scroll(function(){a(b).scrollTop()>j?k||(e[g](i),k=!0):k&&(e[h](i),k=!1)});var l;f.scrollTarget?"number"==typeof f.scrollTarget?l=f.scrollTarget:"string"==typeof f.scrollTarget&&(l=Math.floor(a(f.scrollTarget).offset().top)):l=0,e.click(function(b){b.preventDefault(),a("html, body").animate({scrollTop:l},f.scrollSpeed,f.easingType)})},a.fn.scrollUp.defaults={scrollName:"scrollUp",scrollDistance:300,scrollFrom:"top",scrollSpeed:300,easingType:"linear",animation:"fade",animationSpeed:200,scrollTrigger:!1,scrollTarget:!1,scrollText:"Scroll to top",scrollTitle:!1,scrollImg:!1,activeOverlay:!1,zIndex:2147483647},a.fn.scrollUp.destroy=function(d){a.removeData(c.body,"scrollUp"),a("#"+a.fn.scrollUp.settings.scrollName).remove(),a("#"+a.fn.scrollUp.settings.scrollName+"-active").remove(),a.fn.jquery.split(".")[1]>=7?a(b).off("scroll",d):a(b).unbind("scroll",d)},a.scrollUp=a.fn.scrollUp}(jQuery,window,document); -------------------------------------------------------------------------------- /order_module/views.py: -------------------------------------------------------------------------------- 1 | from django.http import HttpRequest, JsonResponse 2 | from product_module.models import Product 3 | from .models import Order, OrderDetail 4 | 5 | 6 | # Create your views here. 7 | 8 | def add_product_to_order(request: HttpRequest): 9 | product_id = int(request.GET.get('product_id')) 10 | count = int(request.GET.get('count')) 11 | if count < 1: 12 | # count = 1 13 | return JsonResponse({ 14 | 'status': 'invalid_count', 15 | 'text': 'مقدار وارد شده معتبر نمی باشد', 16 | 'confirm_button_text': 'مرسی از شما', 17 | 'icon': 'warning' 18 | }) 19 | 20 | if request.user.is_authenticated: 21 | product = Product.objects.filter(id=product_id, is_active=True, is_delete=False).first() 22 | if product is not None: 23 | current_order, created = Order.objects.get_or_create(is_paid=False, user_id=request.user.id) 24 | current_order_detail = current_order.orderdetail_set.filter(product_id=product_id).first() 25 | if current_order_detail is not None: 26 | current_order_detail.count += count 27 | current_order_detail.save() 28 | else: 29 | new_detail = OrderDetail(order_id=current_order.id, product_id=product_id, count=count) 30 | new_detail.save() 31 | 32 | return JsonResponse({ 33 | 'status': 'success', 34 | 'text': 'محصول مورد نظر با موفقیت به سبد خرید شما اضافه شد', 35 | 'confirm_button_text': 'باشه ممنونم', 36 | 'icon': 'success' 37 | }) 38 | else: 39 | return JsonResponse({ 40 | 'status': 'not_found', 41 | 'text': 'محصول مورد نظر یافت نشد', 42 | 'confirm_button_text': 'مرسییییی', 43 | 'icon': 'error' 44 | }) 45 | else: 46 | return JsonResponse({ 47 | 'status': 'not_auth', 48 | 'text': 'برای افزودن محصول به سبد خرید ابتدا می بایست وارد سایت شوید', 49 | 'confirm_button_text': 'ورود به سایت', 50 | 'icon': 'error' 51 | }) 52 | -------------------------------------------------------------------------------- /article_module/templates/article_module/includes/article_comments_partial.html: -------------------------------------------------------------------------------- 1 | {% load poll_extras %} 2 | 3 |

نظرات ({{ comments_count }})

4 |
    5 | {% for comment in comments %} 6 |
  • 7 | 8 | 9 | 10 |
    11 | 18 |

    19 | {{ comment.text }} 20 |

    21 | پاسـخ 23 |
    24 |
  • 25 | 26 | {% for sub_comment in comment.articlecomment_set.all %} 27 |
  • 28 | 29 | 30 | 31 |
    32 | 40 |

    41 | {{ sub_comment.text }} 42 |

    43 |
    44 |
  • 45 | {% endfor %} 46 | {% endfor %} 47 | 48 |
-------------------------------------------------------------------------------- /static/js/html5shiv.js: -------------------------------------------------------------------------------- 1 | /* 2 | HTML5 Shiv v3.6.2pre | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed 3 | */ 4 | (function(l,f){function m(){var a=e.elements;return"string"==typeof a?a.split(" "):a}function i(a){var b=n[a[o]];b||(b={},h++,a[o]=h,n[h]=b);return b}function p(a,b,c){b||(b=f);if(g)return b.createElement(a);c||(c=i(b));b=c.cache[a]?c.cache[a].cloneNode():r.test(a)?(c.cache[a]=c.createElem(a)).cloneNode():c.createElem(a);return b.canHaveChildren&&!s.test(a)?c.frag.appendChild(b):b}function t(a,b){if(!b.cache)b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag(); 5 | a.createElement=function(c){return!e.shivMethods?b.createElem(c):p(c,a,b)};a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+m().join().replace(/\w+/g,function(a){b.createElem(a);b.frag.createElement(a);return'c("'+a+'")'})+");return n}")(e,b.frag)}function q(a){a||(a=f);var b=i(a);if(e.shivCSS&&!j&&!b.hasCSS){var c,d=a;c=d.createElement("p");d=d.getElementsByTagName("head")[0]||d.documentElement;c.innerHTML="x"; 6 | c=d.insertBefore(c.lastChild,d.firstChild);b.hasCSS=!!c}g||t(a,b);return a}var k=l.html5||{},s=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,r=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,j,o="_html5shiv",h=0,n={},g;(function(){try{var a=f.createElement("a");a.innerHTML="";j="hidden"in a;var b;if(!(b=1==a.childNodes.length)){f.createElement("a");var c=f.createDocumentFragment();b="undefined"==typeof c.cloneNode|| 7 | "undefined"==typeof c.createDocumentFragment||"undefined"==typeof c.createElement}g=b}catch(d){g=j=!0}})();var e={elements:k.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",version:"3.6.2pre",shivCSS:!1!==k.shivCSS,supportsUnknownElements:g,shivMethods:!1!==k.shivMethods,type:"default",shivDocument:q,createElement:p,createDocumentFragment:function(a,b){a||(a=f);if(g)return a.createDocumentFragment(); 8 | for(var b=b||i(a),c=b.frag.cloneNode(),d=0,e=m(),h=e.length;d 11 |
12 | 13 |
14 |
15 |
16 |

لوگـو شرکت

17 | 18 |
19 |
20 |
21 |
22 |

دربـاره ما

23 |

24 | {{ site_setting.about_us_text }} 25 |

26 |
27 |
28 |
29 | 30 |
31 |
32 |
33 |

34 | {{ site_setting.address }}| 35 | تلفن تماس : {{ site_setting.phone }} | 36 | {% if site_setting.fax %} 37 | فکس : {{ site_setting.fax }} | 38 | {% endif %} 39 | {% if site_setting.email %} 40 | ایمیـل : {{ site_setting.email }} 41 | {% endif %} 42 |

43 |
44 |
45 |
46 | 47 |
48 |
49 |

50 | مـا اینجـا هستیـم ...

51 |
52 | Map 53 |
54 |
55 |
56 |
57 | 58 |
59 |
60 | {% endblock %} -------------------------------------------------------------------------------- /static/js/main.js: -------------------------------------------------------------------------------- 1 | /*price range*/ 2 | 3 | $('#sl2').slider(); 4 | 5 | var RGBChange = function() { 6 | $('#RGB').css('background', 'rgb('+r.getValue()+','+g.getValue()+','+b.getValue()+')') 7 | }; 8 | 9 | /*scroll to top*/ 10 | 11 | $(document).ready(function(){ 12 | $(function () { 13 | $.scrollUp({ 14 | scrollName: 'scrollUp', // Element ID 15 | scrollDistance: 300, // Distance from top/bottom before showing element (px) 16 | scrollFrom: 'top', // 'top' or 'bottom' 17 | scrollSpeed: 300, // Speed back to top (ms) 18 | easingType: 'linear', // Scroll to top easing (see http://easings.net/) 19 | animation: 'fade', // Fade, slide, none 20 | animationSpeed: 200, // Animation in speed (ms) 21 | scrollTrigger: false, // Set a custom triggering element. Can be an HTML string or jQuery object 22 | //scrollTarget: false, // Set a custom target element for scrolling to the top 23 | scrollText: '', // Text for element, can contain HTML 24 | scrollTitle: false, // Set a custom title if required. 25 | scrollImg: false, // Set true to use image 26 | activeOverlay: false, // Set CSS color to display scrollUp active point, e.g '#00FFFF' 27 | zIndex: 2147483647 // Z-Index for the overlay 28 | }); 29 | }); 30 | }); 31 | 32 | 33 | 34 | 35 | function updatePrice(container, n) { 36 | //container -> each one of the $('.cd-gallery').children('li') 37 | //n -> index of the selected item in the .cd-item-wrapper 38 | var priceTag = container.find('.cd-price'), 39 | selectedItem = container.find('.cd-item-wrapper li').eq(n); 40 | if( selectedItem.data('sale') ) { 41 | // if item is on sale - cross old price and add new one 42 | priceTag.addClass('on-sale'); 43 | var newPriceTag = ( priceTag.next('.cd-new-price').length > 0 ) ? priceTag.next('.cd-new-price') : $('').insertAfter(priceTag); 44 | newPriceTag.text(selectedItem.data('price')); 45 | setTimeout(function(){ newPriceTag.addClass('is-visible'); }, 100); 46 | } else { 47 | // if item is not on sale - remove cross on old price and sale price 48 | priceTag.removeClass('on-sale').next('.cd-new-price').removeClass('is-visible').on('webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend', function(){ 49 | priceTag.next('.cd-new-price').remove(); 50 | }); 51 | } 52 | } -------------------------------------------------------------------------------- /static/lib/image-lightbox/css/lightbox.min.css: -------------------------------------------------------------------------------- 1 | .lb-loader,.lightbox{text-align:center;line-height:0;position:absolute;left:0}body.lb-disable-scrolling{overflow:hidden}.lightboxOverlay{position:absolute;top:0;left:0;z-index:9999;background-color:#000;filter:alpha(Opacity=80);opacity:.8;display:none}.lightbox{width:100%;z-index:10000;font-weight:400;outline:0}.lightbox .lb-image{display:block;height:auto;max-width:inherit;max-height:none;border-radius:3px;border:4px solid #fff}.lightbox a img{border:none}.lb-outerContainer{position:relative;width:250px;height:250px;margin:0 auto;border-radius:4px;background-color:#fff}.lb-outerContainer:after{content:"";display:table;clear:both}.lb-loader{top:43%;height:25%;width:100%}.lb-cancel{display:block;width:32px;height:32px;margin:0 auto;background:url(../images/loading.gif) no-repeat}.lb-nav{position:absolute;top:0;left:0;height:100%;width:100%;z-index:10}.lb-container>.nav{left:0}.lb-nav a{outline:0;background-image:url(data:image/gif;base64,R0lGODlhAQABAPAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==)}.lb-next,.lb-prev{height:100%;cursor:pointer;display:block}.lb-nav a.lb-prev{width:34%;left:0;float:left;background:url(../images/prev.png) left 48% no-repeat;filter:alpha(Opacity=0);opacity:0;-webkit-transition:opacity .6s;-moz-transition:opacity .6s;-o-transition:opacity .6s;transition:opacity .6s}.lb-nav a.lb-prev:hover{filter:alpha(Opacity=100);opacity:1}.lb-nav a.lb-next{width:64%;right:0;float:right;background:url(../images/next.png) right 48% no-repeat;filter:alpha(Opacity=0);opacity:0;-webkit-transition:opacity .6s;-moz-transition:opacity .6s;-o-transition:opacity .6s;transition:opacity .6s}.lb-nav a.lb-next:hover{filter:alpha(Opacity=100);opacity:1}.lb-dataContainer{margin:0 auto;padding-top:5px;width:100%;border-bottom-left-radius:4px;border-bottom-right-radius:4px}.lb-dataContainer:after{content:"";display:table;clear:both}.lb-data{padding:0 4px;color:#ccc}.lb-data .lb-details{width:85%;float:left;text-align:left;line-height:1.1em}.lb-data .lb-caption{font-size:13px;font-weight:700;line-height:1em}.lb-data .lb-caption a{color:#4ae}.lb-data .lb-number{display:block;clear:left;padding-bottom:1em;font-size:12px;color:#999}.lb-data .lb-close{display:block;float:right;width:30px;height:30px;background:url(../images/close.png) top right no-repeat;text-align:right;outline:0;filter:alpha(Opacity=70);opacity:.7;-webkit-transition:opacity .2s;-moz-transition:opacity .2s;-o-transition:opacity .2s;transition:opacity .2s}.lb-data .lb-close:hover{cursor:pointer;filter:alpha(Opacity=100);opacity:1} -------------------------------------------------------------------------------- /account_module/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | from django.core import validators 3 | from django.core.exceptions import ValidationError 4 | 5 | 6 | class RegisterForm(forms.Form): 7 | email = forms.EmailField( 8 | label='ایمیل', 9 | widget=forms.EmailInput(), 10 | validators=[ 11 | validators.MaxLengthValidator(100), 12 | validators.EmailValidator, 13 | ] 14 | ) 15 | password = forms.CharField( 16 | label='کلمه عبور', 17 | widget=forms.PasswordInput(), 18 | validators=[ 19 | validators.MaxLengthValidator(100), 20 | ] 21 | ) 22 | confirm_password = forms.CharField( 23 | label='تکرار کلمه عبور', 24 | widget=forms.PasswordInput(), 25 | validators=[ 26 | validators.MaxLengthValidator(100), 27 | ] 28 | ) 29 | 30 | def clean_confirm_password(self): 31 | password = self.cleaned_data.get('password') 32 | confirm_password = self.cleaned_data.get('confirm_password') 33 | 34 | if password == confirm_password: 35 | return confirm_password 36 | 37 | raise ValidationError('کلمه عبور و تکرار کلمه عبور مغایرت دارند') 38 | 39 | 40 | class LoginForm(forms.Form): 41 | email = forms.EmailField( 42 | label='ایمیل', 43 | widget=forms.EmailInput(), 44 | validators=[ 45 | validators.MaxLengthValidator(100), 46 | validators.EmailValidator 47 | ] 48 | ) 49 | password = forms.CharField( 50 | label='کلمه عبور', 51 | widget=forms.PasswordInput(), 52 | validators=[ 53 | validators.MaxLengthValidator(100) 54 | ] 55 | ) 56 | 57 | 58 | class ForgotPasswordForm(forms.Form): 59 | email = forms.EmailField( 60 | label='ایمیل', 61 | widget=forms.EmailInput(), 62 | validators=[ 63 | validators.MaxLengthValidator(100), 64 | validators.EmailValidator 65 | ] 66 | ) 67 | 68 | 69 | class ResetPasswordForm(forms.Form): 70 | password = forms.CharField( 71 | label='کلمه عبور', 72 | widget=forms.PasswordInput(), 73 | validators=[ 74 | validators.MaxLengthValidator(100), 75 | ] 76 | ) 77 | 78 | confirm_password = forms.CharField( 79 | label='تکرار کلمه عبور', 80 | widget=forms.PasswordInput(), 81 | validators=[ 82 | validators.MaxLengthValidator(100), 83 | ] 84 | ) 85 | -------------------------------------------------------------------------------- /article_module/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from jalali_date import date2jalali 3 | from account_module.models import User 4 | 5 | 6 | class ArticleCategory(models.Model): 7 | parent = models.ForeignKey('ArticleCategory', null=True, blank=True, on_delete=models.CASCADE, verbose_name='دسته بندی والد') 8 | title = models.CharField(max_length=200, verbose_name='عنوان دسته بندی') 9 | url_title = models.CharField(max_length=200, unique=True, verbose_name='عنوان در url') 10 | is_active = models.BooleanField(default=True, verbose_name='فعال / غیرفعال') 11 | 12 | def __str__(self): 13 | return self.title 14 | 15 | class Meta: 16 | verbose_name = 'دسته بندی مقاله' 17 | verbose_name_plural = 'دسته بندی های مقاله' 18 | 19 | 20 | class Article(models.Model): 21 | title = models.CharField(max_length=300, verbose_name='عنوان مقاله') 22 | slug = models.SlugField(max_length=400, db_index=True, allow_unicode=True, verbose_name='عنوان در url') 23 | image = models.ImageField(upload_to='images/articles', verbose_name='تصویر مقاله') 24 | short_description = models.TextField(verbose_name='توضیحات کوتاه') 25 | text = models.TextField(verbose_name='متن مقاله') 26 | is_active = models.BooleanField(default=True, verbose_name='فعال / غیرفعال') 27 | selected_categories = models.ManyToManyField(ArticleCategory, verbose_name='دسته بندی ها') 28 | author = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='نویسنده', null=True, editable=False) 29 | create_date = models.DateTimeField(auto_now_add=True, editable=False, verbose_name='تاریخ ثبت') 30 | 31 | def __str__(self): 32 | return self.title 33 | 34 | def get_jalali_create_date(self): 35 | return date2jalali(self.create_date) 36 | 37 | def get_jalali_create_time(self): 38 | return self.create_date.strftime('%H:%M') 39 | 40 | class Meta: 41 | verbose_name = 'مقاله' 42 | verbose_name_plural = 'مقالات' 43 | 44 | 45 | class ArticleComment(models.Model): 46 | article = models.ForeignKey(Article, on_delete=models.CASCADE, verbose_name='مقاله') 47 | parent = models.ForeignKey('ArticleComment', null=True, blank=True, on_delete=models.CASCADE, verbose_name='والد') 48 | user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='کاربر') 49 | create_date = models.DateTimeField(auto_now_add=True, verbose_name='تاریخ ثبت') 50 | text = models.TextField(verbose_name='متن نظر') 51 | 52 | def __str__(self): 53 | return str(self.user) 54 | 55 | class Meta: 56 | verbose_name = 'نظر مقاله' 57 | verbose_name_plural = 'نظرات مقاله' 58 | -------------------------------------------------------------------------------- /home_module/views.py: -------------------------------------------------------------------------------- 1 | from django.db.models import Count 2 | from django.shortcuts import render 3 | from django.views.generic.base import TemplateView 4 | from product_module.models import Product, ProductCategory 5 | from site_module.models import SiteSetting, FooterLinkBox, Slider 6 | from utils.convertors import group_list 7 | 8 | 9 | class HomeView(TemplateView): 10 | template_name = 'home_module/index_page.html' 11 | 12 | def get_context_data(self, **kwargs): 13 | context = super().get_context_data(**kwargs) 14 | sliders = Slider.objects.filter(is_active=True) 15 | context['sliders'] = sliders 16 | latest_products = Product.objects.filter(is_active=True, is_delete=False).order_by('-id')[:12] 17 | most_visit_products = Product.objects.filter(is_active=True, is_delete=False).annotate(visit_count=Count('productvisit')).order_by('-visit_count')[:12] 18 | context['latest_products'] = group_list(latest_products) 19 | context['most_visit_products'] = group_list(most_visit_products) 20 | categories = list(ProductCategory.objects.annotate(products_count=Count('product_categories')).filter(is_active=True, is_delete=False, products_count__gt=0)[:6]) 21 | categories_products = [] 22 | for category in categories: 23 | item = { 24 | 'id': category.id, 25 | 'title': category.title, 26 | 'products': list(category.product_categories.all()[:4]) 27 | } 28 | categories_products.append(item) 29 | 30 | context['categories_products'] = categories_products 31 | return context 32 | 33 | 34 | def site_header_component(request): 35 | setting: SiteSetting = SiteSetting.objects.filter(is_main_setting=True).first() 36 | context = { 37 | 'site_setting': setting 38 | } 39 | return render(request, 'shared/site_header_component.html', context) 40 | 41 | 42 | def site_footer_component(request): 43 | setting: SiteSetting = SiteSetting.objects.filter(is_main_setting=True).first() 44 | footer_link_boxes = FooterLinkBox.objects.all() 45 | context = { 46 | 'site_setting': setting, 47 | 'footer_link_boxes': footer_link_boxes 48 | } 49 | return render(request, 'shared/site_footer_component.html', context) 50 | 51 | 52 | class AboutView(TemplateView): 53 | template_name = 'home_module/about_page.html' 54 | 55 | def get_context_data(self, **kwargs): 56 | context = super(AboutView, self).get_context_data(**kwargs) 57 | site_setting: SiteSetting = SiteSetting.objects.filter(is_main_setting=True).first() 58 | context['site_setting'] = site_setting 59 | return context 60 | -------------------------------------------------------------------------------- /user_panel_module/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | from django.core import validators 3 | from django.core.exceptions import ValidationError 4 | 5 | from account_module.models import User 6 | 7 | 8 | class EditProfileModelForm(forms.ModelForm): 9 | class Meta: 10 | model = User 11 | fields = ['first_name', 'last_name', 'avatar', 'address', 'about_user'] 12 | widgets = { 13 | 'first_name': forms.TextInput(attrs={ 14 | 'class': 'form-control' 15 | }), 16 | 'last_name': forms.TextInput(attrs={ 17 | 'class': 'form-control' 18 | }), 19 | 'avatar': forms.FileInput(attrs={ 20 | 'class': 'form-control' 21 | }), 22 | 'address': forms.Textarea(attrs={ 23 | 'class': 'form-control', 24 | 'rows': 3, 25 | }), 26 | 'about_user': forms.Textarea(attrs={ 27 | 'class': 'form-control', 28 | 'rows': 6, 29 | 'id': 'message' 30 | }) 31 | } 32 | 33 | labels = { 34 | 'first_name': 'نام', 35 | 'last_name': 'نام خانوادگی', 36 | 'avatar': 'تصویر پروفایل', 37 | 'address': 'آدرس', 38 | 'about_user': 'درباره شخص', 39 | } 40 | 41 | 42 | class ChangePasswordForm(forms.Form): 43 | current_password = forms.CharField( 44 | label='کلمه عبور فعلی', 45 | widget=forms.PasswordInput( 46 | attrs={ 47 | 'class': 'form-control' 48 | } 49 | ), 50 | validators=[ 51 | validators.MaxLengthValidator(100), 52 | ] 53 | ) 54 | password = forms.CharField( 55 | label='کلمه عبور', 56 | widget=forms.PasswordInput( 57 | attrs={ 58 | 'class': 'form-control' 59 | } 60 | ), 61 | validators=[ 62 | validators.MaxLengthValidator(100), 63 | ] 64 | ) 65 | confirm_password = forms.CharField( 66 | label='تکرار کلمه عبور', 67 | widget=forms.PasswordInput( 68 | attrs={ 69 | 'class': 'form-control' 70 | } 71 | ), 72 | validators=[ 73 | validators.MaxLengthValidator(100), 74 | ] 75 | ) 76 | 77 | def clean_confirm_password(self): 78 | password = self.cleaned_data.get('password') 79 | confirm_password = self.cleaned_data.get('confirm_password') 80 | 81 | if password == confirm_password: 82 | return confirm_password 83 | 84 | raise ValidationError('کلمه عبور و تکرار کلمه عبور مغایرت دارند') 85 | -------------------------------------------------------------------------------- /static/js/custom.js: -------------------------------------------------------------------------------- 1 | function sendArticleComment(articleId) { 2 | var comment = $('#commentText').val(); 3 | var parentId = $('#parent_id').val(); 4 | console.log(parentId); 5 | $.get('/articles/add-article-comment', { 6 | article_comment: comment, 7 | article_id: articleId, 8 | parent_id: parentId 9 | }).then(res => { 10 | $('#comments_area').html(res); 11 | $('#commentText').val(''); 12 | $('#parent_id').val(''); 13 | 14 | if (parentId !== null && parentId !== '') { 15 | document.getElementById('single_comment_box_' + parentId).scrollIntoView({behavior: "smooth"}); 16 | } else { 17 | document.getElementById('comments_area').scrollIntoView({behavior: "smooth"}); 18 | } 19 | }); 20 | } 21 | 22 | function fillParentId(parentId) { 23 | $('#parent_id').val(parentId); 24 | document.getElementById('comment_form').scrollIntoView({behavior: "smooth"}); 25 | } 26 | 27 | function filterProducts() { 28 | const filterPrice = $('#sl2').val(); 29 | const start_price = filterPrice.split(',')[0]; 30 | const end_price = filterPrice.split(',')[1]; 31 | $('#start_price').val(start_price); 32 | $('#end_price').val(end_price); 33 | $('#filter_form').submit(); 34 | } 35 | 36 | function fillPage(page) { 37 | $('#page').val(page); 38 | $('#filter_form').submit(); 39 | } 40 | 41 | function showLargeImage(imageSrc) { 42 | $('#main_image').attr('src', imageSrc); 43 | $('#show_large_image_modal').attr('href', imageSrc); 44 | } 45 | 46 | function addProductToOrder(productId) { 47 | const productCount = $('#product-count').val(); 48 | $.get('/order/add-to-order?product_id=' + productId + '&count=' + productCount).then(res => { 49 | Swal.fire({ 50 | title: 'اعلان', 51 | text: res.text, 52 | icon: res.icon, 53 | showCancelButton: false, 54 | confirmButtonColor: '#3085d6', 55 | confirmButtonText: res.confirm_button_text 56 | }).then((result) => { 57 | if (result.isConfirmed && res.status === 'not_auth') { 58 | window.location.href = '/login'; 59 | } 60 | }); 61 | }); 62 | } 63 | 64 | function removeOrderDetail(detailId) { 65 | $.get('/user/remove-order-detail?detail_id=' + detailId).then(res => { 66 | if (res.status === 'success') { 67 | $('#order-detail-content').html(res.body); 68 | } 69 | }); 70 | } 71 | 72 | 73 | // detail id => order detail id 74 | // state => increase , decrease 75 | function changeOrderDetailCount(detailId, state) { 76 | $.get('/user/change-order-detail?detail_id=' + detailId + '&state=' + state).then(res => { 77 | if (res.status === 'success') { 78 | $('#order-detail-content').html(res.body); 79 | } 80 | }); 81 | } -------------------------------------------------------------------------------- /templates/shared/site_footer_component.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /article_module/views.py: -------------------------------------------------------------------------------- 1 | from django.http import HttpRequest, HttpResponse 2 | from django.shortcuts import render 3 | from django.views.generic import DetailView 4 | from django.views.generic.list import ListView 5 | from article_module.models import Article, ArticleCategory, ArticleComment 6 | 7 | 8 | class ArticlesListView(ListView): 9 | model = Article 10 | paginate_by = 4 11 | template_name = 'article_module/articles_page.html' 12 | 13 | def get_context_data(self, *args, **kwargs): 14 | context = super(ArticlesListView, self).get_context_data(*args, **kwargs) 15 | return context 16 | 17 | def get_queryset(self): 18 | query = super(ArticlesListView, self).get_queryset() 19 | query = query.filter(is_active=True) 20 | category_name = self.kwargs.get('category') 21 | if category_name is not None: 22 | query = query.filter(selected_categories__url_title__iexact=category_name) 23 | return query 24 | 25 | 26 | class ArticleDetailView(DetailView): 27 | model = Article 28 | template_name = 'article_module/article_detail_page.html' 29 | 30 | def get_queryset(self): 31 | query = super(ArticleDetailView, self).get_queryset() 32 | query = query.filter(is_active=True) 33 | return query 34 | 35 | def get_context_data(self, **kwargs): 36 | context = super(ArticleDetailView, self).get_context_data() 37 | article: Article = kwargs.get('object') 38 | context['comments'] = ArticleComment.objects.filter(article_id=article.id, parent=None).order_by('-create_date').prefetch_related('articlecomment_set') 39 | context['comments_count'] = ArticleComment.objects.filter(article_id=article.id).count() 40 | return context 41 | 42 | 43 | def article_categories_component(request: HttpRequest): 44 | article_main_categories = ArticleCategory.objects.prefetch_related('articlecategory_set').filter(is_active=True, parent_id=None) 45 | 46 | context = { 47 | 'main_categories': article_main_categories 48 | } 49 | return render(request, 'article_module/components/article_categories_component.html', context) 50 | 51 | 52 | def add_article_comment(request: HttpRequest): 53 | if request.user.is_authenticated: 54 | article_id = request.GET.get('article_id') 55 | article_comment = request.GET.get('article_comment') 56 | parent_id = request.GET.get('parent_id') 57 | print(article_id, article_comment, parent_id) 58 | new_comment = ArticleComment(article_id=article_id, text=article_comment, user_id=request.user.id, parent_id=parent_id) 59 | new_comment.save() 60 | context = { 61 | 'comments': ArticleComment.objects.filter(article_id=article_id, parent=None).order_by('-create_date').prefetch_related('articlecomment_set'), 62 | 'comments_count': ArticleComment.objects.filter(article_id=article_id).count() 63 | } 64 | 65 | return render(request, 'article_module/includes/article_comments_partial.html', context) 66 | 67 | return HttpResponse('response') 68 | -------------------------------------------------------------------------------- /static/css/price-range.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Slider for Bootstrap 3 | * 4 | * Copyright 2012 Stefan Petre 5 | * Licensed under the Apache License v2.0 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | */ 9 | .slider { 10 | display: inline-block; 11 | vertical-align: middle; 12 | position: relative; 13 | } 14 | .slider.slider-horizontal { 15 | width: 210px; 16 | height: 20px; 17 | } 18 | .slider.slider-horizontal .slider-track { 19 | height: 15px; 20 | left: 0; 21 | margin-top: -5px; 22 | top: 50%; 23 | width: 100%; 24 | } 25 | .slider.slider-horizontal .slider-selection { 26 | height: 100%; 27 | top: 0; 28 | bottom: 0; 29 | } 30 | .slider.slider-horizontal .slider-handle { 31 | margin-left: -12px; 32 | margin-top: 2px; 33 | } 34 | 35 | .left-round{ 36 | margin-left:2px !important; 37 | } 38 | 39 | .slider.slider-horizontal .slider-handle.triangle { 40 | border-width: 0 10px 10px 10px; 41 | width: 0; 42 | height: 0; 43 | border-bottom-color: #0480be; 44 | margin-top: 0; 45 | } 46 | .slider.slider-vertical { 47 | height: 210px; 48 | width: 20px; 49 | } 50 | .slider.slider-vertical .slider-track { 51 | width: 10px; 52 | height: 100%; 53 | margin-left: -5px; 54 | left: 50%; 55 | top: 0; 56 | } 57 | .slider.slider-vertical .slider-selection { 58 | width: 100%; 59 | left: 0; 60 | top: 0; 61 | bottom: 0; 62 | } 63 | .slider.slider-vertical .slider-handle { 64 | margin-left: -5px; 65 | margin-top: -10px; 66 | } 67 | .slider.slider-vertical .slider-handle.triangle { 68 | border-width: 10px 0 10px 10px; 69 | width: 1px; 70 | height: 1px; 71 | border-left-color: #0480be; 72 | margin-left: 0; 73 | } 74 | .slider input { 75 | display: none; 76 | } 77 | .slider .tooltip-inner { 78 | white-space: nowrap; 79 | } 80 | .slider-track { 81 | position: absolute; 82 | cursor: pointer; 83 | background-color: #f7f7f7; 84 | background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); 85 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9)); 86 | background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9); 87 | background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9); 88 | background-image: linear-gradient(to bottom, #f5f5f5, #f9f9f9); 89 | background-repeat: repeat-x; 90 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0); 91 | -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); 92 | -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); 93 | box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); 94 | -webkit-border-radius: 15px; 95 | -moz-border-radius: 15px; 96 | border-radius: 15px; 97 | } 98 | 99 | .slider-selection { 100 | -moz-box-sizing: border-box; 101 | background: none repeat scroll 0 0 #FE980F; 102 | border-radius: 15px; 103 | box-shadow: 0 -1px 0 rgba(0, 0, 0, 0.15) inset; 104 | position: absolute; 105 | } 106 | 107 | .slider-handle { 108 | background: #fff; 109 | box-shadow:none; 110 | height: 10px; 111 | opacity: 1; 112 | position: absolute; 113 | width: 10px; 114 | } 115 | 116 | .slider-handle.round { 117 | -webkit-border-radius: 20px; 118 | -moz-border-radius: 20px; 119 | border-radius: 20px; 120 | } 121 | .slider-handle.triangle { 122 | background: transparent none; 123 | } -------------------------------------------------------------------------------- /site_module/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | 4 | # Create your models here. 5 | 6 | class SiteSetting(models.Model): 7 | site_name = models.CharField(max_length=200, verbose_name='نام سایت') 8 | site_url = models.CharField(max_length=200, verbose_name='دامنه سایت') 9 | address = models.CharField(max_length=200, verbose_name='آدرس') 10 | phone = models.CharField(max_length=200, null=True, blank=True, verbose_name='تلفن') 11 | fax = models.CharField(max_length=200, null=True, blank=True, verbose_name='فکس') 12 | email = models.CharField(max_length=200, null=True, blank=True, verbose_name='ایمیل') 13 | copy_right = models.TextField(verbose_name='متن کپی رایت سایت') 14 | about_us_text = models.TextField(verbose_name='متن درباره ما سایت') 15 | site_logo = models.ImageField(upload_to='images/site-setting/', verbose_name='لوگو سایت') 16 | is_main_setting = models.BooleanField(verbose_name='تنظیمات اصلی') 17 | 18 | class Meta: 19 | verbose_name = 'تنظیمات سایت' 20 | verbose_name_plural = 'تنظیمات' 21 | 22 | def __str__(self): 23 | return self.site_name 24 | 25 | 26 | class FooterLinkBox(models.Model): 27 | title = models.CharField(max_length=200, verbose_name='عنوان') 28 | 29 | class Meta: 30 | verbose_name = 'دسته بندی لینک های فوتر' 31 | verbose_name_plural = 'دسته بندی های لینک های فوتر' 32 | 33 | def __str__(self): 34 | return self.title 35 | 36 | 37 | class FooterLink(models.Model): 38 | title = models.CharField(max_length=200, verbose_name='عنوان') 39 | url = models.URLField(max_length=500, verbose_name='لینک') 40 | footer_link_box = models.ForeignKey(to=FooterLinkBox, on_delete=models.CASCADE, verbose_name='دسته بندی') 41 | 42 | class Meta: 43 | verbose_name = 'لینک فوتر' 44 | verbose_name_plural = 'لینک های فوتر' 45 | 46 | def __str__(self): 47 | return self.title 48 | 49 | 50 | class Slider(models.Model): 51 | title = models.CharField(max_length=200, verbose_name='عنوان') 52 | url = models.URLField(max_length=500, verbose_name='لینک') 53 | url_title = models.CharField(max_length=200, verbose_name='عنوان لینک') 54 | description = models.TextField(verbose_name='توضیحات اسلایدر') 55 | image = models.ImageField(upload_to='images/sliders', verbose_name='تصویر اسلایدر') 56 | is_active = models.BooleanField(default=True, verbose_name='فعال / غیرفعال') 57 | 58 | class Meta: 59 | verbose_name = 'اسلایدر' 60 | verbose_name_plural = 'اسلایدر ها' 61 | 62 | def __str__(self): 63 | return self.title 64 | 65 | 66 | class SiteBanner(models.Model): 67 | class SiteBannerPositions(models.TextChoices): 68 | product_list = 'product_list', 'صفحه لیست محصولات', 69 | product_detail = 'product_detail', 'صفحه ی جزییات محصولات', 70 | about_us = 'about_us', 'درباره ما' 71 | 72 | title = models.CharField(max_length=200, verbose_name='عنوان بنر') 73 | url = models.URLField(max_length=400, null=True, blank=True, verbose_name='آدرس بنر') 74 | image = models.ImageField(upload_to='images/banners', verbose_name='تصویر بنر') 75 | is_active = models.BooleanField(verbose_name='فعال / غیرفعال') 76 | position = models.CharField(max_length=200, choices=SiteBannerPositions.choices, verbose_name='جایگاه نمایشی') 77 | 78 | def __str__(self): 79 | return self.title 80 | 81 | class Meta: 82 | verbose_name = 'بنر تبلیغاتی' 83 | verbose_name_plural = 'بنرهای تبلیغاتی' 84 | -------------------------------------------------------------------------------- /article_module/templates/article_module/articles_page.html: -------------------------------------------------------------------------------- 1 | {% extends 'shared/_layout.html' %} 2 | {% load poll_extras %} 3 | {% load thumbnail %} 4 | {% load render_partial %} 5 | 6 | {% block title %} 7 | لیست مقالات 8 | {% endblock %} 9 | 10 | {% block content %} 11 |
12 |
13 |
14 | 15 | 71 | 72 |
73 | 80 |
81 | 82 |
83 |
84 |
85 | {% endblock %} -------------------------------------------------------------------------------- /product_module/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from django.urls import reverse 3 | from account_module.models import User 4 | 5 | 6 | # Create your models here. 7 | 8 | class ProductCategory(models.Model): 9 | title = models.CharField(max_length=300, db_index=True, verbose_name='عنوان') 10 | url_title = models.CharField(max_length=300, db_index=True, verbose_name='عنوان در url') 11 | is_active = models.BooleanField(verbose_name='فعال / غیرفعال') 12 | is_delete = models.BooleanField(verbose_name='حذف شده / نشده') 13 | 14 | def __str__(self): 15 | return f'( {self.title} - {self.url_title} )' 16 | 17 | class Meta: 18 | verbose_name = 'دسته بندی' 19 | verbose_name_plural = 'دسته بندی ها' 20 | 21 | 22 | class ProductBrand(models.Model): 23 | title = models.CharField(max_length=300, verbose_name='نام برند', db_index=True) 24 | url_title = models.CharField(max_length=300, verbose_name='نام در url', db_index=True) 25 | is_active = models.BooleanField(verbose_name='فعال / غیرفعال') 26 | 27 | class Meta: 28 | verbose_name = 'برند' 29 | verbose_name_plural = 'برند ها' 30 | 31 | def __str__(self): 32 | return self.title 33 | 34 | 35 | class Product(models.Model): 36 | title = models.CharField(max_length=300, verbose_name='نام محصول') 37 | category = models.ManyToManyField(ProductCategory, related_name='product_categories', verbose_name='دسته بندی ها') 38 | image = models.ImageField(upload_to='images/products', null=True, blank=True, verbose_name='تصویر محصول') 39 | brand = models.ForeignKey(ProductBrand, on_delete=models.CASCADE, verbose_name='برند', null=True, blank=True) 40 | price = models.IntegerField(verbose_name='قیمت') 41 | short_description = models.CharField(max_length=360, db_index=True, null=True, verbose_name='توضیحات کوتاه') 42 | description = models.TextField(verbose_name='توضیحات اصلی', db_index=True) 43 | slug = models.SlugField(default="", null=False, db_index=True, blank=True, max_length=200, unique=True, verbose_name='عنوان در url') 44 | is_active = models.BooleanField(default=False, verbose_name='فعال / غیرفعال') 45 | is_delete = models.BooleanField(verbose_name='حذف شده / نشده') 46 | 47 | def get_absolute_url(self): 48 | return reverse('product-detail', args=[self.slug]) 49 | 50 | def save(self, *args, **kwargs): 51 | # self.slug = slugify(self.title) 52 | super().save(*args, **kwargs) 53 | 54 | def __str__(self): 55 | return f"{self.title} ({self.price})" 56 | 57 | class Meta: 58 | verbose_name = 'محصول' 59 | verbose_name_plural = 'محصولات' 60 | 61 | 62 | class ProductTag(models.Model): 63 | caption = models.CharField(max_length=300, db_index=True, verbose_name='عنوان') 64 | product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='product_tags') 65 | 66 | class Meta: 67 | verbose_name = 'تگ محصول' 68 | verbose_name_plural = 'تگ های محصولات' 69 | 70 | def __str__(self): 71 | return self.caption 72 | 73 | 74 | class ProductVisit(models.Model): 75 | product = models.ForeignKey('Product', on_delete=models.CASCADE, verbose_name='محصول') 76 | ip = models.CharField(max_length=30, verbose_name='آی پی کاربر') 77 | user = models.ForeignKey(User, null=True, blank=True, verbose_name='کاربر', on_delete=models.CASCADE) 78 | 79 | def __str__(self): 80 | return f'{self.product.title} / {self.ip}' 81 | 82 | class Meta: 83 | verbose_name = 'بازدید محصول' 84 | verbose_name_plural = 'بازدیدهای محصول' 85 | 86 | 87 | class ProductGallery(models.Model): 88 | product = models.ForeignKey(Product, on_delete=models.CASCADE, verbose_name='محصول') 89 | image = models.ImageField(upload_to='images/product-gallery', verbose_name='تصویر') 90 | 91 | def __str__(self): 92 | return self.product.title 93 | 94 | class Meta: 95 | verbose_name = 'تصویر گالری' 96 | verbose_name_plural = 'گالری تصاویر' 97 | -------------------------------------------------------------------------------- /user_panel_module/templates/user_panel_module/user_basket_content.html: -------------------------------------------------------------------------------- 1 | {% load poll_extras %} 2 | 3 | {% if order.orderdetail_set.all %} 4 |
5 |
6 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | {% for detail in order.orderdetail_set.all %} 26 | 27 | 30 | 34 | 37 | 48 | 52 | 56 | 57 | {% endfor %} 58 | 59 | 60 | 61 |
کـالاقیمتتعـدادمجمـوع
28 | 29 | 31 |

{{ detail.product.title }}

32 |

شناسـه : {{ detail.product.id }}

33 |
35 |

{{ detail.product.price|three_digits_currency }}

36 |
38 |
39 | + 41 | 44 | - 46 |
47 |
49 |

{% multiply detail.count detail.product.price %}

50 | {#

{{ detail.get_total_price|three_digits_currency }}

#} 51 |
53 | 55 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
    71 |
  • مجمـوع سبـد خریـد {{ sum|three_digits_currency }}
  • 72 |
73 | پرداخت 74 |
75 |
76 |
77 |
78 |
79 | {% else %} 80 |
81 |
82 |
83 |
84 |

سبد خرید شما خالی می باشد

85 |
86 |
87 |
88 |
89 | {% endif %} -------------------------------------------------------------------------------- /product_module/views.py: -------------------------------------------------------------------------------- 1 | from django.db.models import Count 2 | from django.http import HttpRequest 3 | from django.shortcuts import render, redirect 4 | from django.views.generic import ListView, DetailView 5 | from django.views.generic.base import View 6 | from site_module.models import SiteBanner 7 | from utils.http_service import get_client_ip 8 | from utils.convertors import group_list 9 | from .models import Product, ProductCategory, ProductBrand, ProductVisit, ProductGallery 10 | 11 | 12 | class ProductListView(ListView): 13 | template_name = 'product_module/product_list.html' 14 | model = Product 15 | context_object_name = 'products' 16 | ordering = ['-price'] 17 | paginate_by = 6 18 | 19 | def get_context_data(self, *, object_list=None, **kwargs): 20 | context = super(ProductListView, self).get_context_data() 21 | query = Product.objects.all() 22 | product: Product = query.order_by('-price').first() 23 | db_max_price = product.price if product is not None else 0 24 | context['db_max_price'] = db_max_price 25 | context['start_price'] = self.request.GET.get('start_price') or 0 26 | context['end_price'] = self.request.GET.get('end_price') or db_max_price 27 | context['banners'] = SiteBanner.objects.filter(is_active=True, position__iexact=SiteBanner.SiteBannerPositions.product_list) 28 | return context 29 | 30 | def get_queryset(self): 31 | query = super(ProductListView, self).get_queryset() 32 | category_name = self.kwargs.get('cat') 33 | brand_name = self.kwargs.get('brand') 34 | request: HttpRequest = self.request 35 | start_price = request.GET.get('start_price') 36 | end_price = request.GET.get('end_price') 37 | if start_price is not None: 38 | query = query.filter(price__gte=start_price) 39 | 40 | if end_price is not None: 41 | query = query.filter(price__lte=end_price) 42 | 43 | if brand_name is not None: 44 | query = query.filter(brand__url_title__iexact=brand_name) 45 | 46 | if category_name is not None: 47 | query = query.filter(category__url_title__iexact=category_name) 48 | return query 49 | 50 | 51 | class ProductDetailView(DetailView): 52 | template_name = 'product_module/product_detail.html' 53 | model = Product 54 | 55 | def get_context_data(self, **kwargs): 56 | context = super().get_context_data(**kwargs) 57 | loaded_product = self.object 58 | request = self.request 59 | favorite_product_id = request.session.get("product_favorites") 60 | context['is_favorite'] = favorite_product_id == str(loaded_product.id) 61 | context['banners'] = SiteBanner.objects.filter(is_active=True, position__iexact=SiteBanner.SiteBannerPositions.product_detail) 62 | galleries = list(ProductGallery.objects.filter(product_id=loaded_product.id).all()) 63 | galleries.insert(0, loaded_product) 64 | context['product_galleries_group'] = group_list(galleries, 3) 65 | context['related_products'] = group_list(list(Product.objects.filter(brand_id=loaded_product.brand_id).exclude(pk=loaded_product.id).all()[:12]), 3) 66 | user_ip = get_client_ip(self.request) 67 | user_id = None 68 | if self.request.user.is_authenticated: 69 | user_id = self.request.user.id 70 | 71 | has_been_visited = ProductVisit.objects.filter(ip__iexact=user_ip, product_id=loaded_product.id).exists() 72 | 73 | if not has_been_visited: 74 | new_visit = ProductVisit(ip=user_ip, user_id=user_id, product_id=loaded_product.id) 75 | new_visit.save() 76 | 77 | return context 78 | 79 | 80 | class AddProductFavorite(View): 81 | def post(self, request): 82 | product_id = request.POST["product_id"] 83 | product = Product.objects.get(pk=product_id) 84 | request.session["product_favorites"] = product_id 85 | return redirect(product.get_absolute_url()) 86 | 87 | 88 | def product_categories_component(request: HttpRequest): 89 | product_categories = ProductCategory.objects.filter(is_active=True, is_delete=False) 90 | context = { 91 | 'categories': product_categories 92 | } 93 | return render(request, 'product_module/components/product_categories_component.html', context) 94 | 95 | 96 | def product_brands_component(request: HttpRequest): 97 | product_brands = ProductBrand.objects.annotate(products_count=Count('product')).filter(is_active=True) 98 | context = { 99 | 'brands': product_brands 100 | } 101 | return render(request, 'product_module/components/product_brands_component.html', context) 102 | -------------------------------------------------------------------------------- /product_module/templates/product_module/product_list.html: -------------------------------------------------------------------------------- 1 | {% extends 'shared/_layout.html' %} 2 | {% load thumbnail %} 3 | {% load render_partial %} 4 | 5 | {% block title %}لیست محصولات{% endblock %} 6 | 7 | {% block content %} 8 |
9 |
10 |
11 | 12 |
13 | {% if products %} 14 |
15 |

محصولات

16 | {% for product in products %} 17 | {% include 'includes/product_item_partial.html' with product=product col_size=4 %} 18 | {% endfor %} 19 |
20 |
    21 | {% if page_obj.has_previous %} 22 |
  • قبلی
  • 24 | {% endif %} 25 | {% for pageNumber in paginator.page_range %} 26 |
  • 27 | {{ pageNumber }} 29 |
  • 30 | {% endfor %} 31 | {% if page_obj.has_next %} 32 |
  • بعدی 33 |
  • 34 | {% endif %} 35 | 36 |
37 |
38 | {% else %} 39 |
40 |

هیچ محصولی یافت نشد

41 |
42 | {% endif %} 43 |
44 | 45 |
46 | 86 |
87 | 88 |
89 |
90 |
91 | {% endblock %} -------------------------------------------------------------------------------- /contact_module/templates/contact_module/contact_us_page.html: -------------------------------------------------------------------------------- 1 | {% extends 'shared/_layout.html' %} 2 | 3 | {% block title %} 4 | تماس با ما 5 | {% endblock %} 6 | 7 | {% block content %} 8 |
9 |
10 |
11 |
12 |
13 |

با ما در ارتباط باشیـد

14 | 15 |
17 | {% csrf_token %} 18 | 19 | {% comment %}{% for field in form %} 20 |
21 | {{ field.label_tag }} 22 | {{ field }} 23 | {{ field.errors }} 24 |
25 | {% endfor %} 26 | 27 |
{% endcomment %} 28 | 29 | 30 |
31 | {{ form.email.label_tag }} 32 | {{ form.email }} 33 | {{ form.email.errors }} 34 |
35 | 36 |
37 | {{ form.full_name.label_tag }} 38 | {{ form.full_name }} 39 | {{ form.full_name.errors }} 40 |
41 | 42 |
43 | {{ form.title.label_tag }} 44 | {{ form.title }} 45 | {{ form.title.errors }} 46 |
47 | 48 |
49 | {{ form.message.label_tag }} 50 | {{ form.message }} 51 | {{ form.message.errors }} 52 |
53 | 54 | {% comment %}{{ form }}{% endcomment %} 55 | {% comment %}
56 | 58 |
59 |
60 | 62 |
63 |
64 | 66 |
67 |
68 | 70 |
{% endcomment %} 71 |
72 | {% comment %}{% endcomment %} 73 | 74 |
75 |
76 |
77 |
78 |
79 |
80 |

اطلاعات تماس

81 |
82 |

{{ site_setting.site_name }}

83 |

آدرس: {{ site_setting.address }}

84 |

تلفن تماس : {{ site_setting.phone }}

85 | {% if site_setting.fax %} 86 |

فکس : {{ site_setting.fax }}

87 | {% endif %} 88 | {% if site_setting.email %} 89 |

ایمیـل : {{ site_setting.email }}

90 | {% endif %} 91 |
92 |
93 |
94 |
95 |
96 |
97 | {% endblock %} -------------------------------------------------------------------------------- /user_panel_module/views.py: -------------------------------------------------------------------------------- 1 | from django.http import HttpRequest, JsonResponse 2 | from django.shortcuts import render, redirect 3 | from django.template.loader import render_to_string 4 | from django.urls import reverse 5 | from django.views import View 6 | from django.views.generic import TemplateView 7 | from account_module.models import User 8 | from order_module.models import Order, OrderDetail 9 | from .forms import EditProfileModelForm, ChangePasswordForm 10 | from django.contrib.auth import logout 11 | 12 | 13 | class UserPanelDashboardPage(TemplateView): 14 | template_name = 'user_panel_module/user_panel_dashboard_page.html' 15 | 16 | 17 | class EditUserProfilePage(View): 18 | def get(self, request: HttpRequest): 19 | current_user = User.objects.filter(id=request.user.id).first() 20 | edit_form = EditProfileModelForm(instance=current_user) 21 | context = { 22 | 'form': edit_form, 23 | 'current_user': current_user 24 | } 25 | return render(request, 'user_panel_module/edit_profile_page.html', context) 26 | 27 | def post(self, request: HttpRequest): 28 | current_user = User.objects.filter(id=request.user.id).first() 29 | edit_form = EditProfileModelForm(request.POST, request.FILES, instance=current_user) 30 | if edit_form.is_valid(): 31 | edit_form.save(commit=True) 32 | 33 | context = { 34 | 'form': edit_form, 35 | 'current_user': current_user 36 | } 37 | return render(request, 'user_panel_module/edit_profile_page.html', context) 38 | 39 | 40 | class ChangePasswordPage(View): 41 | def get(self, request: HttpRequest): 42 | context = { 43 | 'form': ChangePasswordForm() 44 | } 45 | return render(request, 'user_panel_module/change_password_page.html', context) 46 | 47 | def post(self, request: HttpRequest): 48 | form = ChangePasswordForm(request.POST) 49 | if form.is_valid(): 50 | current_user: User = User.objects.filter(id=request.user.id).first() 51 | if current_user.check_password(form.cleaned_data.get('current_password')): 52 | current_user.set_password(form.cleaned_data.get('password')) 53 | current_user.save() 54 | logout(request) 55 | return redirect(reverse('login_page')) 56 | else: 57 | form.add_error('password', 'کلمه عبور وارد شده اشتباه می باشد') 58 | 59 | context = { 60 | 'form': form 61 | } 62 | return render(request, 'user_panel_module/change_password_page.html', context) 63 | 64 | 65 | def user_panel_menu_component(request: HttpRequest): 66 | return render(request, 'user_panel_module/components/user_panel_menu_component.html') 67 | 68 | 69 | def user_basket(request: HttpRequest): 70 | current_order, created = Order.objects.prefetch_related('orderdetail_set').get_or_create(is_paid=False, user_id=request.user.id) 71 | total_amount = current_order.calculate_total_price() 72 | 73 | context = { 74 | 'order': current_order, 75 | 'sum': total_amount 76 | } 77 | return render(request, 'user_panel_module/user_basket.html', context) 78 | 79 | 80 | def remove_order_detail(request): 81 | detail_id = request.GET.get('detail_id') 82 | if detail_id is None: 83 | return JsonResponse({ 84 | 'status': 'not_found_detail_id' 85 | }) 86 | 87 | deleted_count, deleted_dict = OrderDetail.objects.filter(id=detail_id, order__is_paid=False, order__user_id=request.user.id).delete() 88 | 89 | if deleted_count == 0: 90 | return JsonResponse({ 91 | 'status': 'detail_not_found' 92 | }) 93 | 94 | current_order, created = Order.objects.prefetch_related('orderdetail_set').get_or_create(is_paid=False, user_id=request.user.id) 95 | total_amount = current_order.calculate_total_price() 96 | 97 | context = { 98 | 'order': current_order, 99 | 'sum': total_amount 100 | } 101 | return JsonResponse({ 102 | 'status': 'success', 103 | 'body': render_to_string('user_panel_module/user_basket_content.html', context) 104 | }) 105 | 106 | 107 | def change_order_detail_count(request: HttpRequest): 108 | detail_id = request.GET.get('detail_id') 109 | state = request.GET.get('state') 110 | if detail_id is None or state is None: 111 | return JsonResponse({ 112 | 'status': 'not_found_detail_or_state' 113 | }) 114 | 115 | order_detail = OrderDetail.objects.filter(id=detail_id, order__user_id=request.user.id, order__is_paid=False).first() 116 | 117 | if order_detail is None: 118 | return JsonResponse({ 119 | 'status': 'detail_not_found' 120 | }) 121 | 122 | if state == 'increase': 123 | order_detail.count += 1 124 | order_detail.save() 125 | elif state == 'decrease': 126 | if order_detail.count == 1: 127 | order_detail.delete() 128 | else: 129 | order_detail.count -= 1 130 | order_detail.save() 131 | else: 132 | return JsonResponse({ 133 | 'status': 'state_invalid' 134 | }) 135 | 136 | current_order, created = Order.objects.prefetch_related('orderdetail_set').get_or_create(is_paid=False, user_id=request.user.id) 137 | total_amount = current_order.calculate_total_price() 138 | 139 | context = { 140 | 'order': current_order, 141 | 'sum': total_amount 142 | } 143 | return JsonResponse({ 144 | 'status': 'success', 145 | 'body': render_to_string('user_panel_module/user_basket_content.html', context) 146 | }) 147 | -------------------------------------------------------------------------------- /eshop_project/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for eshop_project project. 3 | 4 | Generated by 'django-admin startproject' using Django 3.2.7. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.2/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/3.2/ref/settings/ 11 | """ 12 | 13 | from pathlib import Path 14 | import os 15 | # Build paths inside the project like this: BASE_DIR / 'subdir'. 16 | BASE_DIR = Path(__file__).resolve().parent.parent 17 | 18 | # Quick-start development settings - unsuitable for production 19 | # See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/ 20 | 21 | # SECURITY WARNING: keep the secret key used in production secret! 22 | SECRET_KEY = 'django-insecure-9qts1=s)$ky8o%%_$_#j#dmb106oas2_-n6shcfp$yg2g@uxny' 23 | 24 | # SECURITY WARNING: don't run with debug turned on in production! 25 | DEBUG = True 26 | 27 | ALLOWED_HOSTS = ['*'] 28 | 29 | # Application definition 30 | 31 | INSTALLED_APPS = [ 32 | 'django.contrib.admin', 33 | 'django.contrib.auth', 34 | 'django.contrib.contenttypes', 35 | 'django.contrib.sessions', 36 | 'django.contrib.messages', 37 | 'django.contrib.staticfiles', 38 | # internal apps 39 | 'account_module', 40 | 'home_module', 41 | 'product_module', 42 | 'contact_module', 43 | 'site_module', 44 | 'article_module', 45 | 'user_panel_module', 46 | 'order_module', 47 | 'polls', 48 | # external apps 49 | 'django_render_partial', 50 | 'sorl.thumbnail', 51 | 'jalali_date', 52 | ] 53 | 54 | MIDDLEWARE = [ 55 | 'django.middleware.security.SecurityMiddleware', 56 | 'django.contrib.sessions.middleware.SessionMiddleware', 57 | 'django.middleware.common.CommonMiddleware', 58 | 'django.middleware.csrf.CsrfViewMiddleware', 59 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 60 | 'django.contrib.messages.middleware.MessageMiddleware', 61 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 62 | ] 63 | 64 | ROOT_URLCONF = 'eshop_project.urls' 65 | 66 | TEMPLATES = [ 67 | { 68 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 69 | 'DIRS': [BASE_DIR / 'templates'], 70 | 'APP_DIRS': True, 71 | 'OPTIONS': { 72 | 'context_processors': [ 73 | 'django.template.context_processors.debug', 74 | 'django.template.context_processors.request', 75 | 'django.contrib.auth.context_processors.auth', 76 | 'django.contrib.messages.context_processors.messages', 77 | ], 78 | }, 79 | }, 80 | ] 81 | 82 | WSGI_APPLICATION = 'eshop_project.wsgi.application' 83 | 84 | # Database 85 | # https://docs.djangoproject.com/en/3.2/ref/settings/#databases 86 | 87 | AUTH_USER_MODEL = 'account_module.User' 88 | 89 | DATABASES = { 90 | 'default': { 91 | 'ENGINE': 'django.db.backends.sqlite3', 92 | 'NAME': BASE_DIR / 'db.sqlite3', 93 | } 94 | } 95 | 96 | # Password validation 97 | # https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators 98 | 99 | AUTH_PASSWORD_VALIDATORS = [ 100 | { 101 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 102 | }, 103 | { 104 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 105 | }, 106 | { 107 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 108 | }, 109 | { 110 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 111 | }, 112 | ] 113 | 114 | # Internationalization 115 | # https://docs.djangoproject.com/en/3.2/topics/i18n/ 116 | 117 | LANGUAGE_CODE = 'fa-IR' 118 | 119 | TIME_ZONE = 'UTC' 120 | 121 | USE_I18N = True 122 | 123 | USE_L10N = True 124 | 125 | USE_TZ = True 126 | 127 | # Static files (CSS, JavaScript, Images) 128 | # https://docs.djangoproject.com/en/3.2/howto/static-files/ 129 | 130 | STATIC_URL = '/static/' 131 | # STATIC_ROOT = os.path.join(BASE_DIR, 'static') 132 | 133 | # MEDIA_ROOT = BASE_DIR / 'uploads' 134 | # MEDIA_URL = '/medias/' 135 | 136 | MEDIA_URL = '/media/' 137 | MEDIA_ROOT = os.path.join(BASE_DIR, 'media') 138 | 139 | STATICFILES_DIRS = [ 140 | BASE_DIR / 'static' 141 | ] 142 | 143 | # Default primary key field type 144 | # https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field 145 | 146 | DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' 147 | 148 | # SESSION_COOKIE_AGE = 120 149 | 150 | EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' 151 | EMAIL_USE_TLS = True 152 | EMAIL_HOST = 'smtp.gmail.com' 153 | EMAIL_HOST_USER = 'onionarchitecturemvc@gmail.com' 154 | EMAIL_HOST_PASSWORD = 'django@pass' 155 | EMAIL_PORT = 587 156 | 157 | # default settings 158 | JALALI_DATE_DEFAULTS = { 159 | 'Strftime': { 160 | 'date': '%y/%m/%d', 161 | 'datetime': '%H:%M:%S _ %y/%m/%d', 162 | }, 163 | 'Static': { 164 | 'js': [ 165 | # loading datepicker 166 | 'admin/js/django_jalali.min.js', 167 | # OR 168 | # 'admin/jquery.ui.datepicker.jalali/scripts/jquery.ui.core.js', 169 | # 'admin/jquery.ui.datepicker.jalali/scripts/calendar.js', 170 | # 'admin/jquery.ui.datepicker.jalali/scripts/jquery.ui.datepicker-cc.js', 171 | # 'admin/jquery.ui.datepicker.jalali/scripts/jquery.ui.datepicker-cc-fa.js', 172 | # 'admin/js/main.js', 173 | ], 174 | 'css': { 175 | 'all': [ 176 | 'admin/jquery.ui.datepicker.jalali/themes/base/jquery-ui.min.css', 177 | ] 178 | } 179 | }, 180 | } 181 | -------------------------------------------------------------------------------- /templates/shared/site_header_component.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /account_module/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render, redirect 2 | from django.urls import reverse 3 | from django.views import View 4 | from .models import User 5 | from django.utils.crypto import get_random_string 6 | from django.http import Http404, HttpRequest 7 | from django.contrib.auth import login, logout 8 | from utils.email_service import send_email 9 | 10 | from account_module.forms import RegisterForm, LoginForm, ForgotPasswordForm, ResetPasswordForm 11 | 12 | 13 | class RegisterView(View): 14 | def get(self, request): 15 | register_form = RegisterForm() 16 | context = { 17 | 'register_form': register_form 18 | } 19 | 20 | return render(request, 'account_module/register.html', context) 21 | 22 | def post(self, request): 23 | register_form = RegisterForm(request.POST) 24 | if register_form.is_valid(): 25 | user_email = register_form.cleaned_data.get('email') 26 | user_password = register_form.cleaned_data.get('password') 27 | user: bool = User.objects.filter(email__iexact=user_email).exists() 28 | if user: 29 | register_form.add_error('email', 'ایمیل وارد شده تکراری می باشد') 30 | else: 31 | new_user = User( 32 | email=user_email, 33 | email_active_code=get_random_string(72), 34 | is_active=False, 35 | username=user_email) 36 | new_user.set_password(user_password) 37 | new_user.save() 38 | send_email('فعالسازی حساب کاربری', new_user.email, {'user': new_user}, 'emails/activate_account.html') 39 | return redirect(reverse('login_page')) 40 | 41 | context = { 42 | 'register_form': register_form 43 | } 44 | 45 | return render(request, 'account_module/register.html', context) 46 | 47 | 48 | class ActivateAccountView(View): 49 | def get(self, request, email_active_code): 50 | user: User = User.objects.filter(email_active_code__iexact=email_active_code).first() 51 | if user is not None: 52 | if not user.is_active: 53 | user.is_active = True 54 | user.email_active_code = get_random_string(72) 55 | user.save() 56 | # todo: show success message to user 57 | return redirect(reverse('login_page')) 58 | else: 59 | # todo: show your account was activated message to user 60 | pass 61 | 62 | raise Http404 63 | 64 | 65 | class LoginView(View): 66 | def get(self, request): 67 | login_form = LoginForm() 68 | context = { 69 | 'login_form': login_form 70 | } 71 | 72 | return render(request, 'account_module/login.html', context) 73 | 74 | def post(self, request: HttpRequest): 75 | login_form = LoginForm(request.POST) 76 | if login_form.is_valid(): 77 | user_email = login_form.cleaned_data.get('email') 78 | user_pass = login_form.cleaned_data.get('password') 79 | user: User = User.objects.filter(email__iexact=user_email).first() 80 | if user is not None: 81 | if not user.is_active: 82 | login_form.add_error('email', 'حساب کاربری شما فعال نشده است') 83 | else: 84 | is_password_correct = user.check_password(user_pass) 85 | if is_password_correct: 86 | login(request, user) 87 | return redirect(reverse('user_panel_dashboard')) 88 | else: 89 | login_form.add_error('email', 'کلمه عبور اشتباه است') 90 | else: 91 | login_form.add_error('email', 'کاربری با مشخصات وارد شده یافت نشد') 92 | 93 | context = { 94 | 'login_form': login_form 95 | } 96 | 97 | return render(request, 'account_module/login.html', context) 98 | 99 | 100 | class ForgetPasswordView(View): 101 | def get(self, request: HttpRequest): 102 | forget_pass_form = ForgotPasswordForm() 103 | context = {'forget_pass_form': forget_pass_form} 104 | return render(request, 'account_module/forgot_password.html', context) 105 | 106 | def post(self, request: HttpRequest): 107 | forget_pass_form = ForgotPasswordForm(request.POST) 108 | if forget_pass_form.is_valid(): 109 | user_email = forget_pass_form.cleaned_data.get('email') 110 | user: User = User.objects.filter(email__iexact=user_email).first() 111 | if user is not None: 112 | send_email('بازیابی کلمه عبور', user.email, {'user': user}, 'emails/forgot_password.html') 113 | return redirect(reverse('home_page')) 114 | 115 | context = {'forget_pass_form': forget_pass_form} 116 | return render(request, 'account_module/forgot_password.html', context) 117 | 118 | 119 | class ResetPasswordView(View): 120 | def get(self, request: HttpRequest, active_code): 121 | user: User = User.objects.filter(email_active_code__iexact=active_code).first() 122 | if user is None: 123 | return redirect(reverse('login_page')) 124 | 125 | reset_pass_form = ResetPasswordForm() 126 | 127 | context = { 128 | 'reset_pass_form': reset_pass_form, 129 | 'user': user 130 | } 131 | return render(request, 'account_module/reset_password.html', context) 132 | 133 | def post(self, request: HttpRequest, active_code): 134 | reset_pass_form = ResetPasswordForm(request.POST) 135 | user: User = User.objects.filter(email_active_code__iexact=active_code).first() 136 | if reset_pass_form.is_valid(): 137 | if user is None: 138 | return redirect(reverse('login_page')) 139 | user_new_pass = reset_pass_form.cleaned_data.get('password') 140 | user.set_password(user_new_pass) 141 | user.email_active_code = get_random_string(72) 142 | user.is_active = True 143 | user.save() 144 | return redirect(reverse('login_page')) 145 | 146 | context = { 147 | 'reset_pass_form': reset_pass_form, 148 | 'user': user 149 | } 150 | 151 | return render(request, 'account_module/reset_password.html', context) 152 | 153 | 154 | class LogoutView(View): 155 | def get(self, request): 156 | logout(request) 157 | return redirect(reverse('login_page')) 158 | -------------------------------------------------------------------------------- /article_module/templates/article_module/article_detail_page.html: -------------------------------------------------------------------------------- 1 | {% extends 'shared/_layout.html' %} 2 | {% load render_partial %} 3 | {% load poll_extras %} 4 | {% load thumbnail %} 5 | 6 | {% block title %} 7 | جزییات مقاله 8 | {% endblock %} 9 | 10 | {% block content %} 11 |
12 |
13 |
14 | 15 |
16 |
17 |

{{ article.title }}

18 |
19 |

{{ article.title }}

20 | 37 | 38 | {% thumbnail article.image "862x398" quality=95 crop='center' as im %} 39 | 40 | {% endthumbnail %} 41 | 42 |

43 | {{ article.short_description }} 44 |

45 |

46 | {{ article.text }} 47 |

48 |
49 |
50 | 51 | 52 | {% if article.author %} 53 | 70 | {% endif %} 71 | 72 |
73 |

نظرات ({{ comments_count }})

74 |
    75 | {% for comment in comments %} 76 |
  • 77 | 78 | 79 | 80 |
    81 | 88 |

    89 | {{ comment.text }} 90 |

    91 | پاسـخ 93 |
    94 |
  • 95 | 96 | {% for sub_comment in comment.articlecomment_set.all %} 97 |
  • 98 | 99 | 100 | 101 |
    102 | 110 |

    111 | {{ sub_comment.text }} 112 |

    113 |
    114 |
  • 115 | {% endfor %} 116 | {% endfor %} 117 | 118 |
119 |
120 |
121 | {% if request.user.is_authenticated %} 122 |
123 |
124 |

نظـر خود را بنویسیـد

125 |
126 | 127 |
128 | 129 |
130 | * 131 | 132 | ارسـال 133 | نظـر 134 |
135 |
136 |
137 | {% else %} 138 |
139 | برای درج نظر می بایست لاگین کنید 140 |
141 | {% endif %} 142 |
143 |
144 | 145 |
146 | 149 |
150 | 151 |
152 |
153 |
154 | {% endblock %} -------------------------------------------------------------------------------- /static/lib/image-lightbox/js/lightbox.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Lightbox v2.11.3 3 | * by Lokesh Dhakar 4 | * 5 | * More info: 6 | * http://lokeshdhakar.com/projects/lightbox2/ 7 | * 8 | * Copyright Lokesh Dhakar 9 | * Released under the MIT license 10 | * https://github.com/lokesh/lightbox2/blob/master/LICENSE 11 | * 12 | * @preserve 13 | */ 14 | !function(a,b){"function"==typeof define&&define.amd?define(["jquery"],b):"object"==typeof exports?module.exports=b(require("jquery")):a.lightbox=b(a.jQuery)}(this,function(a){function b(b){this.album=[],this.currentImageIndex=void 0,this.init(),this.options=a.extend({},this.constructor.defaults),this.option(b)}return b.defaults={albumLabel:"Image %1 of %2",alwaysShowNavOnTouchDevices:!1,fadeDuration:600,fitImagesInViewport:!0,imageFadeDuration:600,positionFromTop:50,resizeDuration:700,showImageNumberLabel:!0,wrapAround:!1,disableScrolling:!1,sanitizeTitle:!1},b.prototype.option=function(b){a.extend(this.options,b)},b.prototype.imageCountLabel=function(a,b){return this.options.albumLabel.replace(/%1/g,a).replace(/%2/g,b)},b.prototype.init=function(){var b=this;a(document).ready(function(){b.enable(),b.build()})},b.prototype.enable=function(){var b=this;a("body").on("click","a[rel^=lightbox], area[rel^=lightbox], a[data-lightbox], area[data-lightbox]",function(c){return b.start(a(c.currentTarget)),!1})},b.prototype.build=function(){if(!(a("#lightbox").length>0)){var b=this;a('
').appendTo(a("body")),this.$lightbox=a("#lightbox"),this.$overlay=a("#lightboxOverlay"),this.$outerContainer=this.$lightbox.find(".lb-outerContainer"),this.$container=this.$lightbox.find(".lb-container"),this.$image=this.$lightbox.find(".lb-image"),this.$nav=this.$lightbox.find(".lb-nav"),this.containerPadding={top:parseInt(this.$container.css("padding-top"),10),right:parseInt(this.$container.css("padding-right"),10),bottom:parseInt(this.$container.css("padding-bottom"),10),left:parseInt(this.$container.css("padding-left"),10)},this.imageBorderWidth={top:parseInt(this.$image.css("border-top-width"),10),right:parseInt(this.$image.css("border-right-width"),10),bottom:parseInt(this.$image.css("border-bottom-width"),10),left:parseInt(this.$image.css("border-left-width"),10)},this.$overlay.hide().on("click",function(){return b.end(),!1}),this.$lightbox.hide().on("click",function(c){"lightbox"===a(c.target).attr("id")&&b.end()}),this.$outerContainer.on("click",function(c){return"lightbox"===a(c.target).attr("id")&&b.end(),!1}),this.$lightbox.find(".lb-prev").on("click",function(){return 0===b.currentImageIndex?b.changeImage(b.album.length-1):b.changeImage(b.currentImageIndex-1),!1}),this.$lightbox.find(".lb-next").on("click",function(){return b.currentImageIndex===b.album.length-1?b.changeImage(0):b.changeImage(b.currentImageIndex+1),!1}),this.$nav.on("mousedown",function(a){3===a.which&&(b.$nav.css("pointer-events","none"),b.$lightbox.one("contextmenu",function(){setTimeout(function(){this.$nav.css("pointer-events","auto")}.bind(b),0)}))}),this.$lightbox.find(".lb-loader, .lb-close").on("click",function(){return b.end(),!1})}},b.prototype.start=function(b){function c(a){d.album.push({alt:a.attr("data-alt"),link:a.attr("href"),title:a.attr("data-title")||a.attr("title")})}var d=this,e=a(window);e.on("resize",a.proxy(this.sizeOverlay,this)),this.sizeOverlay(),this.album=[];var f,g=0,h=b.attr("data-lightbox");if(h){f=a(b.prop("tagName")+'[data-lightbox="'+h+'"]');for(var i=0;ik||g.height>j)&&(g.width/k>g.height/j?(i=k,h=parseInt(g.height/(g.width/i),10),f.width(i),f.height(h)):(h=j,i=parseInt(g.width/(g.height/h),10),f.width(i),f.height(h))),c.sizeContainer(f.width(),f.height())},g.src=this.album[b].link,this.currentImageIndex=b},b.prototype.sizeOverlay=function(){var b=this;setTimeout(function(){b.$overlay.width(a(document).width()).height(a(document).height())},0)},b.prototype.sizeContainer=function(a,b){function c(){d.$lightbox.find(".lb-dataContainer").width(g),d.$lightbox.find(".lb-prevLink").height(h),d.$lightbox.find(".lb-nextLink").height(h),d.$overlay.focus(),d.showImage()}var d=this,e=this.$outerContainer.outerWidth(),f=this.$outerContainer.outerHeight(),g=a+this.containerPadding.left+this.containerPadding.right+this.imageBorderWidth.left+this.imageBorderWidth.right,h=b+this.containerPadding.top+this.containerPadding.bottom+this.imageBorderWidth.top+this.imageBorderWidth.bottom;e!==g||f!==h?this.$outerContainer.animate({width:g,height:h},this.options.resizeDuration,"swing",function(){c()}):c()},b.prototype.showImage=function(){this.$lightbox.find(".lb-loader").stop(!0).hide(),this.$lightbox.find(".lb-image").fadeIn(this.options.imageFadeDuration),this.updateNav(),this.updateDetails(),this.preloadNeighboringImages(),this.enableKeyboardNav()},b.prototype.updateNav=function(){var a=!1;try{document.createEvent("TouchEvent"),a=!!this.options.alwaysShowNavOnTouchDevices}catch(a){}this.$lightbox.find(".lb-nav").show(),this.album.length>1&&(this.options.wrapAround?(a&&this.$lightbox.find(".lb-prev, .lb-next").css("opacity","1"),this.$lightbox.find(".lb-prev, .lb-next").show()):(this.currentImageIndex>0&&(this.$lightbox.find(".lb-prev").show(),a&&this.$lightbox.find(".lb-prev").css("opacity","1")),this.currentImageIndex1&&this.options.showImageNumberLabel){var c=this.imageCountLabel(this.currentImageIndex+1,this.album.length);this.$lightbox.find(".lb-number").text(c).fadeIn("fast")}else this.$lightbox.find(".lb-number").hide();this.$outerContainer.removeClass("animating"),this.$lightbox.find(".lb-dataContainer").fadeIn(this.options.resizeDuration,function(){return a.sizeOverlay()})},b.prototype.preloadNeighboringImages=function(){if(this.album.length>this.currentImageIndex+1){(new Image).src=this.album[this.currentImageIndex+1].link}if(this.currentImageIndex>0){(new Image).src=this.album[this.currentImageIndex-1].link}},b.prototype.enableKeyboardNav=function(){this.$lightbox.on("keyup.keyboard",a.proxy(this.keyboardAction,this)),this.$overlay.on("keyup.keyboard",a.proxy(this.keyboardAction,this))},b.prototype.disableKeyboardNav=function(){this.$lightbox.off(".keyboard"),this.$overlay.off(".keyboard")},b.prototype.keyboardAction=function(a){var b=a.keyCode;27===b?(a.stopPropagation(),this.end()):37===b?0!==this.currentImageIndex?this.changeImage(this.currentImageIndex-1):this.options.wrapAround&&this.album.length>1&&this.changeImage(this.album.length-1):39===b&&(this.currentImageIndex!==this.album.length-1?this.changeImage(this.currentImageIndex+1):this.options.wrapAround&&this.album.length>1&&this.changeImage(0))},b.prototype.end=function(){this.disableKeyboardNav(),a(window).off("resize",this.sizeOverlay),this.$lightbox.fadeOut(this.options.fadeDuration),this.$overlay.fadeOut(this.options.fadeDuration),this.options.disableScrolling&&a("body").removeClass("lb-disable-scrolling")},new b}); 15 | //# sourceMappingURL=lightbox.min.map -------------------------------------------------------------------------------- /static/css/responsive.css: -------------------------------------------------------------------------------- 1 | /* lg */ 2 | @media (min-width: 1200px) { 3 | 4 | } 5 | 6 | /* md */ 7 | @media (min-width: 992px) and (max-width: 1199px) { 8 | 9 | 10 | .usa{ 11 | margin-right: 0; 12 | } 13 | 14 | .shipping img{ 15 | width: 100%; 16 | } 17 | 18 | .searchform input{ 19 | width: 160px; 20 | } 21 | 22 | .product-information span span{ 23 | width: 100%; 24 | } 25 | 26 | #similar-product .carousel-inner .item img{ 27 | width: 65px; 28 | } 29 | 30 | #cart_items .cart_info .cart_description h4, 31 | #cart_items .cart_info .cart_description p{ 32 | text-align: center; 33 | } 34 | 35 | } 36 | 37 | 38 | /* sm */ 39 | @media (min-width: 768px) and (max-width: 991px) { 40 | 41 | .shop-menu ul li a{ 42 | padding-left: 0; 43 | } 44 | 45 | #slider-carousel .item{ 46 | padding-left: 30px; 47 | } 48 | 49 | .item h2{ 50 | font-size: 24px; 51 | } 52 | 53 | .girl{ 54 | margin-left: 0; 55 | } 56 | 57 | .pricing{ 58 | width: 100px; 59 | } 60 | 61 | 62 | .shipping img{ 63 | width: 100%; 64 | } 65 | 66 | .slider.slider-horizontal{ 67 | width: 100% !important; 68 | } 69 | 70 | .tab-pane .col-sm-3, .features_items .col-sm-4{ 71 | width: 50%; 72 | } 73 | 74 | .footer-widget .col-sm-2{ 75 | width: 33%; 76 | display: inline-block; 77 | margin-bottom: 50px; 78 | } 79 | 80 | .footer-widget .col-sm-3{ 81 | display: inline-block; 82 | width: 40%; 83 | } 84 | 85 | #similar-product .carousel-inner .item img{ 86 | width: 60px; 87 | margin-left: 0; 88 | } 89 | 90 | .product-information span span{ 91 | display: block; 92 | width: 100%; 93 | } 94 | 95 | .product-information .cart{ 96 | margin-left: 0; 97 | margin-top: 15px; 98 | } 99 | 100 | .item-control i{ 101 | font-size: 12px; 102 | padding: 5px 6px; 103 | } 104 | 105 | #cart_items .cart_info .cart_description h4, #cart_items .cart_info .cart_description p{ 106 | text-align: center; 107 | } 108 | 109 | .companyinfo h2{ 110 | font-size: 20px; 111 | } 112 | 113 | .address { 114 | margin-top: 48px; 115 | margin-left: 20px; 116 | } 117 | 118 | .address p { 119 | font-size: 12px; 120 | top: 5px; 121 | } 122 | 123 | } 124 | 125 | /* xs */ 126 | @media (max-width: 767px) { 127 | 128 | .header_top .col-sm-6:first-child{ 129 | display: inline-block; 130 | float: left; 131 | } 132 | 133 | .header_top .col-sm-6:last-child{ 134 | display: inline-block; 135 | float: right; 136 | } 137 | 138 | .header-middle .col-sm-4 { 139 | display: inline-block; 140 | overflow: inherit; 141 | width: 100%; 142 | } 143 | 144 | .social-icons ul li a i { 145 | padding: 8px 10px; 146 | } 147 | 148 | .shop-menu.pull-right{ 149 | float: none !important; 150 | } 151 | 152 | .shop-menu .nav.navbar-nav{ 153 | margin-left: -30px; 154 | } 155 | 156 | .header-bottom .col-sm-9{ 157 | display: inline-block; 158 | width: 100%; 159 | } 160 | 161 | .mainmenu{ 162 | width: 100%; 163 | } 164 | 165 | .mainmenu ul li{ 166 | background: rgba(0, 0, 0, 0.5); 167 | padding-top: 15px; 168 | padding-bottom: 0; 169 | } 170 | 171 | .mainmenu ul li:last-child{ 172 | padding-bottom: 15px; 173 | } 174 | 175 | .mainmenu ul li a{ 176 | color: #fff; 177 | } 178 | 179 | .navbar-collapse.in{ 180 | overflow: inherit; 181 | } 182 | 183 | .mainmenu ul li a.active{ 184 | padding-left: 15px; 185 | } 186 | 187 | .dropdown .fa-angle-down{ 188 | display: none; 189 | } 190 | 191 | ul.sub-menu{ 192 | position: relative; 193 | width: auto; 194 | display: block; 195 | background: transparent; 196 | box-shadow: none; 197 | top: 0; 198 | } 199 | 200 | .sub-menu li{ 201 | background: transparent; 202 | } 203 | 204 | .mainmenu .navbar-nav li ul.sub-menu li{ 205 | background: transparent; 206 | padding-bottom:0; 207 | } 208 | 209 | .nav.navbar-nav > li:hover > ul.sub-menu{ 210 | -webkit-animation: none; 211 | -moz-animation: none; 212 | -ms-animation: none; 213 | -o-animation: none; 214 | animation: none; 215 | box-shadow: none; 216 | } 217 | 218 | .header-bottom{ 219 | position: relative; 220 | } 221 | 222 | .header-bottom .col-sm-3 { 223 | display: inline-block; 224 | position: absolute; 225 | left: 0; 226 | top: 38px; 227 | } 228 | 229 | #slider-carousel .item{ 230 | padding-left: 0; 231 | } 232 | 233 | .shipping{ 234 | margin-bottom: 25px; 235 | } 236 | 237 | .pricing{ 238 | width: 100px; 239 | } 240 | 241 | .footer-top .col-sm-7 .col-sm-3{ 242 | width: 50%; 243 | float: left; 244 | } 245 | 246 | .footer-widget .col-sm-2 { 247 | width: 28%; 248 | display: flex; 249 | margin-bottom: 50px; 250 | margin-top: 0; 251 | float: left; 252 | margin-left: 30px; 253 | } 254 | 255 | .companyinfo{ 256 | text-align: center; 257 | } 258 | 259 | .footer-widget .col-sm-3{ 260 | display: inline-block; 261 | } 262 | 263 | .single-widget{ 264 | 265 | } 266 | 267 | .product-information span { 268 | display: block; 269 | } 270 | 271 | #similar-product { 272 | margin-bottom: 40px; 273 | } 274 | 275 | .well{ 276 | display: inline-block; 277 | } 278 | 279 | } 280 | 281 | /* XS Portrait */ 282 | @media (max-width: 480px) { 283 | 284 | .contactinfo{ 285 | text-align: center; 286 | } 287 | 288 | .contactinfo ul li a { 289 | padding-right: 15px; 290 | padding-left: 0; 291 | } 292 | 293 | .social-icons.pull-right{ 294 | float: none !important; 295 | text-align: center; 296 | } 297 | 298 | .btn-group.pull-right, 299 | .footer-bottom .pull-left, 300 | .footer-bottom .pull-right, 301 | .mainmenu.pull-left, 302 | .media.commnets .pull-left, 303 | .media-list .pull-left{ 304 | float: none !important; 305 | } 306 | 307 | .header_top .col-sm-6:first-child{ 308 | display: block; 309 | float: none; 310 | } 311 | 312 | .header_top .col-sm-6:last-child{ 313 | display: block; 314 | float: none; 315 | } 316 | 317 | .contactinfo .nav.nav-pills, .social-icons .nav.navbar-nav{ 318 | display: inline-block; 319 | } 320 | 321 | .logo{ 322 | text-align: center; 323 | width: 100%; 324 | } 325 | 326 | 327 | .shop-menu ul li { 328 | padding: 0; 329 | } 330 | 331 | .header-middle .col-sm-4{ 332 | text-align: center; 333 | overflow: inherit; 334 | } 335 | 336 | .shop-menu .nav.navbar-nav { 337 | margin-left: 0; 338 | } 339 | 340 | .btn-group>.btn-group:last-child>.btn:first-child{ 341 | margin-right: 0; 342 | } 343 | 344 | .header-bottom .col-sm-9{ 345 | display: inline-block; 346 | width: 100%; 347 | } 348 | 349 | .mainmenu{ 350 | width: 100%; 351 | } 352 | 353 | .mainmenu ul li{ 354 | background: rgba(0, 0, 0, 0.5); 355 | padding-top: 15px; 356 | padding-bottom: 0; 357 | } 358 | 359 | .mainmenu ul li:last-child{ 360 | padding-bottom: 15px; 361 | } 362 | 363 | .mainmenu ul li a { 364 | color: #FFF; 365 | padding-bottom: 0; 366 | } 367 | 368 | .navbar-collapse.in{ 369 | overflow: inherit; 370 | } 371 | 372 | .mainmenu ul li a.active{ 373 | padding-left: 15px; 374 | } 375 | 376 | .dropdown .fa-angle-down{ 377 | display: none; 378 | } 379 | 380 | ul.sub-menu{ 381 | position: relative; 382 | width: auto; 383 | display: block; 384 | background: transparent; 385 | box-shadow: none; 386 | top: 0; 387 | } 388 | 389 | 390 | .mainmenu .navbar-nav li ul.sub-menu li{ 391 | background: transparent; 392 | padding-bottom:0; 393 | } 394 | 395 | .nav.navbar-nav > li:hover > ul.sub-menu{ 396 | -webkit-animation: none; 397 | -moz-animation: none; 398 | -ms-animation: none; 399 | -o-animation: none; 400 | animation: none; 401 | box-shadow: none; 402 | } 403 | 404 | 405 | .img-responsive{ 406 | max-width: 90% !important; 407 | } 408 | 409 | .item{ 410 | padding-left: 0; 411 | } 412 | 413 | .item h1{ 414 | font-size: 30px; 415 | margin-top: 0; 416 | } 417 | 418 | .item h2{ 419 | font-size: 20px; 420 | } 421 | 422 | .pricing{ 423 | width: 70px; 424 | } 425 | 426 | .category-tab ul li a{ 427 | font-size: 12px; 428 | } 429 | 430 | .companyinfo h2, .companyinfo p{ 431 | text-align: center; 432 | } 433 | 434 | .video-gallery{ 435 | margin-top: 30px; 436 | } 437 | 438 | .footer-bottom p{ 439 | font-size: 13px; 440 | text-align: center; 441 | } 442 | 443 | .footer-widget .col-sm-2 { 444 | width: 50%; 445 | display: flex; 446 | margin-bottom: 50px; 447 | margin-top: 0; 448 | float: left; 449 | padding-right: 0; 450 | padding-left: 30px; 451 | margin-left: 0; 452 | } 453 | 454 | .single-widget { 455 | padding-left: 0; 456 | } 457 | 458 | .features_items{ 459 | margin-top: 30px; 460 | } 461 | 462 | .category-tab .nav-tabs li{ 463 | float: none; 464 | } 465 | 466 | #similar-product .carousel-inner .item img{ 467 | margin-left: 4px; 468 | } 469 | 470 | .product-information{ 471 | margin-top: 40px; 472 | } 473 | 474 | #reviews p, .blog-post-area .single-blog-post p{ 475 | text-align: justify; 476 | } 477 | 478 | #reviews form span input{ 479 | width: 100%; 480 | margin-bottom: 20px; 481 | } 482 | 483 | #reviews form span input:last-child{ 484 | margin-left: 0; 485 | } 486 | 487 | .blog-post-area .single-blog-post h3{ 488 | font-size: 14px; 489 | } 490 | 491 | .blog-post-area .post-meta ul li{ 492 | margin-right: 7px; 493 | font-size: 5pt; 494 | } 495 | 496 | .sinlge-post-meta li i:after, .blog-post-area .post-meta ul li i:after { 497 | top: 4px; 498 | right: 20px; 499 | } 500 | 501 | .shipping{ 502 | margin-bottom: 20px; 503 | } 504 | 505 | .commnets{ 506 | padding: 0; 507 | } 508 | 509 | .content-404 h1{ 510 | font-size: 30px; 511 | } 512 | 513 | .content-404 h2 a{ 514 | font-size: 20px; 515 | } 516 | 517 | .order-message{ 518 | display: inline-block; 519 | } 520 | 521 | .response-area .media img{ 522 | width: auto; 523 | } 524 | 525 | .sinlge-post-meta li{ 526 | margin-bottom: 10px; 527 | } 528 | 529 | .product-information{ 530 | padding-left: 0; 531 | text-align: center; 532 | } 533 | 534 | .product-information span span{ 535 | float: none; 536 | } 537 | 538 | 539 | } -------------------------------------------------------------------------------- /product_module/templates/product_module/product_detail.html: -------------------------------------------------------------------------------- 1 | {% extends 'shared/_layout.html' %} 2 | {% load render_partial %} 3 | {% load poll_extras %} 4 | 5 | {% block title %} 6 | {{ product.title }} 7 | {% endblock %} 8 | 9 | {% block header_references %} 10 | 11 | {% endblock %} 12 | 13 | {% block footer_references %} 14 | 15 | {# #} 16 | {% endblock %} 17 | 18 | {% block content %} 19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | {% if product.image %} 27 | 28 | {% else %} 29 | 30 | {% endif %} 31 |

32 | 34 | بزرگنمایـی 35 | 36 |

37 |
38 | 66 | 67 |
68 |
69 |
70 | 71 |
72 |

{{ product.title }}

73 |

شناسـه : {{ product.id }}

74 |
75 |
76 | 77 | قیمت : {{ product.price|three_digits_currency }} 78 | 79 | 80 | 81 | 83 | 88 | 89 |
90 |
91 |

موجـودی : در انبـار موجود می باشد

92 | 93 | {% if product.brand %} 94 |

برنـد : {{ product.brand.title }}

95 | {% endif %} 96 |
97 | 98 |
99 |
100 |
101 | 102 |
103 |
104 | 108 |
109 |
110 |
111 |
112 | {{ product.description | safe }} 113 |
114 |
115 | 116 |
117 |
118 | 123 |

لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با استفاده ازلورملورم 124 | ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با استفاده از طراحان 125 | گرافیک است. چاپگرها و متون بلکه روزنامه و مجله در ستون و سطرآنچنان که لازم است و 126 | برای شرایط فعلی تکنولوژی مورد نیاز و کاربردهای متنوع با هدف بهبود ابزارهای 127 | کاربردی می باشد. کتابهای زیادی در شصت و سه درصد گذشته، حال و آینده شناخت فراوان 128 | جامعه و متخصصان را می طلبد تا با نرم افزارها شناخت بیشتری را برای طراحان رایانه 129 | ای علی الخصوص طراحان خلاقی و فرهنگ پیشرو در زبان فارسی ایجاد کرد.

130 |

نظـر خود را بنویسیـد

131 | 132 |
133 | 134 | 135 | 136 | 137 | 138 | رتبـه : 139 | 142 |
143 |
144 |
145 | 146 |
147 |
148 | 149 | 175 | 176 |
177 | 178 |
179 | 192 |
193 | 194 |
195 |
196 |
197 | {% endblock %} --------------------------------------------------------------------------------