├── auctions ├── __init__.py ├── migrations │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-38.pyc │ │ ├── 0001_initial.cpython-38.pyc │ │ ├── 0002_auto_20200902_0116.cpython-38.pyc │ │ ├── 0003_auto_20200902_0117.cpython-38.pyc │ │ ├── 0004_auto_20200902_0121.cpython-38.pyc │ │ └── 0002_remove_bidding_auction.cpython-38.pyc │ ├── 0002_remove_bidding_auction.py │ ├── 0002_auto_20200902_0116.py │ ├── 0004_auto_20200902_0121.py │ ├── 0003_auto_20200902_0117.py │ ├── 0002_auto_20200911_0907.py │ └── 0001_initial.py ├── tests.py ├── apps.py ├── __pycache__ │ ├── admin.cpython-38.pyc │ ├── forms.cpython-38.pyc │ ├── models.cpython-38.pyc │ ├── urls.cpython-38.pyc │ ├── views.cpython-38.pyc │ └── __init__.cpython-38.pyc ├── static │ └── auctions │ │ ├── categories.css │ │ ├── create.css │ │ ├── login.css │ │ └── styles.css ├── templates │ └── auctions │ │ ├── winner.html │ │ ├── create.html │ │ ├── categories.html │ │ ├── login.html │ │ ├── register.html │ │ ├── allclosed.html │ │ ├── closed.html │ │ ├── index.html │ │ ├── categorylistings.html │ │ ├── layout.html │ │ ├── watchlist.html │ │ └── listing.html ├── admin.py ├── urls.py ├── forms.py ├── models.py └── views.py ├── commerce ├── __init__.py ├── __pycache__ │ ├── urls.cpython-38.pyc │ ├── wsgi.cpython-38.pyc │ ├── __init__.cpython-38.pyc │ └── settings.cpython-38.pyc ├── asgi.py ├── wsgi.py ├── urls.py └── settings.py ├── .gitignore ├── Procfile ├── db.sqlite3 ├── requirements.txt ├── README.md └── manage.py /auctions/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /commerce/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /auctions/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | auctions/__pycache__ 2 | commerce/__pycache__ 3 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | release: python manage.py migrate 2 | web: gunicorn Project2.wsgi 3 | -------------------------------------------------------------------------------- /db.sqlite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algaringo/e-commerce-website/HEAD/db.sqlite3 -------------------------------------------------------------------------------- /auctions/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /auctions/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class AuctionsConfig(AppConfig): 5 | name = 'auctions' 6 | -------------------------------------------------------------------------------- /auctions/__pycache__/admin.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algaringo/e-commerce-website/HEAD/auctions/__pycache__/admin.cpython-38.pyc -------------------------------------------------------------------------------- /auctions/__pycache__/forms.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algaringo/e-commerce-website/HEAD/auctions/__pycache__/forms.cpython-38.pyc -------------------------------------------------------------------------------- /auctions/__pycache__/models.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algaringo/e-commerce-website/HEAD/auctions/__pycache__/models.cpython-38.pyc -------------------------------------------------------------------------------- /auctions/__pycache__/urls.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algaringo/e-commerce-website/HEAD/auctions/__pycache__/urls.cpython-38.pyc -------------------------------------------------------------------------------- /auctions/__pycache__/views.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algaringo/e-commerce-website/HEAD/auctions/__pycache__/views.cpython-38.pyc -------------------------------------------------------------------------------- /commerce/__pycache__/urls.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algaringo/e-commerce-website/HEAD/commerce/__pycache__/urls.cpython-38.pyc -------------------------------------------------------------------------------- /commerce/__pycache__/wsgi.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algaringo/e-commerce-website/HEAD/commerce/__pycache__/wsgi.cpython-38.pyc -------------------------------------------------------------------------------- /auctions/__pycache__/__init__.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algaringo/e-commerce-website/HEAD/auctions/__pycache__/__init__.cpython-38.pyc -------------------------------------------------------------------------------- /commerce/__pycache__/__init__.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algaringo/e-commerce-website/HEAD/commerce/__pycache__/__init__.cpython-38.pyc -------------------------------------------------------------------------------- /commerce/__pycache__/settings.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algaringo/e-commerce-website/HEAD/commerce/__pycache__/settings.cpython-38.pyc -------------------------------------------------------------------------------- /auctions/migrations/__pycache__/__init__.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algaringo/e-commerce-website/HEAD/auctions/migrations/__pycache__/__init__.cpython-38.pyc -------------------------------------------------------------------------------- /auctions/migrations/__pycache__/0001_initial.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algaringo/e-commerce-website/HEAD/auctions/migrations/__pycache__/0001_initial.cpython-38.pyc -------------------------------------------------------------------------------- /auctions/migrations/__pycache__/0002_auto_20200902_0116.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algaringo/e-commerce-website/HEAD/auctions/migrations/__pycache__/0002_auto_20200902_0116.cpython-38.pyc -------------------------------------------------------------------------------- /auctions/migrations/__pycache__/0003_auto_20200902_0117.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algaringo/e-commerce-website/HEAD/auctions/migrations/__pycache__/0003_auto_20200902_0117.cpython-38.pyc -------------------------------------------------------------------------------- /auctions/migrations/__pycache__/0004_auto_20200902_0121.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algaringo/e-commerce-website/HEAD/auctions/migrations/__pycache__/0004_auto_20200902_0121.cpython-38.pyc -------------------------------------------------------------------------------- /auctions/migrations/__pycache__/0002_remove_bidding_auction.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algaringo/e-commerce-website/HEAD/auctions/migrations/__pycache__/0002_remove_bidding_auction.cpython-38.pyc -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | asgiref==3.2.10 2 | dj-database-url==0.5.0 3 | Django==3.1 4 | django-crispy-forms==1.9.2 5 | django-filter==2.3.0 6 | django-heroku==0.3.1 7 | django-widget-tweaks==1.4.8 8 | gunicorn==20.0.4 9 | psycopg2==2.8.6 10 | pytz==2020.1 11 | sqlparse==0.3.1 12 | whitenoise==5.2.0 13 | -------------------------------------------------------------------------------- /auctions/migrations/0002_remove_bidding_auction.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.1 on 2020-08-31 10:46 2 | 3 | from django.db import migrations 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('auctions', '0001_initial'), 10 | ] 11 | 12 | operations = [ 13 | migrations.RemoveField( 14 | model_name='bidding', 15 | name='auction', 16 | ), 17 | ] 18 | -------------------------------------------------------------------------------- /commerce/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for commerce 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.0/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', 'commerce.settings') 15 | 16 | application = get_asgi_application() 17 | -------------------------------------------------------------------------------- /commerce/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for commerce 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.0/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', 'commerce.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /auctions/migrations/0002_auto_20200902_0116.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.1 on 2020-09-01 17:16 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('auctions', '0001_initial'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='bidding', 15 | name='bidprice', 16 | field=models.DecimalField(decimal_places=2, max_digits=15), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /auctions/migrations/0004_auto_20200902_0121.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.1 on 2020-09-01 17:21 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('auctions', '0003_auto_20200902_0117'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='listing', 15 | name='startingbids', 16 | field=models.DecimalField(decimal_places=2, max_digits=15), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /auctions/static/auctions/categories.css: -------------------------------------------------------------------------------- 1 | .btn-squared-default 2 | { 3 | width: 30% !important; 4 | height: 30% !important; 5 | font-size: 10px; 6 | } 7 | 8 | .btn-squared-default:hover 9 | { 10 | border: 3px solid white; 11 | font-weight: 800; 12 | } 13 | 14 | .btn-squared-default-plain 15 | { 16 | width: 30% !important; 17 | height: 30% !important; 18 | font-size: 10px; 19 | } 20 | 21 | .btn-squared-default-plain:hover 22 | { 23 | border: 0px solid white; 24 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # e-commerce-website | [Sample Run](https://www.youtube.com/watch?v=_beRba3eHRg&t=93s) 2 | 3 | E-commerce auction site that allows users to post auction listings, place bids on listings, comment on those listings, and add listings to a “watchlist.” 4 | Using Python with Django framework, SQLite as database and Bootstrap4 for responsive design. 5 | 6 |

Installation

7 | 8 | Create Database 9 | ``` 10 | python manage.py migrate 11 | ``` 12 | Run Server 13 | ``` 14 | python manage.py runserver 15 | ``` 16 | Visit 17 | ``` 18 | 127.0.0.1:8000 19 | ``` 20 | -------------------------------------------------------------------------------- /auctions/migrations/0003_auto_20200902_0117.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.1 on 2020-09-01 17:17 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('auctions', '0002_auto_20200902_0116'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='listing', 15 | name='price', 16 | field=models.DecimalField(blank=True, decimal_places=2, max_digits=15, null=True), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /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 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'commerce.settings') 9 | try: 10 | from django.core.management import execute_from_command_line 11 | except ImportError as exc: 12 | raise ImportError( 13 | "Couldn't import Django. Are you sure it's installed and " 14 | "available on your PYTHONPATH environment variable? Did you " 15 | "forget to activate a virtual environment?" 16 | ) from exc 17 | execute_from_command_line(sys.argv) 18 | 19 | 20 | if __name__ == '__main__': 21 | main() 22 | -------------------------------------------------------------------------------- /auctions/templates/auctions/winner.html: -------------------------------------------------------------------------------- 1 | {% extends "auctions/layout.html" %} 2 | 3 | {% block body %} 4 | 5 |
6 |

Summary for {{ name }}

7 | 16 |
17 | 18 | {% endblock %} -------------------------------------------------------------------------------- /auctions/migrations/0002_auto_20200911_0907.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.1 on 2020-09-11 01:07 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('auctions', '0001_initial'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='category', 15 | name='name', 16 | field=models.CharField(blank=True, max_length=20, null=True), 17 | ), 18 | migrations.AlterField( 19 | model_name='listing', 20 | name='category', 21 | field=models.CharField(blank=True, default='', max_length=50, null=True), 22 | ), 23 | ] 24 | -------------------------------------------------------------------------------- /commerce/urls.py: -------------------------------------------------------------------------------- 1 | """commerce URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/3.0/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 include, path 18 | 19 | urlpatterns = [ 20 | path("admin/", admin.site.urls), 21 | path("", include("auctions.urls")) 22 | ] -------------------------------------------------------------------------------- /auctions/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from .models import Listing, Bidding, Watchlist, Closebid, Comment, Category 3 | 4 | # Register your models here. 5 | 6 | class ListingAdmin(admin.ModelAdmin): 7 | list_display = ("__str__", "productnames") 8 | 9 | class BiddingAdmin(admin.ModelAdmin): 10 | list_display = ("__str__", "bidprice") 11 | 12 | class WatchlistAdmin(admin.ModelAdmin): 13 | list_display = ("__str__", "watcher") 14 | 15 | class ClosebidAdmin(admin.ModelAdmin): 16 | list_display = ("__str__", "lister") 17 | 18 | class CommentAdmin(admin.ModelAdmin): 19 | list_display = ("__str__", "user") 20 | 21 | class CategoryAdmin(admin.ModelAdmin): 22 | list_display = ("__str__", "name") 23 | 24 | admin.site.register(Listing, ListingAdmin) 25 | admin.site.register(Bidding, BiddingAdmin) 26 | admin.site.register(Watchlist, WatchlistAdmin) 27 | admin.site.register(Closebid, ClosebidAdmin) 28 | admin.site.register(Comment, CommentAdmin) 29 | admin.site.register(Category, CategoryAdmin) -------------------------------------------------------------------------------- /auctions/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from django.conf.urls import url, include 3 | 4 | from . import views 5 | 6 | urlpatterns = [ 7 | path("", views.index, name="index"), 8 | path("login", views.login_view, name="login"), 9 | path("logout", views.logout_view, name="logout"), 10 | path("register", views.register, name="register"), 11 | path("create", views.createlisting, name="create"), 12 | path("category", views.category, name="category"), 13 | path("listing/", views.listingpage, name="listingpage"), 14 | path("listing//addwatch",views.addwatch,name="addwatch"), 15 | path("listing//removewatch",views.removewatch,name="removewatch"), 16 | path("listing//bid",views.bid,name="bid"), 17 | path("listing//closebid",views.closebid,name="closebid"), 18 | path("watchlist", views.watchlist, name="watchlist"), 19 | path("listing//closed", views.closed, name="closed"), 20 | path("comment/", views.comment, name="comment"), 21 | path("category", views.category, name="category"), 22 | path("category/", views.categorylistings, name="categorylistings"), 23 | path("listing/closed", views.allclosed, name="allclosed"), 24 | ] 25 | -------------------------------------------------------------------------------- /auctions/templates/auctions/create.html: -------------------------------------------------------------------------------- 1 | {% extends "auctions/layout.html" %} 2 | {% load crispy_forms_tags %} 3 | 4 | {% block body %} 5 | 6 |
7 |

Create Listings

8 |
9 | {% csrf_token %} 10 |
11 | {{ form.productnames|as_crispy_field }} 12 |
13 |
14 | {{ form.startingbids|as_crispy_field }} 15 |
16 |
17 | {{ form.category|as_crispy_field }} 18 |
19 |
20 | {{ form.images|as_crispy_field }} 21 |
22 |
23 | {{ form.descriptions|as_crispy_field }} 24 |
25 |
26 | 27 |
28 |
29 |
30 | 31 | 32 | {% endblock %} 33 | 34 | -------------------------------------------------------------------------------- /auctions/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | from .models import Listing, Bidding, Comment, Category 3 | 4 | CATEGORY = Category.objects.all().values_list('name', 'name') 5 | CATEGORY1 = { 6 | ('', '') 7 | } 8 | 9 | categories = [] 10 | 11 | for item in CATEGORY: 12 | categories.append(item) 13 | for item in CATEGORY1: 14 | categories.append(item) 15 | 16 | class ListingForm(forms.ModelForm): 17 | class Meta: 18 | model = Listing 19 | labels = { 20 | 'productnames' : 'Productname', 21 | 'descriptions' : 'Description', 22 | 'startingbids' : 'Starting Bids', 23 | 'images' : 'Image URL', 24 | 'category' : 'Category' 25 | } 26 | fields = [ 27 | 'productnames', 28 | 'descriptions', 29 | 'startingbids', 30 | 'images', 31 | 'category' 32 | ] 33 | widgets = { 34 | 'category': forms.Select(choices=categories, attrs={'class': 'form-control'}) 35 | } 36 | 37 | 38 | class BiddingForm(forms.ModelForm): 39 | class Meta: 40 | model = Bidding 41 | labels = { 42 | 'bidprice' : '' 43 | } 44 | fields = [ 45 | 'bidprice' 46 | ] 47 | 48 | class CommentForm(forms.ModelForm): 49 | class Meta: 50 | model = Comment 51 | labels = { 52 | 'comment' : '' 53 | } 54 | fields = [ 55 | 'comment' 56 | ] 57 | 58 | 59 | -------------------------------------------------------------------------------- /auctions/templates/auctions/categories.html: -------------------------------------------------------------------------------- 1 | {% extends "auctions/layout.html" %} 2 | 3 | {% block body %} 4 | 5 | 6 |
7 |
8 |






9 | 10 | 11 |
12 |
13 |
14 |

15 |

16 | 17 | CLOSED 18 |
19 | {% for item in object %} 20 | 24 | {% endfor %} 25 | 26 |

27 | 28 |
29 |
30 |
31 | 32 |
33 |
34 | 35 | {% endblock %} -------------------------------------------------------------------------------- /auctions/templates/auctions/login.html: -------------------------------------------------------------------------------- 1 | {% extends "auctions/layout.html" %} 2 | 3 | {% block body %} 4 | 5 |
6 |
7 | 36 |
37 |
38 | 39 | {% endblock %} -------------------------------------------------------------------------------- /auctions/templates/auctions/register.html: -------------------------------------------------------------------------------- 1 | {% extends "auctions/layout.html" %} 2 | 3 | {% block body %} 4 | 5 |
6 |
7 |
8 |
9 | 10 |
11 | 12 | 13 | 14 | {% if message %} 15 |
{{ message }}
16 | {% endif %} 17 | 18 |
19 | {% csrf_token %} 20 |
21 | 22 |
23 |
24 | 25 |
26 |
27 | 28 |
29 |
30 | 31 |
32 | 33 |
34 | 35 | 36 |
37 |
38 |
39 |
40 | 41 |
42 | 43 | 44 | {% endblock %} -------------------------------------------------------------------------------- /auctions/templates/auctions/allclosed.html: -------------------------------------------------------------------------------- 1 | {% extends "auctions/layout.html" %} 2 | 3 | {% block body %} 4 | 5 | 6 |
7 |
8 |

CLOSED LISTINGS

9 |
10 |
11 | 12 | 13 | 14 | 15 |
16 |
17 | 18 | 19 | {% for object in closedlist %} 20 | 21 |
22 |
23 | 24 | {% if object.images %} 25 | 26 | 27 | 28 | {% else %} 29 | 30 | 31 | 32 | {% endif %} 33 | 38 |
39 |
40 | 41 | {% empty %} 42 | No closed listings yet. View Active Listings. 43 | {% endfor %} 44 | 45 | 46 |
47 |
48 |
49 | 50 | 51 | 52 | 53 | {% endblock %} -------------------------------------------------------------------------------- /auctions/static/auctions/create.css: -------------------------------------------------------------------------------- 1 | 2 | .get-in-touch { 3 | max-width: 800px; 4 | margin: 50px auto; 5 | position: relative; 6 | 7 | } 8 | .get-in-touch .title { 9 | text-align: center; 10 | text-transform: uppercase; 11 | letter-spacing: 3px; 12 | font-size: 3.2em; 13 | line-height: 48px; 14 | padding-bottom: 48px; 15 | color: #5543ca; 16 | background: #5543ca; 17 | background: -moz-linear-gradient(left,#f4524d 0%,#5543ca 100%) !important; 18 | background: -webkit-linear-gradient(left,#f4524d 0%,#5543ca 100%) !important; 19 | background: linear-gradient(to right,#f4524d 0%,#5543ca 100%) !important; 20 | -webkit-background-clip: text !important; 21 | -webkit-text-fill-color: transparent !important; 22 | } 23 | 24 | .contact-form .form-field { 25 | position: relative; 26 | margin: 32px 0; 27 | } 28 | .contact-form .input-text { 29 | display: block; 30 | width: 100%; 31 | height: 36px; 32 | border-width: 0 0 2px 0; 33 | border-color: #5543ca; 34 | font-size: 18px; 35 | line-height: 26px; 36 | font-weight: 400; 37 | } 38 | .contact-form .input-text:focus { 39 | outline: none; 40 | } 41 | .contact-form .input-text:focus + .label, 42 | .contact-form .input-text.not-empty + .label { 43 | -webkit-transform: translateY(-24px); 44 | transform: translateY(-24px); 45 | } 46 | .contact-form .label { 47 | position: absolute; 48 | left: 20px; 49 | bottom: 11px; 50 | font-size: 18px; 51 | line-height: 26px; 52 | font-weight: 400; 53 | color: #5543ca; 54 | cursor: text; 55 | transition: -webkit-transform .2s ease-in-out; 56 | transition: transform .2s ease-in-out; 57 | transition: transform .2s ease-in-out, 58 | -webkit-transform .2s ease-in-out; 59 | } 60 | .contact-form .submit-btn { 61 | display: inline-block; 62 | background-color: #000; 63 | background-image: linear-gradient(125deg,#a72879,#064497); 64 | color: #fff; 65 | text-transform: uppercase; 66 | letter-spacing: 2px; 67 | font-size: 16px; 68 | padding: 8px 16px; 69 | border: none; 70 | width:200px; 71 | cursor: pointer; 72 | } 73 | 74 | -------------------------------------------------------------------------------- /auctions/templates/auctions/closed.html: -------------------------------------------------------------------------------- 1 | {% extends "auctions/layout.html" %} 2 | {% block body %} 3 | 4 |
5 | 6 |
7 | 8 | 9 |
10 | {% if object.images %} 11 | No Image Available for {{ object.productnames}} 12 | {% else %} 13 | No-Image-Available 14 | {% endif %} 15 |


16 |
17 | 18 | 19 |
20 | 21 | 22 | {% if object.bidder == user.username %} 23 |
24 | 27 | {% else %} 28 |
29 | 32 | {% endif %} 33 | 34 | 35 |

Details for {{ object.productnames }}:

36 |
37 | 38 |
Highest Bidder:
39 |
{{ object.bidder }}
40 | 41 |
Final Bid:
42 |
${{ object.finalbid }}
43 | 44 |
Listed by:
45 |
{{ object.lister }}
46 | 47 |
Checkout other Listings!
48 |
49 |
50 |
51 |
52 | 53 | {% endblock %} 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /auctions/templates/auctions/index.html: -------------------------------------------------------------------------------- 1 | {% extends "auctions/layout.html" %} 2 | 3 | {% block body %} 4 | {% load static %} 5 | 6 | 7 |
8 |
9 |






10 |
11 | 12 | 13 |
14 | {% for object in object %} 15 |
16 |
17 | {% if object.images %} 18 | 19 | 20 | 21 | {% else %} 22 | 23 | 24 | 25 | {% endif %} 26 |
27 |
{{ object.productnames }}
28 |

Current Bid: ${{ object.startingbids }} 29 |
30 | {{ object.descriptions }}

31 |
32 | 36 |
37 |
38 | {% endfor %} 39 |
40 |
41 | 42 | {% endblock %} 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /auctions/templates/auctions/categorylistings.html: -------------------------------------------------------------------------------- 1 | {% extends "auctions/layout.html" %} 2 | 3 | {% block body %} 4 | 5 |
6 |
7 |

{{ cats }}

8 |
9 |
10 | 11 |
12 | 13 | 14 | {% if category_posts %} 15 | 16 |
17 | {% for object in category_posts %} 18 |
19 |
20 | {% if object.images %} 21 | 22 | 23 | 24 | {% else %} 25 | 26 | 27 | 28 | {% endif %} 29 |
30 |
{{ object.productnames }}
31 |

Current Bid: ${{ object.startingbids }} 32 |
33 | {{ object.descriptions }}

34 |
35 | 39 |
40 |
41 | {% endfor %} 42 |
43 | 44 | {% else %} 45 | 46 |
47 | Pngtree-it-s-in-the-3845898 48 |
This category is empty. Checkout other categories!
49 |
50 | 51 | {% endif %} 52 | 53 |
54 | 55 | 56 | 57 | {% endblock %} -------------------------------------------------------------------------------- /auctions/models.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.models import AbstractUser 2 | from django.db import models 3 | from django import forms 4 | from django.utils.timezone import now 5 | 6 | # CATEGORY = ( 7 | # ('fashion', 'fashion'), 8 | # ('toys', 'toys'), 9 | # ('electronics', 'electronics'), 10 | # ('home', 'home'), 11 | # ('sports', 'sports'), 12 | # ('pets', 'pets'), 13 | # ('baby', 'baby'), 14 | # ('grocery','grocery'), 15 | # ('entertainment','entertainment'), 16 | # ) 17 | 18 | class User(AbstractUser): 19 | pass 20 | 21 | class Category(models.Model): 22 | name = models.CharField(max_length=20, null=True, blank=True) 23 | 24 | def __str__(self): 25 | return self.name 26 | 27 | class Listing(models.Model): 28 | productnames = models.CharField(max_length=20) 29 | descriptions = models.TextField(max_length=500) 30 | startingbids = models.DecimalField(max_digits=15, decimal_places=2) 31 | images = models.URLField(blank=True, null=True) 32 | category = models.CharField(max_length=50, blank=True, null=True, default="") 33 | lister = models.CharField(max_length=50, blank=True, null=True) 34 | created = models.DateTimeField(default=now, editable=False) 35 | 36 | def __str__(self): 37 | return self.productnames 38 | 39 | class Bidding(models.Model): 40 | bidder = models.CharField(max_length=50, blank=True, null=True) 41 | bidprice = models.DecimalField(max_digits=15, decimal_places=2) 42 | listingid = models.IntegerField() 43 | 44 | def __str__(self): 45 | return f"{self.listingid}" 46 | 47 | class Watchlist(models.Model): 48 | productnames = models.CharField(max_length=20) 49 | images = models.URLField(blank=True, null=True) 50 | finalbid = models.DecimalField(max_digits=15, decimal_places=2) 51 | lister = models.CharField(max_length=50, blank=True, null=True) 52 | watcher = models.CharField(max_length=50, blank=True, null=True) 53 | listingid = models.IntegerField() 54 | 55 | def __str__(self): 56 | return f"{self.listingid}" 57 | 58 | class Closebid(models.Model): 59 | productnames = models.CharField(max_length=20) 60 | images = models.URLField(blank=True, null=True) 61 | lister = models.CharField(max_length=64, blank=True, null=True) 62 | bidder = models.CharField(max_length=64, blank=True, null=True) 63 | listingid = models.IntegerField() 64 | category = models.CharField(max_length=50, blank=True, null=True) 65 | finalbid = models.DecimalField(max_digits=15, decimal_places=2, blank=True, null=True) 66 | 67 | def __str__(self): 68 | return f"{self.listingid}" 69 | 70 | class Comment(models.Model): 71 | user = models.CharField(max_length=64, blank=True, null=True) 72 | time = models.DateTimeField(default=now, editable=False) 73 | comment = models.CharField(max_length=30) 74 | listingid = models.IntegerField() 75 | 76 | def __str__(self): 77 | return f"{self.listingid}" 78 | 79 | -------------------------------------------------------------------------------- /auctions/static/auctions/login.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: "Karla", sans-serif; 3 | min-height: 100vh; } 4 | 5 | .brand-wrapper { 6 | margin-bottom: 19px; } 7 | .brand-wrapper .logo { 8 | height: 37px; } 9 | 10 | .underlineHover:after { 11 | display: block; 12 | left: 0; 13 | bottom: -10px; 14 | width: 0; 15 | height: 2px; 16 | background-color: #56baed; 17 | content: ""; 18 | transition: width 0.2s; 19 | } 20 | 21 | .underlineHover:hover { 22 | color: #0d0d0d; 23 | } 24 | 25 | .underlineHover:hover:after{ 26 | width: 50%; 27 | } 28 | 29 | .login-card { 30 | border: 0; 31 | border-radius: 27.5px; 32 | box-shadow: 0 10px 30px 0 rgba(172, 168, 168, 0.43); 33 | overflow: hidden; } 34 | .login-card-img { 35 | border-radius: 0; 36 | position: absolute; 37 | width: 100%; 38 | height: 100%; 39 | -o-object-fit: cover; 40 | object-fit: cover; } 41 | .login-card .card-body { 42 | padding: 85px 60px 60px; } 43 | @media (max-width: 422px) { 44 | .login-card .card-body { 45 | padding: 35px 24px; } } 46 | .login-card-description { 47 | font-size: 25px; 48 | color: #000; 49 | font-weight: normal; 50 | margin-bottom: 23px; } 51 | .login-card form { 52 | max-width: 326px; } 53 | .login-card .form-control { 54 | border: 1px solid #d5dae2; 55 | padding: 15px 25px; 56 | margin-bottom: 20px; 57 | min-height: 45px; 58 | font-size: 13px; 59 | line-height: 15; 60 | font-weight: normal; } 61 | .login-card .form-control::-webkit-input-placeholder { 62 | color: #919aa3; } 63 | .login-card .form-control::-moz-placeholder { 64 | color: #919aa3; } 65 | .login-card .form-control:-ms-input-placeholder { 66 | color: #919aa3; } 67 | .login-card .form-control::-ms-input-placeholder { 68 | color: #919aa3; } 69 | .login-card .form-control::placeholder { 70 | color: #919aa3; } 71 | .login-card .login-btn { 72 | padding: 13px 20px 12px; 73 | background-color: #000; 74 | border-radius: 4px; 75 | font-size: 17px; 76 | font-weight: bold; 77 | line-height: 20px; 78 | color: #fff; 79 | margin-bottom: 24px; } 80 | .login-card .login-btn:hover { 81 | border: 1px solid #000; 82 | background-color: transparent; 83 | color: #000; } 84 | .login-card .forgot-password-link { 85 | font-size: 14px; 86 | color: #919aa3; 87 | margin-bottom: 12px; } 88 | .login-card-footer-text { 89 | font-size: 16px; 90 | color: #0d2366; 91 | margin-bottom: 60px; } 92 | @media (max-width: 767px) { 93 | .login-card-footer-text { 94 | margin-bottom: 24px; } } 95 | .login-card-footer-nav a { 96 | font-size: 14px; 97 | color: #919aa3; } 98 | 99 | /*# sourceMappingURL=login.css.map */ 100 | -------------------------------------------------------------------------------- /auctions/static/auctions/styles.css: -------------------------------------------------------------------------------- 1 | .mdl-grid { 2 | max-width: 600px; 3 | } 4 | .mdl-card__media { 5 | margin: 0; 6 | } 7 | .mdl-card__media > img { 8 | max-width: 100%; 9 | } 10 | .mdl-card__actions { 11 | display: flex; 12 | box-sizing:border-box; 13 | align-items: center; 14 | } 15 | .mdl-card__actions > .mdl-button--icon { 16 | margin-right: 3px; 17 | margin-left: 3px; 18 | } 19 | 20 | span.text { 21 | display: block; 22 | width: 100px; 23 | overflow: hidden; 24 | white-space: nowrap; 25 | text-overflow: ellipsis; 26 | } 27 | .comments-details button.btn.dropdown-toggle, 28 | .comments-details .total-comments { 29 | font-size: 18px; 30 | font-weight: 500; 31 | color: #5e5e5e; 32 | } 33 | .comments-details { 34 | padding: 15px 15px; 35 | } 36 | .comments .comments .dropdown, 37 | .comments .dropup { 38 | position: relative; 39 | } 40 | .comments button { 41 | background-color: transparent; 42 | border: none; 43 | } 44 | .comments .comment-box { 45 | width: 100%; 46 | float: left; 47 | height: 100%; 48 | background-color: #FAFAFA; 49 | padding: 10px 10px 10px; 50 | margin-bottom: 15px; 51 | border-radius: 5px; 52 | border: 1px solid #ddd; 53 | } 54 | .comments .add-comment { 55 | background-color: transparent; 56 | border: none; 57 | position: relative; 58 | margin-bottom: 50px; 59 | } 60 | .comments .commenter-pic { 61 | width: 50px; 62 | height: 50px; 63 | display: inline-block; 64 | border-radius: 100%; 65 | border: 2px solid #fff; 66 | overflow: hidden; 67 | background-color: #fff; 68 | } 69 | .comments .add-comment .commenter-name { 70 | width: 100%; 71 | padding-left: 75px; 72 | position: absolute; 73 | top: 20px; 74 | left: 0px; 75 | } 76 | .comments .add-comment input { 77 | border-top: 0px; 78 | border-bottom: 1px solid #ccc; 79 | border-left: 0px; 80 | border-right: 0px; 81 | outline: 0px; 82 | box-shadow: none; 83 | border-radius: 0; 84 | width: 100%; 85 | padding: 0; 86 | font-weight: normal; 87 | } 88 | .comments .add-comment input:focus { 89 | border-color: #03a9f4; 90 | border-width: 2px; 91 | } 92 | .comments .add-comment button[type=submit] { 93 | background-color: #03a9f4; 94 | color: #fff; 95 | margin-right: 0px; 96 | } 97 | .comments .add-comment button { 98 | background-color: #f5f5f5; 99 | margin: 10px 5px; 100 | font-size: 14px; 101 | text-transform: uppercase; 102 | float: right; 103 | } 104 | .comments .commenter-name .comment-time { 105 | font-weight: normal; 106 | margin-left: 8px; 107 | font-size: 15px; 108 | } 109 | .comments p.comment-txt { 110 | font-size: 15px; 111 | border-bottom: 1px solid #ddd; 112 | padding: 0px 0px 15px; 113 | } 114 | .comments .commenter-name { 115 | display: inline-block; 116 | position: relative; 117 | top: -20px; 118 | left: 10px; 119 | font-size: 16px; 120 | font-weight: bold; 121 | } 122 | .comments .comment-meta { 123 | font-size: 14px; 124 | color: #333; 125 | padding: 2px 5px 0px; 126 | line-height: 20px; 127 | float: right; 128 | } 129 | .comments .reply-box { 130 | display: none; 131 | } 132 | .comments .replied { 133 | background-color: #fff; 134 | width: 95%; 135 | float: right; 136 | margin-top: 15px; 137 | } 138 | 139 | /*======Responsive CSS=======*/ 140 | @media (max-width: 767px){ 141 | .comments .commenter-name { 142 | font-size: 13px; 143 | top: -5px; 144 | } 145 | .comments .commenter-pic { 146 | width: 40px; 147 | height: 40px; 148 | } 149 | .comments .commenter-name a{ 150 | display: block; 151 | } 152 | .comments .commenter-name .comment-time{ 153 | display: block; 154 | margin-left: 0px; 155 | } 156 | } -------------------------------------------------------------------------------- /commerce/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for commerce project. 3 | 4 | Generated by 'django-admin startproject' using Django 3.0.2. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.0/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/3.0/ref/settings/ 11 | """ 12 | import django_heroku 13 | import os 14 | 15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 17 | 18 | 19 | # Quick-start development settings - unsuitable for production 20 | # See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/ 21 | 22 | # SECURITY WARNING: keep the secret key used in production secret! 23 | SECRET_KEY = '6ps8j!crjgrxt34cqbqn7x&b3y%(fny8k8nh21+qa)%ws3fh!q' 24 | 25 | # SECURITY WARNING: don't run with debug turned on in production! 26 | DEBUG = True 27 | 28 | ALLOWED_HOSTS = [] 29 | 30 | 31 | # Application definition 32 | 33 | INSTALLED_APPS = [ 34 | 'auctions', 35 | 'django.contrib.admin', 36 | 'django.contrib.auth', 37 | 'django.contrib.contenttypes', 38 | 'django.contrib.sessions', 39 | 'django.contrib.messages', 40 | 'django.contrib.staticfiles', 41 | 'widget_tweaks', 42 | 'crispy_forms' 43 | ] 44 | 45 | CRISPY_TEMPLATE_PACK = 'bootstrap4' 46 | 47 | MIDDLEWARE = [ 48 | 'django.middleware.security.SecurityMiddleware', 49 | 'django.contrib.sessions.middleware.SessionMiddleware', 50 | 'django.middleware.common.CommonMiddleware', 51 | 'django.middleware.csrf.CsrfViewMiddleware', 52 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 53 | 'django.contrib.messages.middleware.MessageMiddleware', 54 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 55 | ] 56 | 57 | ROOT_URLCONF = 'commerce.urls' 58 | 59 | TEMPLATES = [ 60 | { 61 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 62 | 'DIRS': [], 63 | 'APP_DIRS': True, 64 | 'OPTIONS': { 65 | 'context_processors': [ 66 | 'django.template.context_processors.debug', 67 | 'django.template.context_processors.request', 68 | 'django.contrib.auth.context_processors.auth', 69 | 'django.contrib.messages.context_processors.messages', 70 | ], 71 | }, 72 | }, 73 | ] 74 | 75 | WSGI_APPLICATION = 'commerce.wsgi.application' 76 | 77 | 78 | # Database 79 | # https://docs.djangoproject.com/en/3.0/ref/settings/#databases 80 | 81 | DATABASES = { 82 | 'default': { 83 | 'ENGINE': 'django.db.backends.sqlite3', 84 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 85 | } 86 | } 87 | 88 | AUTH_USER_MODEL = 'auctions.User' 89 | 90 | # Password validation 91 | # https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators 92 | 93 | AUTH_PASSWORD_VALIDATORS = [ 94 | { 95 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 96 | }, 97 | { 98 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 99 | }, 100 | { 101 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 102 | }, 103 | { 104 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 105 | }, 106 | ] 107 | 108 | 109 | # Internationalization 110 | # https://docs.djangoproject.com/en/3.0/topics/i18n/ 111 | 112 | LANGUAGE_CODE = 'en-us' 113 | 114 | TIME_ZONE = 'UTC' 115 | 116 | USE_I18N = True 117 | 118 | USE_L10N = True 119 | 120 | USE_TZ = True 121 | 122 | 123 | # Static files (CSS, JavaScript, Images) 124 | # https://docs.djangoproject.com/en/3.0/howto/static-files/ 125 | 126 | PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__)) 127 | STATIC_URL = '/static/' 128 | STATIC_ROOT = os.path.join(PROJECT_ROOT, 'static') 129 | 130 | 131 | # Activate Django-Heroku. 132 | django_heroku.settings(locals()) 133 | -------------------------------------------------------------------------------- /auctions/templates/auctions/layout.html: -------------------------------------------------------------------------------- 1 | {% load static %} 2 | 3 | 4 | 5 | 6 | {% block title %}Auctions{% endblock %} 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 75 | 76 |
77 | {% block body %} 78 | {% endblock %} 79 | 80 | 81 |
82 |
83 |

Copyright © Angelu Garingo 2020

84 |
85 |
86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /auctions/templates/auctions/watchlist.html: -------------------------------------------------------------------------------- 1 | {% extends "auctions/layout.html" %} 2 | 3 | {% block body %} 4 | 5 | 6 |
7 |
8 |

WATCHLIST

9 |
10 |
11 | 12 | 13 | 14 | 15 |

20 | 21 | 22 |
23 | 24 | 25 |
26 |
27 | 28 | 29 | {% for object in closedbid %} 30 | 31 |
32 |
33 | 34 | {% if object.images %} 35 | 36 | 37 | 38 | {% else %} 39 | 40 | 41 | 42 | {% endif %} 43 | 48 |
49 |
50 | 51 | {% empty %} 52 | You haven't won any bids yet. Start bidding now! 53 | {% endfor %} 54 | 55 | 56 |
57 |
58 |
59 |
60 | 61 | 62 | 63 | 64 | 65 |

66 |

71 |

72 | 73 |   74 |
75 | 76 | 77 |
78 |
79 | 80 | 81 | {% for object in object %} 82 | 83 |
84 |
85 | {% if object.images %} 86 | 87 | 88 | 89 | {% else %} 90 | 91 | 92 | 93 | {% endif %} 94 |
95 | 96 |
{{ object.productnames }}
97 |
98 |
99 | ${{ object.finalbid }} 100 |
101 |
102 |
103 |
104 | 105 | {% empty %} 106 |
107 | Pngtree-it-s-in-the-3845898 108 |
No active listings on your watchlist.
109 |
110 | {% endfor %} 111 | 112 | 113 |
114 |
115 |
116 | 117 | 118 | 119 | {% endblock %} -------------------------------------------------------------------------------- /auctions/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.1 on 2020-09-08 19:34 2 | 3 | import django.contrib.auth.models 4 | import django.contrib.auth.validators 5 | from django.db import migrations, models 6 | import django.utils.timezone 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | initial = True 12 | 13 | dependencies = [ 14 | ('auth', '0012_alter_user_first_name_max_length'), 15 | ] 16 | 17 | operations = [ 18 | migrations.CreateModel( 19 | name='Bidding', 20 | fields=[ 21 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 22 | ('bidder', models.CharField(blank=True, max_length=50, null=True)), 23 | ('bidprice', models.DecimalField(decimal_places=2, max_digits=15)), 24 | ('listingid', models.IntegerField()), 25 | ], 26 | ), 27 | migrations.CreateModel( 28 | name='Category', 29 | fields=[ 30 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 31 | ('name', models.CharField(max_length=20)), 32 | ], 33 | ), 34 | migrations.CreateModel( 35 | name='Closebid', 36 | fields=[ 37 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 38 | ('productnames', models.CharField(max_length=20)), 39 | ('images', models.URLField(blank=True, null=True)), 40 | ('lister', models.CharField(blank=True, max_length=64, null=True)), 41 | ('bidder', models.CharField(blank=True, max_length=64, null=True)), 42 | ('listingid', models.IntegerField()), 43 | ('category', models.CharField(blank=True, max_length=50, null=True)), 44 | ('finalbid', models.DecimalField(blank=True, decimal_places=2, max_digits=15, null=True)), 45 | ], 46 | ), 47 | migrations.CreateModel( 48 | name='Comment', 49 | fields=[ 50 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 51 | ('user', models.CharField(blank=True, max_length=64, null=True)), 52 | ('time', models.DateTimeField(default=django.utils.timezone.now, editable=False)), 53 | ('comment', models.CharField(max_length=30)), 54 | ('listingid', models.IntegerField()), 55 | ], 56 | ), 57 | migrations.CreateModel( 58 | name='Listing', 59 | fields=[ 60 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 61 | ('productnames', models.CharField(max_length=20)), 62 | ('descriptions', models.TextField(max_length=500)), 63 | ('startingbids', models.DecimalField(decimal_places=2, max_digits=15)), 64 | ('images', models.URLField(blank=True, null=True)), 65 | ('category', models.CharField(blank=True, choices=[('FASHION', 'Fashion'), ('TOYS', 'Toys'), ('ELECTRONICS', 'Electronics'), ('HOME', 'Home'), ('BEAUTY & HEALTH', 'Beauty & Health'), ('SPORTS', 'Sports'), ('PETS', 'Pets'), ('BABY', 'Baby'), ('GROCERY', 'Grocery'), ('ENTERTAINMENT', 'Entertainment')], max_length=50, null=True)), 66 | ('lister', models.CharField(blank=True, max_length=50, null=True)), 67 | ('created', models.DateTimeField(default=django.utils.timezone.now, editable=False)), 68 | ], 69 | ), 70 | migrations.CreateModel( 71 | name='Watchlist', 72 | fields=[ 73 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 74 | ('productnames', models.CharField(max_length=20)), 75 | ('images', models.URLField(blank=True, null=True)), 76 | ('finalbid', models.DecimalField(decimal_places=2, max_digits=15)), 77 | ('lister', models.CharField(blank=True, max_length=50, null=True)), 78 | ('watcher', models.CharField(blank=True, max_length=50, null=True)), 79 | ('listingid', models.IntegerField()), 80 | ], 81 | ), 82 | migrations.CreateModel( 83 | name='User', 84 | fields=[ 85 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 86 | ('password', models.CharField(max_length=128, verbose_name='password')), 87 | ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), 88 | ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), 89 | ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')), 90 | ('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')), 91 | ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')), 92 | ('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')), 93 | ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), 94 | ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), 95 | ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), 96 | ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')), 97 | ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')), 98 | ], 99 | options={ 100 | 'verbose_name': 'user', 101 | 'verbose_name_plural': 'users', 102 | 'abstract': False, 103 | }, 104 | managers=[ 105 | ('objects', django.contrib.auth.models.UserManager()), 106 | ], 107 | ), 108 | ] 109 | -------------------------------------------------------------------------------- /auctions/templates/auctions/listing.html: -------------------------------------------------------------------------------- 1 | {% extends "auctions/layout.html" %} 2 | {% load crispy_forms_tags %} 3 | {% block body %} 4 | {% load static %} 5 | 6 |
7 | 8 |
9 | 10 | 11 |
12 | 13 | 14 | 15 | {% if object.images %} 16 | No Image Available for {{ object.productnames}} 17 | {% else %} 18 | No-Image-Available 19 | {% endif %} 20 |


21 |
22 |
23 |
24 |
25 |
Description:
26 |
{{ object.descriptions }}
27 |
28 |
29 |
30 |
31 | 32 | 33 |
34 |
35 |
36 |
37 | 38 | 39 | 40 | {% if user.username %} 41 |
42 | 43 | 44 | 45 | 46 |
47 | {% csrf_token %} 48 | {{ cform.comment|as_crispy_field }} 49 | 50 |
51 |
52 |
53 | {% else %} 54 | 55 | {% endif %} 56 | 57 | 58 | 59 |

60 |

68 | 69 |

70 | 71 | 72 |
73 | {% for obj in comment reversed %} 74 |
75 | 76 | 77 | 78 | 79 | {{ obj.user }} {{ obj.time }} 80 | 81 |

{{ obj.comment }}

82 |
83 | {% endfor %} 84 |
85 | 86 |
87 |
88 |
89 |
90 |
91 | 92 | 93 |
94 |

{{ object.productnames }}

95 | 96 | 97 |
98 | 99 | 100 |
Current Price:
101 |
${{ object.startingbids }}
102 | 103 |
Number of Bids:
104 | {% if bidcount is 0 %}
No bids yet
105 | {% else %}
{{ bidcount }}
{% endif %} 106 | 107 |
Category:
108 |
{{ object.category }}
109 | 110 |
Listed by:
111 |
{{ object.lister }}
112 | 113 |
Date Posted:
114 |
{{ object.created }}
115 |
116 | 117 | 118 | {% if error %} 119 |
120 | 123 | {% endif %} 124 | {% if success %} 125 |
126 | 129 | {% endif %} 130 | 131 | 132 | {% if user.username %} 133 |
134 |
135 | {% csrf_token %} 136 | {{ bidform.bidprice|as_crispy_field }} 137 | 139 |
140 |
141 | {% else %} 142 | 143 | 145 | 146 | {% endif %} 147 | 148 | 149 |
150 | {% if user.username %} 151 | {% if added%} 152 | 154 | {% else %} 155 | 157 | {% endif %} 158 | {% endif %} 159 | 160 | 161 |
162 | {% if user.username %} 163 | {% if lister %} 164 | 166 | {% endif %} 167 | {% endif %} 168 |
169 |
170 |
171 | 172 | 173 | {% endblock %} 174 | -------------------------------------------------------------------------------- /auctions/views.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth import authenticate, login, logout 2 | from django.db import IntegrityError 3 | from django.http import HttpResponse, HttpResponseRedirect, Http404, HttpResponseBadRequest 4 | from django.shortcuts import render, redirect 5 | from django.urls import reverse 6 | from django import forms 7 | from django.contrib.auth.decorators import login_required 8 | from django.contrib.sessions.models import Session 9 | from datetime import datetime 10 | from django.utils.timezone import now 11 | 12 | 13 | from .models import User, Listing, Bidding, Watchlist, Closebid, Comment, Category 14 | 15 | from .forms import ListingForm, BiddingForm, CommentForm 16 | 17 | def index(request): 18 | listing = Listing.objects.all() 19 | try: 20 | watch = Watchlist.objects.filter(watcher=request.user.username) 21 | watchcount=len(watch) 22 | except: 23 | watchcount=None 24 | return render(request, "auctions/index.html", { 25 | 'object': listing, 26 | 'watchcount': watchcount 27 | }) 28 | 29 | @login_required 30 | def createlisting(request): 31 | creator = Listing.objects.all() 32 | form = ListingForm(request.POST or None) 33 | try: 34 | watch = Watchlist.objects.filter(watcher=request.user.username) 35 | watchcount = len(watch) 36 | except: 37 | watchcount = None 38 | if request.method == "POST": 39 | if form.is_valid(): 40 | now = datetime.now() #save date created with current timezone 41 | fs = form.save(commit=False) 42 | fs.lister = request.user #save info not listed at forms.py 43 | fs.created = now 44 | fs.save() 45 | return HttpResponseRedirect(reverse('index')) 46 | else: 47 | return render(request, "auctions/create.html", { 48 | 'form': form, 49 | 'creator': creator, 50 | 'watchcount': watchcount 51 | }) 52 | 53 | def listingpage(request,id): 54 | listing = Listing.objects.get(id=id) 55 | comment = Comment.objects.filter(listingid=id) 56 | try: 57 | cform = CommentForm(request.POST or None) 58 | bidform = BiddingForm(request.POST or None) 59 | except: 60 | return redirect('index') 61 | if request.user.username: 62 | try: 63 | if Watchlist.objects.get(watcher=request.user.username, listingid=id): 64 | added=True 65 | except: 66 | added = False 67 | try: 68 | watch = Watchlist.objects.filter(watcher=request.user.username) 69 | watchcount=len(watch) 70 | except: 71 | watchcount=None 72 | try: 73 | ccount = Comment.objects.filter(listingid=id) 74 | ccount = len(ccount) 75 | except: 76 | ccount = len(ccount) 77 | try: 78 | 79 | if listing.lister == request.user.username : 80 | lister = True 81 | else: 82 | lister = False 83 | except: 84 | return redirect('index') 85 | else: 86 | ccount = Comment.objects.filter(listingid=id) 87 | ccount = len(ccount) 88 | added = False 89 | lister = False 90 | watchcount = None 91 | try: 92 | bid = Bidding.objects.filter(listingid=id) 93 | bidcount = len(bid) 94 | listing = Listing.objects.get(id=id) 95 | except: 96 | bicount = None 97 | return render(request, "auctions/listing.html", { 98 | 'object': listing, 99 | 'added': added, 100 | 'bidform': bidform, 101 | "watchcount": watchcount, 102 | "error":request.COOKIES.get('error'), 103 | "success":request.COOKIES.get('success'), 104 | "bidcount": bidcount, 105 | "lister": lister, 106 | 'cform': cform, 107 | "comment": comment, 108 | "ccount": ccount 109 | }) 110 | 111 | @login_required 112 | def addwatch(request, id): 113 | if request.user.username: 114 | listing = Listing.objects.get(id=id) 115 | watchers = Watchlist(watcher = request.user.username, listingid = id) 116 | watchers.lister = listing.lister 117 | watchers.finalbid = listing.startingbids 118 | watchers.productnames = listing.productnames 119 | watchers.images = listing.images 120 | watchers.save() 121 | return redirect('listingpage', id=id) 122 | else: 123 | return redirect('index') 124 | 125 | @login_required 126 | def removewatch(request,id): 127 | if request.user.username: 128 | try: 129 | Watchlist.objects.filter(listingid=id).delete() 130 | return redirect('listingpage', id=id) 131 | except: 132 | return redirect('listingpage', id=id) 133 | else: 134 | return redirect('index') 135 | 136 | @login_required 137 | def watchlist(request): 138 | try: 139 | watchlist = Watchlist.objects.filter(watcher=request.user.username) 140 | closebid = Closebid.objects.filter(bidder=request.user.username) 141 | watchcount = len(watchlist) #count how many rows in table Watchlist using len() 142 | except: 143 | watchcount = None 144 | try: 145 | bidwincount = Closebid.objects.filter(bidder = request.user.username) 146 | bidwincount = len(bidwincount) 147 | except: 148 | binwincoun = None 149 | try: 150 | if Watchlist.objects.get(listingid=listingid): 151 | closed = True 152 | else: 153 | closed = False 154 | except: 155 | closed = False 156 | return render(request, "auctions/watchlist.html", { 157 | 'object': watchlist, 158 | "watchcount": watchcount, 159 | "closedbid": closebid, 160 | "closed" : closed, 161 | "bidwincount": bidwincount 162 | }) 163 | 164 | @login_required 165 | def bid(request, listingid): 166 | current = Listing.objects.get(id=listingid) 167 | current = current.startingbids 168 | bidform = BiddingForm(request.POST or None) 169 | if request.user.username: 170 | bid = float(request.POST.get("bidprice")) 171 | if bid > current: 172 | listing = Listing.objects.get(id=listingid) 173 | listing.startingbids = bid 174 | listing.save() 175 | try: 176 | if Bidding.objects.filter(id=listingid): 177 | bidrow = Bidding.objects.filter(id=listingid) 178 | bidrow.delete() 179 | fs = bidform.save(commit=False) 180 | fs.bidder = request.user.username 181 | fs.listingid = listingid 182 | fs.save() 183 | except: 184 | fs = bidform.save(commit=False) 185 | fs.bidder = request.user 186 | fs.listingid = listingid 187 | fs.save() 188 | response = redirect('listingpage', id=listingid) 189 | response.set_cookie('success','Successful Bid! Your bid is currently the highest bid.', max_age=1) 190 | return response 191 | else: 192 | response = redirect('listingpage', id=listingid) 193 | response.set_cookie('error','Your bid must be higher than the current price!', max_age=1) 194 | return response 195 | else: 196 | return redirect('index') 197 | 198 | @login_required 199 | def closebid(request, listingid): 200 | if request.user.username: 201 | try: 202 | listing = Listing.objects.get(id=listingid) 203 | except: 204 | return redirect('index') 205 | closebid = Closebid() 206 | name = listing.productnames 207 | closebid.lister = listing.lister 208 | closebid.listingid = listingid 209 | closebid.productnames = listing.productnames 210 | closebid.images = listing.images 211 | closebid.category = listing.category 212 | try: 213 | bid = Bidding.objects.get(listingid=listingid,bidprice=listing.startingbids) 214 | closebid.bidder = bid.bidder 215 | closebid.finalbid = bid.bidprice 216 | closebid.save() 217 | bid.delete() 218 | except: 219 | closebid.bidder = listing.lister 220 | closebid.finalbid = listing.startingbids 221 | closebid.save() 222 | try: 223 | if Watchlist.objects.filter(listingid=listingid): 224 | watch = Watchlist.objects.filter(listingid=listingid) 225 | watch.delete() 226 | else: 227 | pass 228 | except: 229 | pass 230 | try: 231 | comment = Comment.objects.filter(listingid=listingid) 232 | comment.delete() 233 | except: 234 | pass 235 | try: 236 | bid = Bid.objects.filter(listingid=listingid) 237 | bid.delete() 238 | except: 239 | pass 240 | try: 241 | closebidlist = Closebid.objects.get(listingid=listingid) 242 | except: 243 | closebid.lister = listing.lister 244 | closebid.bidder = listing.lister 245 | closebid.listingid = listingid 246 | closebid.finalbid = listing.startingbids 247 | closebid.productnames = listing.productnames 248 | closebid.images = listing.images 249 | closebid.category = listing.category 250 | closebid.save() 251 | closebidlist = Closebid.objects.get(listingid=listingid) 252 | listing.delete() 253 | try: 254 | watch = Watchlist.objects.filter(watcher=request.user.username) 255 | watchcount=len(watch) 256 | except: 257 | watchcount = None 258 | return render(request,"auctions/winner.html",{ 259 | "closebidlist": closebidlist, 260 | "name": name, 261 | "watchcount":watchcount 262 | }) 263 | else: 264 | return redirect('index') 265 | 266 | @login_required 267 | def closed(request, listingid): 268 | closed = Closebid.objects.get(listingid=listingid) 269 | try: 270 | watch = Watchlist.objects.filter(watcher=request.user.username) 271 | watchcount = len(watch) 272 | except: 273 | watchcount = None 274 | return render(request, "auctions/closed.html", { 275 | "object": closed, 276 | "watchcount": watchcount 277 | }) 278 | 279 | @login_required 280 | def comment(request, listingid): 281 | if request.method == "POST": 282 | comment = Comment.objects.all() 283 | cform = CommentForm(request.POST or None) 284 | if cform.is_valid(): 285 | now = datetime.now() 286 | fs = cform.save(commit=False) 287 | fs.listingid = listingid 288 | fs.user = request.user.username 289 | fs.time = now 290 | fs.save() 291 | return redirect('listingpage', id=listingid) 292 | else: 293 | return redirect('index') 294 | 295 | def category(request): 296 | category = Category.objects.all() 297 | closedbid = Closebid.objects.all() 298 | try: 299 | if Watchlist.objects.get(listingid=listingid): 300 | closed = True 301 | else: 302 | closed = False 303 | except: 304 | closed = False 305 | try: 306 | watch = Watchlist.objects.filter(watcher=request.user.username) 307 | watchcount = len(watch) 308 | except: 309 | watchcount = None 310 | return render(request, "auctions/categories.html", { 311 | "object": category, 312 | "watchcount": watchcount, 313 | "closed": closed, 314 | "closedbid": closedbid 315 | }) 316 | 317 | def categorylistings(request, cats): 318 | category_posts = Listing.objects.filter(category=cats) 319 | try: 320 | watch = Watchlist.objects.filter(watcher=request.user.username) 321 | watchcount = len(watch) 322 | except: 323 | watchcount = None 324 | return render(request, 'auctions/categorylistings.html', { 325 | 'cats': cats, 326 | 'category_posts': category_posts, 327 | 'watchcount': watchcount 328 | }) 329 | 330 | def allclosed(request): 331 | closedlist = Closebid.objects.all() 332 | try: 333 | watch = Watchlist.objects.filter(watcher=request.user.username) 334 | watchcount = len(watch) 335 | except: 336 | watchcount = None 337 | return render(request, 'auctions/allclosed.html', { 338 | 'closedlist': closedlist, 339 | 'watchcount': watchcount 340 | }) 341 | 342 | def login_view(request): 343 | if request.method == "POST": 344 | # Attempt to sign user in 345 | username = request.POST["username"] 346 | password = request.POST["password"] 347 | user = authenticate(request, username=username, password=password) 348 | 349 | # Check if authentication successful 350 | if user is not None: 351 | login(request, user) 352 | return HttpResponseRedirect(reverse("index")) 353 | else: 354 | return render(request, "auctions/login.html", { 355 | "message": "Invalid username and/or password." 356 | }) 357 | else: 358 | return render(request, "auctions/login.html") 359 | 360 | 361 | def logout_view(request): 362 | logout(request) 363 | return HttpResponseRedirect(reverse("index")) 364 | 365 | 366 | def register(request): 367 | if request.method == "POST": 368 | username = request.POST["username"] 369 | email = request.POST["email"] 370 | 371 | # Ensure password matches confirmation 372 | password = request.POST["password"] 373 | confirmation = request.POST["confirmation"] 374 | if password != confirmation: 375 | return render(request, "auctions/register.html", { 376 | "message": "Passwords must match." 377 | }) 378 | 379 | # Attempt to create new user 380 | try: 381 | user = User.objects.create_user(username, email, password) 382 | user.save() 383 | except IntegrityError: 384 | return render(request, "auctions/register.html", { 385 | "message": "Username already taken." 386 | }) 387 | login(request, user) 388 | return HttpResponseRedirect(reverse("index")) 389 | else: 390 | return render(request, "auctions/register.html") 391 | --------------------------------------------------------------------------------