#Art by Cecilia
Our team of four navigated the challenge of integrating multiple Django apps—collections, events, owner management, and store functionality—while maintaining a cohesive user experience across visitor-facing galleries and administrative dashboards.
Successfully implementing a full-stack e-commerce platform featuring:
- Cloudinary image optimization
- Dynamic theming with 20+ Google Font combinations
- Sophisticated messaging system connecting visitors directly with the artist
Tracked on our Kanban board, we delivered:
- ✅ CRUD operations for artworks and exhibitions
- ✅ Integrated Stripe payments for testing
- ✅ Production-ready Heroku deployment with PostgreSQL
- ✅ Responsive design and accessibility standards across all devices
Art that remembers. Const Collection by Cecilia K. is a quiet revolution—paintings that reclaim the feminine, resist distortion, and invite you to collect what feels true.
This platform is designed to honor the artist's voice, showcase their evolving body of work, and invite visitors into a space of emotional resonance and thoughtful exploration. It blends storytelling, visual clarity, and intuitive navigation to serve artists, visitors, and buyers alike.
Artwork: Art by Cecilia K. — constcollection.com
Deployed Link: Art by Cecilia
- Features
- Technologies Used
- E-Commerce & Payment System
- User Stories & Planning
- Database Design
- Testing
- Deployment
- AI Integration
- Credits and Acknowledgements
- Features Left to Implement
- Home Page responsive design Here
- Store - with possibility to search and sort Here and Here
- User Authentication - Register, login, logout functionality Here
- Picture Management - Create, read, update, and delete media, Art, Collections, About page or Exibitions for the Owner (CRUD) Here
- The About Page is

- Payment enable for testing for Admin Here
- Sophisticated messaging system — A three-tier communication platform enabling direct visitor-to-artist contact through public contact forms, real-time unread message tracking with badge notifications, and threaded conversation history where owners can reply directly through the platform with automatic email delivery to anonymous visitors
- Responsive Design - Works perfectly on all devices Here
- Modern UI - Clean, accessible interface with Bootstrap 5
- Image Upload - Cloudinary integration for images
- Admin Interface - Full Django admin for content management Here
Minimalist Palette Philosophy This grayscale palette—ranging from pure white to absolute black—embodies the principles of minimalism: clarity, restraint, and emotional space. It serves as a neutral canvas that allows the artwork to speak without distraction, letting color-rich pieces radiate with full intensity. Rainbowcolored hover Effects: Subtle hover effects on some buttons enhance user interaction, providing visual feedback when the button is hovered over, which encourages clicks.
| Name | Hex Code | Usage |
|---|---|---|
| Pure White | #FFFFFF | Background, whitespace, clean canvas |
| Light Gray | #F5F5F5 | Section dividers, subtle hover effects |
| Cool Gray | #D3D3D3 | Card backgrounds, secondary text |
| Medium Gray | #A9A9A9 | Borders, muted buttons |
| Charcoal Gray | #555555 | Body text, icons |
| Graphite | #333333 | Headings, navigation bar |
| Absolute Black | #000000 | Accent text, high-contrast elements |
The site uses Google Fonts. The project has a sophisticated multi-theme system where each theme (Scheme 1-20+) can use different font combinations. Here's how it works:
All Available Google Fonts (loaded in base.html line 32):
- Font Variables in Each Scheme (from CSS files): Scheme 1 (Dark theme):
Headings: Playfair Display (serif) Body: Montserrat (sans-serif) Scheme 2 (Light museum theme):
Headings: Playfair Display (serif) Body: Montserrat (sans-serif) Scheme 3 (Taupe theme):
Headings: Playfair Display (serif) Body: Montserrat (sans-serif) 3. How the Switch Happens (from schemes.css):
/* CSS Variables control fonts */
:root {
--font-heading: "Playfair Display", serif;
--font-body: "Montserrat", sans-serif;
}
/* Applied globally */
body {
font-family: var(--font-body, system-ui, ...);
}
h1, h2, h3, h4, h5, h6 {
font-family: var(--font-heading, inherit);
}When a user selects a different theme (Scheme 1, 2, 3, etc.), the corresponding Scheme-X.css file is loaded, which redefines --font-heading and --font-body, instantly changing all fonts across the site!
- Where Users Change Themes: The theme selector appears in the user dashboard with a radial selector showing theme dots that users can click to switch between schemes.
- Source: Art by Cecilia K.
- Hosting: Cloudinary for optimized loading
- Optimization: Responsive images with proper aspect ratios
- Python 3.12 - Core language
- Django 4.2 - Web framework
- PostgreSQL - Database
- Django Allauth - Authentication
- HTML5 & CSS3 - Markup & styling
- JavaScript - Interactivity
- Bootstrap 5 - UI framework
- Font Awesome - Icons
- Heroku - Hosting
- Cloudinary - Image optimization
- WhiteNoise - Static files
- GitHub & GitHub Copilot - Version control & AI assistance
- VS Code - Code editor
- Chrome DevTools - Debugging
Integrated Payment System
A complete e-commerce checkout flow featuring:
- Shopping basket functionality with real-time item management, quantity updates, and persistent storage across sessions
- Admin test checkout enabling order creation with billing information capture (email, address, contact details)
- Stripe integration prepared with API configuration and payment processing architecture ready for production deployment
- Order management system that creates permanent order records with snapshot pricing, variant tracking, and automatic basket clearing upon successful checkout
Currently operational for admin testing with full Stripe payment processing infrastructure in place for future activation.
The project was developed using Agile methodology (see Board in process) with iterative progress and continuous feedback. User stories were tracked using a Kanban board to ensure systematic development, using categorized tasks into Must have, Should have, Could have, and Won’t have to clarify what’s essential, desirable, optional, or excluded for a project’s success. Here are some of the User Stories.
As a visitor, I want to explore themed collections so I can engage with the artist’s evolving body of work.
Acceptance Criteria:
- Collections are displayed with titles, cover images, and brief descriptions.
- Clicking a collection opens a page with its artworks and artist statement.
Tasks:
- Design collection model in Django (title, description, cover image).
- Create gallery view for collections.
- Link each collection to its artworks and statement.
- As a visitor, I want to click on an artwork to see its full image, title, date, and description so I can appreciate it fully.
Acceptance Criteria:
- Artwork thumbnails link to detail pages.
- Detail page includes full image, title, date, medium, dimensions, and description.
Tasks:
- Create artwork detail template.
- Add fields to artwork model.
- Implement routing from gallery to detail view.
- As a visitor, I want to filter artworks by medium (e.g., acrylic, mixed media) or style so I can find pieces that match my interests.
Acceptance Criteria:
- Filter options are visible and functional.
- Selecting a filter updates the gallery view dynamically.
Tasks:
- Add medium/style fields to artwork model.
- Implement filter logic in views.
- Style filter UI with dropdowns or checkboxes.
- As a visitor, I want to read the artist’s reflections for each collection so I understand the emotional and philosophical context.
Acceptance Criteria:
- Each collection includes a visible artist statement.
- Statement is readable and styled for clarity.
Tasks:
- Add statement field to collection model.
- Display statement on collection page.
- Style typography for emotional impact.
- As an artist, I want to group my work into series or themes so my portfolio feels cohesive and intentional.
Acceptance Criteria:
- Artist can assign artworks to a series.
- Series are displayed as part of the collection or separately.
Tasks:
- Create series model and link to artworks.
- Add series management to admin panel.
- Display series grouping in gallery view.
The Entity Relationship Diagram visually represents the structure of the database and the relationships between entities.
- Click to view relationships between entities diagram Entities
- Contact
Stores the gallery’s/owner’s public contact info (address lines, city, zip, phone, email, curator details, opening hours). Useful for rendering the Contact page/footer and for admin updates. Admin can manage a single or multiple contact records.
- Messages
Captures incoming messages from visitors: name, email, optional phone, message body, subject (general/artwork/exhibition), timestamp. Links to: sender: optional authenticated user who submitted it. owner: the site owner/admin user who should receive/handle it. Tracks unread state to show counts in the UI and inbox. Enables listing, filtering, marking as read, and replying workflows.
- MessageReply
Stores replies to a given message with body, timestamp, and who replied (sender is a user). via_email indicates if the reply was sent out via email (for anonymous visitors) or kept internal (for registered users). Enables threaded conversation history per message.
- Display and update official contact information in admin.
- Public contact form submissions create Messages.
- Owner dashboard can: See unread counts, list messages, filter by subject. Open a message, mark as read/unread. Post replies; optionally send via email to non-logged-in senders. View full reply thread per message.
class ArtistProfile(models.Model):
# Unique ID (auto PK by Django)
name = models.CharField(max_length=200)
email = models.EmailField(unique=True)
phone_number = models.CharField(max_length=30, blank=True)
bio = models.TextField(blank=True)
image = CloudinaryField(resource_type='image', blank=True, null=True)
def __str__(self):
return f"{self.name} <{self.email}>"
class Contact(models.Model):
address_line_1 = models.CharField(max_length=200)
address_line_2 = models.CharField(max_length=200)
city = models.CharField(max_length=200)
zip_code = models.CharField(max_length=20)
phone = models.CharField(max_length=30)
email = models.EmailField()
curator_name = models.CharField(max_length=200, blank=True)
curator_email = models.EmailField(blank=True)
opening_hours = models.CharField(max_length=255, blank=True)
def __str__(self):
return f"{self.city} <{self.email}>"
| Test Case | Expected Result | Actual Result | Status |
|---|---|---|---|
| Click Home menu | Navigate to homepage | ✅ Success | PASS |
| Click Register | Open registration form | ✅ Success | PASS |
| Click Login | Open login form | ✅ Success | PASS |
| Click Logout | User logged out successfully | ✅ Success | PASS |
| Put item in a basket | Item is in a basket | ✅ Success | PASS |
| Register new account | Account created successfully | ✅ Success | PASS |
| Access admin interface | Admin panel accessible | ✅ Success | PASS |
| Responsivity | Works on all devices | ✅ Success | PASS |
Test Coverage:
- ✅ Home page loads successfully
- ✅ About and Shop page loads successfully
- ✅ User authentication flows
- ✅ CRUD operations for Artworks
- Tool: W3C Markup Validation Service
- Result: Minor template-related warnings (Django syntax)
- Tool: W3C CSS Validation Service
- Result: ✅ No errors found - CSS Validation
- Tool: CI Python Linter
- Result: ✅ PEP8 compliant, no errors found
Performance Metrics:
Performance Metrics:
The site is deployed to Heroku with continuous deployment from the main branch.
-
Create Heroku App
- Create new "const-collection" app on Heroku dashboard
- Note the app name for later configuration
-
Configure Environment Variables
- Navigate to app Settings → "Reveal Config Vars"
- Add all required environment variables:
DATABASE_URL- PostgreSQL connection stringSECRET_KEY- Django secret keyCLOUDINARY_URL- Cloudinary API configuration
-
Prepare Project Files
- Create a
Procfilewith:web: gunicorn project_name.wsgi - Ensure
Debug = Falseinsettings.py - Add
'localhost'and'project_name.herokuapp.com'toALLOWED_HOSTS - Update
requirements.txtwith all dependencies
- Create a
-
Database Setup
- Service: PostgreSQL from Code Institute
- Copy DATABASE_URL from dashboard
- Add DATABASE_URL to both Heroku Config Vars and local
env.py - Run migrations:
python3 manage.py makemigrations python3 manage.py migrate
-
Deploy Application
- Connect GitHub repository to Heroku
- Enable automatic deploys from main branch
- Perform initial manual deploy
- Verify deployment success
Live Application: Art of Cecilia
GitHub Copilot helped shape user stories, generate Django scaffolding, and streamline frontend design. It also supported error fixes, performance tuning, and deployment.
- Const Collection Art by Cecilia K. - project provided main inspiration
- Django Documentation - Comprehensive framework guidance
- Bootstrap Documentation - UI component implementation
- GitHub Copilot - AI-assisted development
- Favicon.io - Favicon generation
- Shields.io - README badges
- MermaidChart - Database diagram creation
- Cloudinary - Image hosting and optimization
Note: All images are property of Cecilia K. and https://constcollection.com/ website.
- Implement user story: As a visitor, I want to access press articles and academic credentials so I can learn more about the artist’s professional identity.
- Implement user story: A user dashboard displays account info and saved (featured) items.
- Improve performance metrics.
Project Specifications
- Responsive Design: Mobile-first approach with Bootstrap 5
- Accessibility: WCAG compliant with semantic HTML
- Continuous Deployment: Heroku integration with GitHub
- Environment Management: Secure configuration variables
- Static File Handling: WhiteNoise for production efficiency
- Database: PostgreSQL with Heroku hosting