Skip to content
Browse files

chapter 4

  • Loading branch information...
1 parent e43099c commit 9c9efa94cc128cd7dea8784925abcf71684fb31b @ButuzGOL committed
View
0 catalog/__init__.py
No changes.
View
32 catalog/admin.py
@@ -0,0 +1,32 @@
+from django.contrib import admin
+from ecomstore.catalog.models import Product, Category
+from ecomstore.catalog.forms import ProductAdminForm
+
+class ProductAdmin(admin.ModelAdmin):
+ form = ProductAdminForm
+ # sets values for how the admin site lists your products
+ list_display = ('name', 'price', 'old_price', 'created_at', 'updated_at',)
+ list_display_links = ('name',)
+ list_per_page = 50
+ ordering = ['-created_at']
+
+ earch_fields = ['name', 'description', 'meta_keywords', 'meta_description']
+ exclude = ('created_at', 'updated_at',)
+ prepopulated_fields = {'slug' : ('name',)}
+
+# registers your product model with the admin site
+admin.site.register(Product, ProductAdmin)
+
+class CategoryAdmin(admin.ModelAdmin):
+ #sets up values for how admin site lists categories
+ list_display = ('name', 'created_at', 'updated_at',)
+ list_display_links = ('name',)
+ list_per_page = 20
+ ordering = ['name']
+ search_fields = ['name', 'description', 'meta_keywords', 'meta_description']
+ exclude = ('created_at', 'updated_at',)
+ # sets up slug to be generated from category name
+ prepopulated_fields = {'slug' : ('name',)}
+
+admin.site.register(Category, CategoryAdmin)
+
View
11 catalog/forms.py
@@ -0,0 +1,11 @@
+from django import forms
+from ecomstore.catalog.models import Product
+
+class ProductAdminForm(forms.ModelForm):
+ class Meta:
+ model = Product
+
+ def clean_price(self):
+ if self.cleaned_data['price'] <= 0:
+ raise forms.ValidationError('Price must be greater than zero.')
+ return self.cleaned_data['price']
View
67 catalog/models.py
@@ -0,0 +1,67 @@
+from django.db import models
+
+class Category(models.Model):
+ name = models.CharField(max_length=50)
+ slug = models.SlugField(max_length=50, unique=True,
+ help_text='Unique value for product page URL, created from name.')
+ description = models.TextField()
+ is_active = models.BooleanField(default=True)
+ meta_keywords = models.CharField("Meta Keywords", max_length=255,
+ help_text='Comma-delimited set of SEO keywords for meta tag')
+ meta_description = models.CharField("Meta Description", max_length=255,
+ help_text='Content for description meta tag')
+ created_at = models.DateTimeField(auto_now_add=True)
+ updated_at = models.DateTimeField(auto_now=True)
+
+ class Meta:
+ db_table = 'categories'
+ ordering = ['-created_at']
+ verbose_name_plural = 'Categories'
+
+ def __unicode__(self):
+ return self.name
+
+ @models.permalink
+ def get_absolute_url(self):
+ return ('catalog_category', (), { 'category_slug': self.slug })
+
+class Product(models.Model):
+ name = models.CharField(max_length=255, unique=True)
+ slug = models.SlugField(max_length=255, unique=True,
+ help_text='Unique value for product page URL, created from name.')
+ brand = models.CharField(max_length=50)
+ sku = models.CharField(max_length=50)
+ price = models.DecimalField(max_digits=9, decimal_places=2)
+ old_price = models.DecimalField(max_digits=9, decimal_places=2, blank=True,
+ default=0.00)
+ image = models.CharField(max_length=50)
+ is_active = models.BooleanField(default=True)
+ is_bestseller = models.BooleanField(default=False)
+ is_featured = models.BooleanField(default=False)
+ quantity = models.IntegerField()
+ description = models.TextField()
+ meta_keywords = models.CharField(max_length=255,
+ help_text='Comma-delimited set of SEO keywords for meta tag')
+ meta_description = models.CharField(max_length=255,
+ help_text='Content for description meta tag')
+ created_at = models.DateTimeField(auto_now_add=True)
+ updated_at = models.DateTimeField(auto_now=True)
+ categories = models.ManyToManyField(Category)
+
+ class Meta:
+ db_table = 'products'
+ ordering = ['-created_at']
+
+ def __unicode__(self):
+ return self.name
+
+ @models.permalink
+ def get_absolute_url(self):
+ return ('catalog_product', (), { 'product_slug': self.slug })
+
+ def sale_price(self):
+ if self.old_price > self.price:
+ return self.price
+ else:
+ return None
+
View
23 catalog/tests.py
@@ -0,0 +1,23 @@
+"""
+This file demonstrates two different styles of tests (one doctest and one
+unittest). These will both pass when you run "manage.py test".
+
+Replace these with more appropriate tests for your application.
+"""
+
+from django.test import TestCase
+
+class SimpleTest(TestCase):
+ def test_basic_addition(self):
+ """
+ Tests that 1 + 1 always equals 2.
+ """
+ self.failUnlessEqual(1 + 1, 2)
+
+__test__ = {"doctest": """
+Another way to test that 1 + 1 is equal to 2.
+
+>>> 1 + 1 == 2
+True
+"""}
+
View
11 catalog/urls.py
@@ -0,0 +1,11 @@
+from django.conf.urls.defaults import *
+
+urlpatterns = patterns('ecomstore.catalog.views',
+ (r'^$', 'index', { 'template_name':'catalog/index.html'}, 'catalog_home'),
+ (r'^category/(?P<category_slug>[-\w]+)/$',
+ 'show_category', {'template_name':'catalog/category.html'},
+ 'catalog_category'),
+ (r'^product/(?P<product_slug>[-\w]+)/$',
+ 'show_product', {'template_name':'catalog/product.html'},
+ 'catalog_product'),
+)
View
28 catalog/views.py
@@ -0,0 +1,28 @@
+from django.shortcuts import get_object_or_404, render_to_response
+from ecomstore.catalog.models import Category, Product
+from django.template import RequestContext
+
+def index(request, template_name="catalog/index.html"):
+ page_title = 'Musical Instruments and Sheet Music for Musicians'
+ return render_to_response(template_name, locals(),
+ context_instance=RequestContext(request))
+
+def show_category(request, category_slug,
+ template_name="catalog/category.html"):
+ c = get_object_or_404(Category, slug=category_slug)
+ products = c.product_set.all()
+ page_title = c.name
+ meta_keywords = c.meta_keywords
+ meta_description = c.meta_description
+ return render_to_response(template_name, locals(),
+ context_instance=RequestContext(request))
+
+def show_product(request, product_slug, template_name="catalog/product.html"):
+ p = get_object_or_404(Product, slug=product_slug)
+ categories = p.categories.filter(is_active=True)
+ page_title = p.name
+ meta_keywords = p.meta_keywords
+ meta_description = p.meta_description
+ return render_to_response(template_name, locals(),
+ context_instance=RequestContext(request))
+
View
400 global_settings.py
@@ -0,0 +1,400 @@
+# Default Django settings. Override these with settings in the module
+# pointed-to by the DJANGO_SETTINGS_MODULE environment variable.
+
+# This is defined here as a do-nothing function because we can't import
+# django.utils.translation -- that module depends on the settings.
+gettext_noop = lambda s: s
+
+####################
+# CORE #
+####################
+
+DEBUG = False
+TEMPLATE_DEBUG = False
+
+# Whether the framework should propagate raw exceptions rather than catching
+# them. This is useful under some testing siutations and should never be used
+# on a live site.
+DEBUG_PROPAGATE_EXCEPTIONS = False
+
+# Whether to use the "Etag" header. This saves bandwidth but slows down performance.
+USE_ETAGS = False
+
+# People who get code error notifications.
+# In the format (('Full Name', 'email@domain.com'), ('Full Name', 'anotheremail@domain.com'))
+ADMINS = ()
+
+# Tuple of IP addresses, as strings, that:
+# * See debug comments, when DEBUG is true
+# * Receive x-headers
+INTERNAL_IPS = ()
+
+# Local time zone for this installation. All choices can be found here:
+# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name (although not all
+# systems may support all possibilities).
+TIME_ZONE = 'America/Chicago'
+
+# Language code for this installation. All choices can be found here:
+# http://www.i18nguy.com/unicode/language-identifiers.html
+LANGUAGE_CODE = 'en-us'
+
+# Languages we provide translations for, out of the box. The language name
+# should be the utf-8 encoded local name for the language.
+LANGUAGES = (
+ ('ar', gettext_noop('Arabic')),
+ ('bn', gettext_noop('Bengali')),
+ ('bg', gettext_noop('Bulgarian')),
+ ('ca', gettext_noop('Catalan')),
+ ('cs', gettext_noop('Czech')),
+ ('cy', gettext_noop('Welsh')),
+ ('da', gettext_noop('Danish')),
+ ('de', gettext_noop('German')),
+ ('el', gettext_noop('Greek')),
+ ('en', gettext_noop('English')),
+ ('es', gettext_noop('Spanish')),
+ ('et', gettext_noop('Estonian')),
+ ('es-ar', gettext_noop('Argentinean Spanish')),
+ ('eu', gettext_noop('Basque')),
+ ('fa', gettext_noop('Persian')),
+ ('fi', gettext_noop('Finnish')),
+ ('fr', gettext_noop('French')),
+ ('ga', gettext_noop('Irish')),
+ ('gl', gettext_noop('Galician')),
+ ('hu', gettext_noop('Hungarian')),
+ ('he', gettext_noop('Hebrew')),
+ ('hi', gettext_noop('Hindi')),
+ ('hr', gettext_noop('Croatian')),
+ ('is', gettext_noop('Icelandic')),
+ ('it', gettext_noop('Italian')),
+ ('ja', gettext_noop('Japanese')),
+ ('ka', gettext_noop('Georgian')),
+ ('ko', gettext_noop('Korean')),
+ ('km', gettext_noop('Khmer')),
+ ('kn', gettext_noop('Kannada')),
+ ('lv', gettext_noop('Latvian')),
+ ('lt', gettext_noop('Lithuanian')),
+ ('mk', gettext_noop('Macedonian')),
+ ('nl', gettext_noop('Dutch')),
+ ('no', gettext_noop('Norwegian')),
+ ('pl', gettext_noop('Polish')),
+ ('pt', gettext_noop('Portuguese')),
+ ('pt-br', gettext_noop('Brazilian Portuguese')),
+ ('ro', gettext_noop('Romanian')),
+ ('ru', gettext_noop('Russian')),
+ ('sk', gettext_noop('Slovak')),
+ ('sl', gettext_noop('Slovenian')),
+ ('sr', gettext_noop('Serbian')),
+ ('sv', gettext_noop('Swedish')),
+ ('ta', gettext_noop('Tamil')),
+ ('te', gettext_noop('Telugu')),
+ ('th', gettext_noop('Thai')),
+ ('tr', gettext_noop('Turkish')),
+ ('uk', gettext_noop('Ukrainian')),
+ ('zh-cn', gettext_noop('Simplified Chinese')),
+ ('zh-tw', gettext_noop('Traditional Chinese')),
+)
+
+# Languages using BiDi (right-to-left) layout
+LANGUAGES_BIDI = ("he", "ar", "fa")
+
+# If you set this to False, Django will make some optimizations so as not
+# to load the internationalization machinery.
+USE_I18N = True
+LOCALE_PATHS = ()
+LANGUAGE_COOKIE_NAME = 'django_language'
+
+# Not-necessarily-technical managers of the site. They get broken link
+# notifications and other various e-mails.
+MANAGERS = ADMINS
+
+# Default content type and charset to use for all HttpResponse objects, if a
+# MIME type isn't manually specified. These are used to construct the
+# Content-Type header.
+DEFAULT_CONTENT_TYPE = 'text/html'
+DEFAULT_CHARSET = 'utf-8'
+
+# Encoding of files read from disk (template and initial SQL files).
+FILE_CHARSET = 'utf-8'
+
+# E-mail address that error messages come from.
+SERVER_EMAIL = 'root@localhost'
+
+# Whether to send broken-link e-mails.
+SEND_BROKEN_LINK_EMAILS = False
+
+# Database connection info.
+DATABASE_ENGINE = '' # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
+DATABASE_NAME = '' # Or path to database file if using sqlite3.
+DATABASE_USER = '' # Not used with sqlite3.
+DATABASE_PASSWORD = '' # Not used with sqlite3.
+DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3.
+DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3.
+DATABASE_OPTIONS = {} # Set to empty dictionary for default.
+
+# Host for sending e-mail.
+EMAIL_HOST = 'localhost'
+
+# Port for sending e-mail.
+EMAIL_PORT = 25
+
+# Optional SMTP authentication information for EMAIL_HOST.
+EMAIL_HOST_USER = ''
+EMAIL_HOST_PASSWORD = ''
+EMAIL_USE_TLS = False
+
+# List of strings representing installed apps.
+INSTALLED_APPS = ()
+
+# List of locations of the template source files, in search order.
+TEMPLATE_DIRS = ()
+
+# List of callables that know how to import templates from various sources.
+# See the comments in django/core/template/loader.py for interface
+# documentation.
+TEMPLATE_LOADERS = (
+ 'django.template.loaders.filesystem.load_template_source',
+ 'django.template.loaders.app_directories.load_template_source',
+# 'django.template.loaders.eggs.load_template_source',
+)
+
+# List of processors used by RequestContext to populate the context.
+# Each one should be a callable that takes the request object as its
+# only parameter and returns a dictionary to add to the context.
+TEMPLATE_CONTEXT_PROCESSORS = (
+ 'django.core.context_processors.auth',
+ 'django.core.context_processors.debug',
+ 'django.core.context_processors.i18n',
+ 'django.core.context_processors.media',
+# 'django.core.context_processors.request',
+)
+
+# Output to use in template system for invalid (e.g. misspelled) variables.
+TEMPLATE_STRING_IF_INVALID = ''
+
+# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
+# trailing slash.
+# Examples: "http://foo.com/media/", "/media/".
+ADMIN_MEDIA_PREFIX = '/media/'
+
+# Default e-mail address to use for various automated correspondence from
+# the site managers.
+DEFAULT_FROM_EMAIL = 'webmaster@localhost'
+
+# Subject-line prefix for email messages send with django.core.mail.mail_admins
+# or ...mail_managers. Make sure to include the trailing space.
+EMAIL_SUBJECT_PREFIX = '[Django] '
+
+# Whether to append trailing slashes to URLs.
+APPEND_SLASH = True
+
+# Whether to prepend the "www." subdomain to URLs that don't have it.
+PREPEND_WWW = False
+
+# Override the server-derived value of SCRIPT_NAME
+FORCE_SCRIPT_NAME = None
+
+# List of compiled regular expression objects representing User-Agent strings
+# that are not allowed to visit any page, systemwide. Use this for bad
+# robots/crawlers. Here are a few examples:
+# import re
+# DISALLOWED_USER_AGENTS = (
+# re.compile(r'^NaverBot.*'),
+# re.compile(r'^EmailSiphon.*'),
+# re.compile(r'^SiteSucker.*'),
+# re.compile(r'^sohu-search')
+# )
+DISALLOWED_USER_AGENTS = ()
+
+ABSOLUTE_URL_OVERRIDES = {}
+
+# Tuple of strings representing allowed prefixes for the {% ssi %} tag.
+# Example: ('/home/html', '/var/www')
+ALLOWED_INCLUDE_ROOTS = ()
+
+# If this is a admin settings module, this should be a list of
+# settings modules (in the format 'foo.bar.baz') for which this admin
+# is an admin.
+ADMIN_FOR = ()
+
+# 404s that may be ignored.
+IGNORABLE_404_STARTS = ('/cgi-bin/', '/_vti_bin', '/_vti_inf')
+IGNORABLE_404_ENDS = ('mail.pl', 'mailform.pl', 'mail.cgi', 'mailform.cgi', 'favicon.ico', '.php')
+
+# A secret key for this particular Django installation. Used in secret-key
+# hashing algorithms. Set this in your settings, or Django will complain
+# loudly.
+SECRET_KEY = ''
+
+# Default file storage mechanism that holds media.
+DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'
+
+# Absolute path to the directory that holds media.
+# Example: "/home/media/media.lawrence.com/"
+MEDIA_ROOT = ''
+
+# URL that handles the media served from MEDIA_ROOT.
+# Example: "http://media.lawrence.com"
+MEDIA_URL = ''
+
+# List of upload handler classes to be applied in order.
+FILE_UPLOAD_HANDLERS = (
+ 'django.core.files.uploadhandler.MemoryFileUploadHandler',
+ 'django.core.files.uploadhandler.TemporaryFileUploadHandler',
+)
+
+# Maximum size, in bytes, of a request before it will be streamed to the
+# file system instead of into memory.
+FILE_UPLOAD_MAX_MEMORY_SIZE = 2621440 # i.e. 2.5 MB
+
+# Directory in which upload streamed files will be temporarily saved. A value of
+# `None` will make Django use the operating system's default temporary directory
+# (i.e. "/tmp" on *nix systems).
+FILE_UPLOAD_TEMP_DIR = None
+
+# The numeric mode to set newly-uploaded files to. The value should be a mode
+# you'd pass directly to os.chmod; see http://docs.python.org/lib/os-file-dir.html.
+FILE_UPLOAD_PERMISSIONS = None
+
+# Default formatting for date objects. See all available format strings here:
+# http://docs.djangoproject.com/en/dev/ref/templates/builtins/#now
+DATE_FORMAT = 'N j, Y'
+
+# Default formatting for datetime objects. See all available format strings here:
+# http://docs.djangoproject.com/en/dev/ref/templates/builtins/#now
+DATETIME_FORMAT = 'N j, Y, P'
+
+# Default formatting for time objects. See all available format strings here:
+# http://docs.djangoproject.com/en/dev/ref/templates/builtins/#now
+TIME_FORMAT = 'P'
+
+# Default formatting for date objects when only the year and month are relevant.
+# See all available format strings here:
+# http://docs.djangoproject.com/en/dev/ref/templates/builtins/#now
+YEAR_MONTH_FORMAT = 'F Y'
+
+# Default formatting for date objects when only the month and day are relevant.
+# See all available format strings here:
+# http://docs.djangoproject.com/en/dev/ref/templates/builtins/#now
+MONTH_DAY_FORMAT = 'F j'
+
+# Do you want to manage transactions manually?
+# Hint: you really don't!
+TRANSACTIONS_MANAGED = False
+
+# The User-Agent string to use when checking for URL validity through the
+# isExistingURL validator.
+from django import get_version
+URL_VALIDATOR_USER_AGENT = "Django/%s (http://www.djangoproject.com)" % get_version()
+
+# The tablespaces to use for each model when not specified otherwise.
+DEFAULT_TABLESPACE = ''
+DEFAULT_INDEX_TABLESPACE = ''
+
+##############
+# MIDDLEWARE #
+##############
+
+# List of middleware classes to use. Order is important; in the request phase,
+# this middleware classes will be applied in the order given, and in the
+# response phase the middleware will be applied in reverse order.
+MIDDLEWARE_CLASSES = (
+ 'django.middleware.common.CommonMiddleware',
+ 'django.contrib.sessions.middleware.SessionMiddleware',
+ 'django.contrib.auth.middleware.AuthenticationMiddleware',
+# 'django.middleware.http.ConditionalGetMiddleware',
+# 'django.middleware.gzip.GZipMiddleware',
+)
+
+############
+# SESSIONS #
+############
+
+SESSION_COOKIE_NAME = 'sessionid' # Cookie name. This can be whatever you want.
+SESSION_COOKIE_AGE = 60 * 60 * 24 * 7 * 2 # Age of cookie, in seconds (default: 2 weeks).
+SESSION_COOKIE_DOMAIN = None # A string like ".lawrence.com", or None for standard domain cookie.
+SESSION_COOKIE_SECURE = False # Whether the session cookie should be secure (https:// only).
+SESSION_COOKIE_PATH = '/' # The path of the session cookie.
+SESSION_SAVE_EVERY_REQUEST = False # Whether to save the session data on every request.
+SESSION_EXPIRE_AT_BROWSER_CLOSE = False # Whether a user's session cookie expires when the Web browser is closed.
+SESSION_ENGINE = 'django.contrib.sessions.backends.db' # The module to store session data
+SESSION_FILE_PATH = None # Directory to store session files if using the file session module. If None, the backend will use a sensible default.
+
+#########
+# CACHE #
+#########
+
+# The cache backend to use. See the docstring in django.core.cache for the
+# possible values.
+CACHE_BACKEND = 'locmem://'
+CACHE_MIDDLEWARE_KEY_PREFIX = ''
+CACHE_MIDDLEWARE_SECONDS = 600
+
+####################
+# COMMENTS #
+####################
+
+COMMENTS_ALLOW_PROFANITIES = False
+
+# The profanities that will trigger a validation error in the
+# 'hasNoProfanities' validator. All of these should be in lowercase.
+PROFANITIES_LIST = ('asshat', 'asshead', 'asshole', 'cunt', 'fuck', 'gook', 'nigger', 'shit')
+
+# The group ID that designates which users are banned.
+# Set to None if you're not using it.
+COMMENTS_BANNED_USERS_GROUP = None
+
+# The group ID that designates which users can moderate comments.
+# Set to None if you're not using it.
+COMMENTS_MODERATORS_GROUP = None
+
+# The group ID that designates the users whose comments should be e-mailed to MANAGERS.
+# Set to None if you're not using it.
+COMMENTS_SKETCHY_USERS_GROUP = None
+
+# The system will e-mail MANAGERS the first COMMENTS_FIRST_FEW comments by each
+# user. Set this to 0 if you want to disable it.
+COMMENTS_FIRST_FEW = 0
+
+# A tuple of IP addresses that have been banned from participating in various
+# Django-powered features.
+BANNED_IPS = ()
+
+##################
+# AUTHENTICATION #
+##################
+
+AUTHENTICATION_BACKENDS = ('django.contrib.auth.backends.ModelBackend',)
+
+LOGIN_URL = '/accounts/login/'
+
+LOGOUT_URL = '/accounts/logout/'
+
+LOGIN_REDIRECT_URL = '/accounts/profile/'
+
+# The number of days a password reset link is valid for
+PASSWORD_RESET_TIMEOUT_DAYS = 3
+
+###########
+# TESTING #
+###########
+
+# The name of the method to use to invoke the test suite
+TEST_RUNNER = 'django.test.simple.run_tests'
+
+# The name of the database to use for testing purposes.
+# If None, a name of 'test_' + DATABASE_NAME will be assumed
+TEST_DATABASE_NAME = None
+
+# Strings used to set the character set and collation order for the test
+# database. These values are passed literally to the server, so they are
+# backend-dependent. If None, no special settings are sent (system defaults are
+# used).
+TEST_DATABASE_CHARSET = None
+TEST_DATABASE_COLLATION = None
+
+############
+# FIXTURES #
+############
+
+# The list of directories to search for fixtures
+FIXTURE_DIRS = ()
View
2 preview/views.py
@@ -1,4 +1,4 @@
from django.shortcuts import render_to_response
def home(request):
- return render_to_response("index.html")
+ return render_to_response("index.html")
View
19 settings.py
@@ -80,5 +80,24 @@
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
+ 'django.contrib.admin',
+ 'ecomstore.catalog',
+ 'ecomstore.utils',
'djangodblog',
)
+
+SITE_NAME = 'Modern Musician'
+META_KEYWORDS = 'Music, instruments, music accessories, musician supplies'
+META_DESCRIPTION = 'Modern Musician is an online supplier of instruments, \
+ sheet music, and other accessories for musicians'
+MEDIA_URL = '/static/'
+
+TEMPLATE_CONTEXT_PROCESSORS = (
+ 'django.core.context_processors.auth',
+ 'django.core.context_processors.debug',
+ 'django.core.context_processors.i18n',
+ 'django.core.context_processors.media',
+ 'ecomstore.utils.context_processors.ecomstore',
+)
+
+
View
20 static/css.css
@@ -91,4 +91,24 @@ a.skip_link{
background-color:White;
text-decoration:none;
}
+a{
+ color:#98AC5E;
+ font-weight:bold;
+ text-decoration:none;
+}
+a:hover{
+ text-decoration:underline;
+}
+/* category page styles */
+div.product_thumbnail{
+ text-align:center;
+ float:left;
+ width:150px;
+ height:200px;
+}
+/* product page styles */
+div.product_image{
+ float:left;
+ padding:0 10px 10px 0;
+}
View
BIN static/images/products/main/image1.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN static/images/products/thumbnails/image1.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
0 templates/.tmp_404.html.99937~
No changes.
View
13 templates/.tmp_base.html.84608~
@@ -0,0 +1,13 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "XHTML1-s.dtd" ><html
+xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <link rel="Stylesheet" type="text/css" href="/static/css.css" />
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <title>{% block title %}{% if page_title %}{{ page_title }} - {% endif %}
+ {{ site_name }}{% endblock %}</title>
+ <meta name="keywords" content="{{ meta_keywords }}" />
+ <meta name="description" content="{{ meta_description }}" />
+</head>
+<body>
+ {% block site_wrapper %}{% endblock %}
+</body></html>
View
39 templates/.tmp_catalog.html.14333~
@@ -0,0 +1,39 @@
+{% extends "base.html" %}
+{% block site_wrapper %}
+<div id="main">
+ <a href="#content" class="skip_link">Skip to main content</a>
+ <div id="banner">
+ <div class="bannerIEPadder">
+ <div class="cart_box">
+ [link to cart here]
+ </div>
+ Modern Musician
+ </div>
+ </div>
+ <div id="navigation">
+ <div class="navIEPadder">
+ {% include 'tags/navigation.html' %}
+ </div>
+ </div>
+ <div id="middle">
+ <div id="sidebar">
+ <div class="sidebarIEPadder">
+ [search box here]
+ <br />
+ [category listing here]
+ </div>
+ </div>
+ <div id="content">
+ <a name=”content”></a>
+ <div class="contentIEPadder">
+ {% block content %}{% endblock %}
+ </div>
+ </div>
+ </div>
+ <div id="footer">
+ <div class="footerIEPadder">
+ [footer here]
+ </div>
+ </div>
+</div>
+{% endblock %}
View
7 templates/404.html
@@ -0,0 +1,7 @@
+{% extends "catalog.html" %}
+
+{% block content %}
+ The page or resource you requested was not found.
+ We apologize for the inconvenience.
+ Please go back and check to make sure you typed in the URL correctly.
+{% endblock %}
View
2 templates/base.html
@@ -1,7 +1,7 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "XHTML1-s.dtd" ><html
xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
- <link rel="Stylesheet" type="text/css" href="/static/css.css" />
+ <link rel="Stylesheet" type="text/css" href="{{ MEDIA_URL }}css.css" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>{% block title %}{% if page_title %}{{ page_title }} - {% endif %}
{{ site_name }}{% endblock %}</title>
View
2 templates/catalog.html
@@ -20,7 +20,7 @@
<div class="sidebarIEPadder">
[search box here]
<br />
- [category listing here]
+ {% include "tags/category_list.html" %}
</div>
</div>
<div id="content">
View
0 templates/catalog/.tmp_category.html.95093~
No changes.
View
0 templates/catalog/.tmp_index.html.75481~
No changes.
View
0 templates/catalog/.tmp_product.html.9309~
No changes.
View
15 templates/catalog/category.html
@@ -0,0 +1,15 @@
+{% extends "catalog.html" %}
+{% block content %}
+ <h1>{{ c.name }}</h1>
+ {{ c.description }}
+ <br /><br />
+ {% for p in products %}
+ <div class="product_thumbnail">
+ <a href="{{ p.get_absolute_url }}">
+ <img src="{{ MEDIA_URL }}images/products/thumbnails/{{ p.image}}" alt="{{ p.name }}" class="bn" />
+ <br />
+ {{ p.name }}
+ </a>
+ </div>
+ {% endfor %}
+{% endblock %}
View
4 templates/catalog/index.html
@@ -0,0 +1,4 @@
+{% extends "catalog.html" %}
+{%block content %}
+<h1>Welcome to Modern Musician!</h1>
+{% endblock %}
View
30 templates/catalog/product.html
@@ -0,0 +1,30 @@
+{% extends "catalog.html" %}
+{% block content %}
+ <div class="product_image" >
+ <img src="{{ MEDIA_URL }}images/products/main/{{ p.image }}" alt="{{ p.name}}" />
+ </div>
+ <h1>{{ p.name }}</h1>
+ Brand: <em>{{ p.brand }}</em>
+ <br /><br />
+ SKU: {{ p.sku }}
+ <br />
+ In categor{{ categories.count|pluralize:"y,ies" }}:
+ {% for c in categories %}
+ <a href="{{ c.get_absolute_url }}">{{ c.name }}</a>
+ {% if not forloop.last %}, {% endif %}
+ {% endfor %}
+ <br /><br />
+ {% if p.sale_price %}
+ Was: <del>$ {{ p.old_price }}</del>
+ <br />
+ Now: $ {{ p.price }}
+ {% else %}
+ Price: $ {{ p.price }}
+ {% endif %}
+ <br /><br />
+ [add to cart button]
+ <br /><br />
+ <div class="cb"><br /><br /></div>
+ <h3>Product Description</h3>
+ {{ p.description }}
+{% endblock %}
View
0 templates/tags/.tmp_category_list.html.34792~
No changes.
View
4 templates/tags/category_list.html
@@ -0,0 +1,4 @@
+<h3>Categories</h3>
+{% for c in active_categories %}
+ <a href="{{ c.get_absolute_url }}">{{ c.name }}</a><br />
+{% endfor %}
View
22 urls.py
@@ -1,32 +1,24 @@
from django.conf.urls.defaults import *
from ecomstore import settings
-# Uncomment the next two lines to enable the admin:
-# from django.contrib import admin
-# admin.autodiscover()
+from django.contrib import admin
+admin.autodiscover()
import os
static = os.path.join(
os.path.dirname(__file__), 'static'
)
-
urlpatterns = patterns('',
(r'^catalog/?', 'preview.views.home'),
-
- # Example:
- # (r'^ecomstore/', include('ecomstore.foo.urls')),
-
- # Uncomment the admin/doc line below and add 'django.contrib.admindocs'
- # to INSTALLED_APPS to enable admin documentation:
- # (r'^admin/doc/', include('django.contrib.admindocs.urls')),
-
- # Uncomment the next line to enable the admin:
- # (r'^admin/', include(admin.site.urls)),
+ (r'^admin/', include(admin.site.urls)),
+ (r'^', include('catalog.urls')),
)
if settings.DEBUG:
- urlpatterns += patterns('',
+ urlpatterns += patterns('',
(r'^static/(?P<path>.*)$', 'django.views.static.serve',
{ 'document_root' : static }),
)
+
+handler404 = 'ecomstore.views.file_not_found_404'
View
0 utils/__init__.py
No changes.
View
11 utils/context_processors.py
@@ -0,0 +1,11 @@
+from ecomstore.catalog.models import Category
+from ecomstore import settings
+
+def ecomstore(request):
+ return {
+ 'active_categories': Category.objects.filter(is_active=True),
+ 'site_name': settings.SITE_NAME,
+ 'meta_keywords': settings.META_KEYWORDS,
+ 'meta_description': settings.META_DESCRIPTION,
+ 'request': request
+ }
View
3 utils/models.py
@@ -0,0 +1,3 @@
+from django.db import models
+
+# Create your models here.
View
23 utils/tests.py
@@ -0,0 +1,23 @@
+"""
+This file demonstrates two different styles of tests (one doctest and one
+unittest). These will both pass when you run "manage.py test".
+
+Replace these with more appropriate tests for your application.
+"""
+
+from django.test import TestCase
+
+class SimpleTest(TestCase):
+ def test_basic_addition(self):
+ """
+ Tests that 1 + 1 always equals 2.
+ """
+ self.failUnlessEqual(1 + 1, 2)
+
+__test__ = {"doctest": """
+Another way to test that 1 + 1 is equal to 2.
+
+>>> 1 + 1 == 2
+True
+"""}
+
View
1 utils/views.py
@@ -0,0 +1 @@
+# Create your views here.
View
7 views.py
@@ -0,0 +1,7 @@
+from django.shortcuts import render_to_response
+from django.template import RequestContext
+
+def file_not_found_404(request):
+ page_title = 'Page Not Found'
+ return render_to_response('404.html', locals(),
+ context_instance=RequestContext(request))

0 comments on commit 9c9efa9

Please sign in to comment.
Something went wrong with that request. Please try again.