diff --git a/core/__pycache__/forms.cpython-311.pyc b/core/__pycache__/forms.cpython-311.pyc new file mode 100644 index 0000000..c967f7f Binary files /dev/null and b/core/__pycache__/forms.cpython-311.pyc differ diff --git a/core/__pycache__/models.cpython-311.pyc b/core/__pycache__/models.cpython-311.pyc index 18a063c..9529ab8 100644 Binary files a/core/__pycache__/models.cpython-311.pyc and b/core/__pycache__/models.cpython-311.pyc differ diff --git a/core/__pycache__/urls.cpython-311.pyc b/core/__pycache__/urls.cpython-311.pyc index ebb8c6e..9f3827a 100644 Binary files a/core/__pycache__/urls.cpython-311.pyc and b/core/__pycache__/urls.cpython-311.pyc differ diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc index 8d204fa..1e496a9 100644 Binary files a/core/__pycache__/views.cpython-311.pyc and b/core/__pycache__/views.cpython-311.pyc differ diff --git a/core/forms.py b/core/forms.py new file mode 100644 index 0000000..c10f469 --- /dev/null +++ b/core/forms.py @@ -0,0 +1,22 @@ +from django import forms +from .models import Startup, Message, Profile + +class StartupForm(forms.ModelForm): + class Meta: + model = Startup + fields = ['name', 'headline', 'description', 'target_amount', 'status'] + widgets = { + 'name': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Startup Name'}), + 'headline': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'A catchy one-liner'}), + 'description': forms.Textarea(attrs={'class': 'form-control', 'rows': 4, 'placeholder': 'What are you building?'}), + 'target_amount': forms.NumberInput(attrs={'class': 'form-control', 'placeholder': 'Target funding amount (£)'}), + 'status': forms.Select(attrs={'class': 'form-select'}), + } + +class MessageForm(forms.ModelForm): + class Meta: + model = Message + fields = ['content'] + widgets = { + 'content': forms.Textarea(attrs={'class': 'form-control', 'rows': 3, 'placeholder': 'Write your message...'}), + } diff --git a/core/management/commands/__pycache__/seed_data.cpython-311.pyc b/core/management/commands/__pycache__/seed_data.cpython-311.pyc new file mode 100644 index 0000000..83014ca Binary files /dev/null and b/core/management/commands/__pycache__/seed_data.cpython-311.pyc differ diff --git a/core/management/commands/seed_data.py b/core/management/commands/seed_data.py new file mode 100644 index 0000000..c68b3c7 --- /dev/null +++ b/core/management/commands/seed_data.py @@ -0,0 +1,58 @@ +from django.core.management.base import BaseCommand +from django.contrib.auth.models import User +from core.models import Profile, Tag, Startup, Investment + +class Command(BaseCommand): + help = 'Seed the database with initial mock data' + + def handle(self, *args, **kwargs): + self.stdout.write('Seeding initial data...') + + # Create Tags + tags = ['Fintech', 'Healthtech', 'Edtech', 'Sustainability', 'Consumer', 'Social Impact', 'AI', 'SaaS'] + tag_objs = [] + for tag in tags: + obj, created = Tag.objects.get_or_create(name=tag) + tag_objs.append(obj) + + # Create Founders + founders = [ + {'username': 'alex_founder', 'uni': 'Oxford', 'grad': 2025, 'bio': 'Building the future of finance for Gen Z.'}, + {'username': 'sarah_tech', 'uni': 'Imperial', 'grad': 2024, 'bio': 'Tech enthusiast and full-stack developer.'}, + {'username': 'michael_green', 'uni': 'UCL', 'grad': 2023, 'bio': 'Sustainability expert looking to change the world.'} + ] + + founder_profiles = [] + for f in founders: + user, created = User.objects.get_or_create(username=f['username'], email=f'{f["username"]}@uni.ac.uk') + if created: + user.set_password('password123') + user.save() + + profile = user.profile + profile.role = 'FOUNDER' + profile.university = f['uni'] + profile.graduation_year = f['grad'] + profile.bio = f['bio'] + profile.is_verified = True + profile.save() + founder_profiles.append(profile) + + # Create Startups + startups = [ + {'name': 'Stashify', 'headline': 'Micro-investing for students', 'amount': 5000, 'founder': founder_profiles[0]}, + {'name': 'HealthPulse', 'headline': 'AI-driven wellness tracker', 'amount': 10000, 'founder': founder_profiles[1]}, + {'name': 'EcoCart', 'headline': 'Track your carbon footprint while shopping', 'amount': 7500, 'founder': founder_profiles[2]} + ] + + for s in startups: + Startup.objects.get_or_create( + founder=s['founder'], + name=s['name'], + headline=s['headline'], + description="This is a detailed description of the startup " + s['name'] + ". We are building an MVP and looking for early-stage investors from the university community.", + target_amount=s['amount'], + status='FUNDING' + ) + + self.stdout.write(self.style.SUCCESS('Successfully seeded data!')) diff --git a/core/migrations/0001_initial.py b/core/migrations/0001_initial.py new file mode 100644 index 0000000..68093f4 --- /dev/null +++ b/core/migrations/0001_initial.py @@ -0,0 +1,85 @@ +# Generated by Django 5.2.7 on 2026-02-28 12:06 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Tag', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=50, unique=True)), + ], + ), + migrations.CreateModel( + name='Profile', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('role', models.CharField(choices=[('FOUNDER', 'Founder'), ('INVESTOR', 'Investor'), ('PENDING', 'Pending')], default='PENDING', max_length=10)), + ('university', models.CharField(blank=True, max_length=255)), + ('graduation_year', models.IntegerField(blank=True, null=True)), + ('bio', models.CharField(blank=True, max_length=150)), + ('investment_appetite', models.DecimalField(blank=True, decimal_places=2, max_digits=12, null=True)), + ('investment_frequency', models.CharField(blank=True, max_length=100)), + ('matching_answers', models.JSONField(blank=True, null=True)), + ('is_verified', models.BooleanField(default=False)), + ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='profile', to=settings.AUTH_USER_MODEL)), + ('interests', models.ManyToManyField(blank=True, to='core.tag')), + ], + ), + migrations.CreateModel( + name='Notification', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('content', models.TextField()), + ('timestamp', models.DateTimeField(auto_now_add=True)), + ('is_read', models.BooleanField(default=False)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='notifications', to='core.profile')), + ], + ), + migrations.CreateModel( + name='Message', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('content', models.TextField()), + ('timestamp', models.DateTimeField(auto_now_add=True)), + ('is_read', models.BooleanField(default=False)), + ('receiver', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='received_messages', to='core.profile')), + ('sender', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sent_messages', to='core.profile')), + ], + ), + migrations.CreateModel( + name='Startup', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255)), + ('headline', models.CharField(max_length=255)), + ('description', models.TextField()), + ('target_amount', models.DecimalField(decimal_places=2, max_digits=12)), + ('raised_amount', models.DecimalField(decimal_places=2, default=0, max_digits=12)), + ('status', models.CharField(choices=[('DRAFT', 'Draft'), ('FUNDING', 'Funding'), ('FUNDED', 'Funded')], default='DRAFT', max_length=10)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('founder', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='startups', to='core.profile')), + ], + ), + migrations.CreateModel( + name='Investment', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('amount', models.DecimalField(decimal_places=2, max_digits=12)), + ('timestamp', models.DateTimeField(auto_now_add=True)), + ('investor', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='investments', to='core.profile')), + ('startup', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='investments', to='core.startup')), + ], + ), + ] diff --git a/core/migrations/__pycache__/0001_initial.cpython-311.pyc b/core/migrations/__pycache__/0001_initial.cpython-311.pyc new file mode 100644 index 0000000..468ae30 Binary files /dev/null and b/core/migrations/__pycache__/0001_initial.cpython-311.pyc differ diff --git a/core/models.py b/core/models.py index 71a8362..65a65c7 100644 --- a/core/models.py +++ b/core/models.py @@ -1,3 +1,92 @@ from django.db import models +from django.contrib.auth.models import User +from django.db.models.signals import post_save +from django.dispatch import receiver -# Create your models here. +class Tag(models.Model): + name = models.CharField(max_length=50, unique=True) + + def __str__(self): + return self.name + +class Profile(models.Model): + ROLE_CHOICES = [ + ('FOUNDER', 'Founder'), + ('INVESTOR', 'Investor'), + ('PENDING', 'Pending'), + ] + + user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile') + role = models.CharField(max_length=10, choices=ROLE_CHOICES, default='PENDING') + university = models.CharField(max_length=255, blank=True) + graduation_year = models.IntegerField(null=True, blank=True) + bio = models.CharField(max_length=150, blank=True) + interests = models.ManyToManyField(Tag, blank=True) + + # Investor specific + investment_appetite = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True) + investment_frequency = models.CharField(max_length=100, blank=True) + + # Founder specific (for partner matching) + matching_answers = models.JSONField(null=True, blank=True) # To store questionnaire responses + + is_verified = models.BooleanField(default=False) + + def __str__(self): + return self.user.username + +@receiver(post_save, sender=User) +def create_user_profile(sender, instance, created, **kwargs): + if created: + Profile.objects.create(user=instance) + +@receiver(post_save, sender=User) +def save_user_profile(sender, instance, **kwargs): + instance.profile.save() + +class Startup(models.Model): + STATUS_CHOICES = [ + ('DRAFT', 'Draft'), + ('FUNDING', 'Funding'), + ('FUNDED', 'Funded'), + ] + + founder = models.ForeignKey(Profile, on_delete=models.CASCADE, related_name='startups') + name = models.CharField(max_length=255) + headline = models.CharField(max_length=255) + description = models.TextField() + target_amount = models.DecimalField(max_digits=12, decimal_places=2) + raised_amount = models.DecimalField(max_digits=12, decimal_places=2, default=0) + status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='DRAFT') + created_at = models.DateTimeField(auto_now_add=True) + + def __str__(self): + return self.name + +class Investment(models.Model): + investor = models.ForeignKey(Profile, on_delete=models.CASCADE, related_name='investments') + startup = models.ForeignKey(Startup, on_delete=models.CASCADE, related_name='investments') + amount = models.DecimalField(max_digits=12, decimal_places=2) + timestamp = models.DateTimeField(auto_now_add=True) + + def __str__(self): + return f"{self.investor.user.username} invested in {self.startup.name}" + +class Message(models.Model): + sender = models.ForeignKey(Profile, on_delete=models.CASCADE, related_name='sent_messages') + receiver = models.ForeignKey(Profile, on_delete=models.CASCADE, related_name='received_messages') + content = models.TextField() + timestamp = models.DateTimeField(auto_now_add=True) + is_read = models.BooleanField(default=False) + + def __str__(self): + return f"From {self.sender.user.username} to {self.receiver.user.username}" + +class Notification(models.Model): + user = models.ForeignKey(Profile, on_delete=models.CASCADE, related_name='notifications') + content = models.TextField() + timestamp = models.DateTimeField(auto_now_add=True) + is_read = models.BooleanField(default=False) + + def __str__(self): + return f"Notification for {self.user.user.username}" \ No newline at end of file diff --git a/core/templates/base.html b/core/templates/base.html index 1e7e5fb..5ced4ff 100644 --- a/core/templates/base.html +++ b/core/templates/base.html @@ -1,9 +1,9 @@ -
-