Skip to content

Commit 44f27dc

Browse files
authored
Merge pull request #10 from githubuniverseworkshops/arilivigni/self-service-prompting
Refactor README and backend setup instructions
2 parents f3cce6e + fa5ff48 commit 44f27dc

File tree

5 files changed

+154
-53
lines changed

5 files changed

+154
-53
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,5 @@ Without further ado, let's get started.
2828
1. [Story](docs/1_Story)
2929
2. [Prerequisites and development environment setup](docs/2_Prerequisites)
3030
3. [Getting started - app frontend and backend creation](docs/3_GettingStarted)
31-
4. [MongoDB install and setup](docs/4_MongoDBInstallSetup/)
31+
4. [OctoFit Tracker database and app backend setup](docs/4_BackendSettings)
32+
5. [Populate the database with sample data](docs/5_PopulateDBwData)

docs/1_Story/README.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,18 @@ OctoFit Tracker will include:
3030
GitHub Copilot and Copilot Chat uses OpenAI GPT models for its coding suggestions and chat interaction.
3131
OpenAI gpt-4o: *"Our high-intelligence flagship model for complex, multi-step tasks. GPT-4o is cheaper and faster than GPT-4 Turbo. Currently points to gpt-4o-2024-08-06"*
3232

33-
[OpenAI GPT models explained](https://platform.openai.com/docs/models)
33+
#### [OpenAI GPT models explained](https://platform.openai.com/docs/models)
3434

3535
![openai gpt models](./gpt-models.png)
3636

37+
#### Prompt engineering
38+
39+
- [GitHub documentation prompt engineering](https://docs.github.com/en/copilot/using-github-copilot/prompt-engineering-for-github-copilot)
40+
- [How to use GitHub Copilot: Prompts, tips, and use cases](https://github.blog/2023-06-20-how-to-write-better-prompts-for-github-copilot/)
41+
- [Using GitHub Copilot in your IDE: Tips, tricks, and best practices](https://github.blog/2024-03-25-how-to-use-github-copilot-in-your-ide-tips-tricks-and-best-practices/)
42+
- [A developer’s guide to prompt engineering and LLMs](https://docs.github.com/en/copilot/using-github-copilot/prompt-engineering-for-github-copilot#:~:text=A%20developer%E2%80%99s%20guide%20to%20prompt%20engineering%20and%20LLMs)
43+
- [Prompting GitHub Copilot Chat to become your personal AI assistant for accessibility]https://github.blog/2023-10-09-prompting-github-copilot-chat-to-become-your-personal-ai-assistant-for-accessibility/()
44+
3745
OpenAI gpt-4o: *"Our high-intelligence flagship model for complex, multi-step tasks. GPT-4o is cheaper and faster than GPT-4 Turbo. Currently points to gpt-4o-2024-08-06"*
3846

3947
> NOTE: we will be using gpt-4o in GitHub Copilot Chat for this workshop at GitHub Universe.

docs/3_GettingStarted/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ generate instructions in this order
2626
2727
1. Create the frontend and backend in the octofit-tracker directory of this repository in one command
2828
2. Setup backend python venv and install octofit-tracker/requirements.txt first
29-
3. The octofit-tracker/backend directory will store the django project with the name octofit-tracker
29+
3. The octofit-tracker/backend directory will store the django project and app with the name octofit-tracker
3030
4. The Django project octofit-tracker directory will have all the backend components for the app
3131
5. Create the django app directly in the directory octofit_tracker/backend
3232
6. Setup the octofit-tracker/frontend directory will store the react app with no subdirectories
@@ -75,4 +75,4 @@ Important to avoid using public code and we do NOT need to initialize the git re
7575

7676
![octofit-tracker app directory tree](./3_3_OctoFitTrackerDirTree.png)</br>
7777

78-
[Back :: Previous: Prerequisites and development environment setup](../2_Prerequisites) | [Next :: OctoFit app backend setup](../4_BackendSettings/)
78+
[Back :: Previous: Prerequisites and development environment setup](../2_Prerequisites) | [Next :: OctoFit Tracker database and app backend setup](../4_BackendSettings/)

docs/4_BackendSettings/README.md

Lines changed: 46 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
1-
# Setup database in settings.py, models, views, serializers, and populate data
1+
# OctoFit Tracker database and app backend setup
22

3-
## Use Copilot Chat
3+
## Initialize the database, setup database and install apps in settings.py, models, serializers, urls, and views
44

55
Type the following prompt in GitHub Copilot Chat:
66

77
```text
88
In our next steps lets think step by step and setup the following in this order
99
10-
1. Initialize the mongo octofit_db database
11-
2. settings.py in our django project for mongodb octofit_db database including localhost and the port
12-
3. settings.py in our django project setup for all installed apps. ex djongo, octofit_tracker, rest_framework
13-
4. In octofit_tracker project setup and touch models, serializers, urls, and views for users, teams, activity, leaderboard, and workouts
10+
1. Initialize the mongo octofit_db database and create a correct table structure for users, teams, activities, leaderboards, and workouts collections
11+
2. Make sure there is a unique id for primary key for the user collection
12+
ex. db.users.createIndex({ "email": 1 }, { unique: true })
13+
3. settings.py in our django project for mongodb octofit_db database including localhost and the port
14+
4. settings.py in our django project setup for all installed apps. ex djongo, octofit_tracker, rest_framework
15+
5. In octofit_tracker project setup and use command touch models.py, serializers.py, urls.py, and views.py for users, teams, activities, leaderboards, and workouts
16+
6. make sure urls.py has a root, admin, and api endpoints
1417
```
1518

1619
![OctoFit Tracker backend files](./4_1_OctoFitTrackerBackendFiles.png)</br>
@@ -56,41 +59,34 @@ INSTALLED_APPS = [
5659
```python
5760
# FILE: octofit-tracker/backend/octofit_tracker/models.py
5861

59-
from django.db import models
60-
from django.contrib.auth.models import AbstractUser
62+
from djongo import models
6163

62-
class User(AbstractUser):
64+
class User(models.Model):
65+
_id = models.ObjectIdField()
66+
username = models.CharField(max_length=100)
6367
email = models.EmailField(unique=True)
64-
groups = models.ManyToManyField(
65-
'auth.Group',
66-
related_name='octofit_tracker_user_set',
67-
blank=True,
68-
help_text='The groups this user belongs to.',
69-
verbose_name='groups',
70-
)
71-
user_permissions = models.ManyToManyField(
72-
'auth.Permission',
73-
related_name='octofit_tracker_user_set',
74-
blank=True,
75-
help_text='Specific permissions for this user.',
76-
verbose_name='user permissions',
77-
)
68+
password = models.CharField(max_length=100)
7869

7970
class Team(models.Model):
71+
_id = models.ObjectIdField()
8072
name = models.CharField(max_length=100)
73+
members = models.ArrayReferenceField(to=User, on_delete=models.CASCADE)
8174

8275
class Activity(models.Model):
76+
_id = models.ObjectIdField()
77+
user = models.ForeignKey(User, on_delete=models.CASCADE)
8378
activity_type = models.CharField(max_length=100)
84-
85-
class Workout(models.Model):
86-
name = models.CharField(max_length=100)
8779
duration = models.DurationField()
88-
activity = models.ForeignKey(Activity, on_delete=models.CASCADE)
89-
user = models.ForeignKey(User, on_delete=models.CASCADE)
9080

9181
class Leaderboard(models.Model):
82+
_id = models.ObjectIdField()
9283
user = models.ForeignKey(User, on_delete=models.CASCADE)
9384
score = models.IntegerField()
85+
86+
class Workout(models.Model):
87+
_id = models.ObjectIdField()
88+
name = models.CharField(max_length=100)
89+
description = models.TextField()
9490
```
9591

9692
#### serializers.py
@@ -99,7 +95,7 @@ class Leaderboard(models.Model):
9995
# FILE: octofit-tracker/backend/octofit_tracker/serializers.py
10096

10197
from rest_framework import serializers
102-
from .models import User, Team, Activity, Workout, Leaderboard
98+
from .models import User, Team, Activity, Leaderboard, Workout
10399

104100
class UserSerializer(serializers.ModelSerializer):
105101
class Meta:
@@ -116,14 +112,14 @@ class ActivitySerializer(serializers.ModelSerializer):
116112
model = Activity
117113
fields = '__all__'
118114

119-
class WorkoutSerializer(serializers.ModelSerializer):
115+
class LeaderboardSerializer(serializers.ModelSerializer):
120116
class Meta:
121-
model = Workout
117+
model = Leaderboard
122118
fields = '__all__'
123119

124-
class LeaderboardSerializer(serializers.ModelSerializer):
120+
class WorkoutSerializer(serializers.ModelSerializer):
125121
class Meta:
126-
model = Leaderboard
122+
model = Workout
127123
fields = '__all__'
128124
```
129125

@@ -132,9 +128,9 @@ class LeaderboardSerializer(serializers.ModelSerializer):
132128
```python
133129
# FILE: octofit_tracker/views.py
134130

135-
from rest_framework import viewsets
136-
from .models import User, Team, Activity, Leaderboard, Workout
137131
from .serializers import UserSerializer, TeamSerializer, ActivitySerializer, LeaderboardSerializer, WorkoutSerializer
132+
from rest_framework.response import Response
133+
from rest_framework.decorators import api_view
138134

139135
class UserViewSet(viewsets.ModelViewSet):
140136
queryset = User.objects.all()
@@ -155,6 +151,17 @@ class LeaderboardViewSet(viewsets.ModelViewSet):
155151
class WorkoutViewSet(viewsets.ModelViewSet):
156152
queryset = Workout.objects.all()
157153
serializer_class = WorkoutSerializer
154+
155+
@api_view(['GET'])
156+
def api_root(request, format=None):
157+
base_url = 'http://upgraded-space-happiness-959pr7vpgw3p7vv-8000.app.github.dev/'
158+
return Response({
159+
'users': base_url + 'api/users/?format=api',
160+
'teams': base_url + 'api/teams/?format=api',
161+
'activities': base_url + 'api/activities/?format=api',
162+
'leaderboards': base_url + 'api/leaderboards/?format=api',
163+
'workouts': base_url + 'api/workouts/?format=api'
164+
})
158165
```
159166

160167
#### urls.py
@@ -165,7 +172,7 @@ class WorkoutViewSet(viewsets.ModelViewSet):
165172
from django.contrib import admin
166173
from django.urls import path, include
167174
from rest_framework.routers import DefaultRouter
168-
from .views import UserViewSet, TeamViewSet, ActivityViewSet, LeaderboardViewSet, WorkoutViewSet
175+
from .views import UserViewSet, TeamViewSet, ActivityViewSet, LeaderboardViewSet, WorkoutViewSet, api_root
169176

170177
router = DefaultRouter()
171178
router.register(r'users', UserViewSet)
@@ -175,8 +182,9 @@ router.register(r'leaderboards', LeaderboardViewSet)
175182
router.register(r'workouts', WorkoutViewSet)
176183

177184
urlpatterns = [
178-
path('admin/', admin.site.urls),
179-
path('api/', include(router.urls)),
185+
path('', api_root, name='api-root'), # Root endpoint
186+
path('admin/', admin.site.urls), # Admin endpoint
187+
path('api/', include(router.urls)), # API endpoint
180188
]
181189
```
182190

docs/5_PopulateDBwData/README.md

Lines changed: 95 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
> NOTE: This is an example of not being specific skip this prompt and go to the next one
66
77
```text
8-
Let's use manage.py to get everything setup we need to create init.py for populate_db command include steps to migrate as well
8+
Let's use manage.py to get everything setup we need to populate_db command include steps to migrate as well
99
```
1010

1111
### Example of not being specfic in prompting Copilot Chat
@@ -19,10 +19,11 @@ Let's use manage.py to get everything setup we need to create init.py for popula
1919
Type the following prompt in GitHub Copilot Chat:
2020

2121
```text
22-
Let's use manage.py to get the database setup and populated
22+
Let's use manage.py to get the database setup and populated based on fields in models.py
2323
24-
- Populate the database with super hero users
25-
- Create full setup for a command populate_db.py
24+
- Create populate_db.py so it initializes and deletes previous data and recreates it
25+
- populate_db.py creates users, teams, activities, leaderboards, and workouts
26+
- users will be super hero users
2627
- Include steps to migrate in the octofit_tracker project
2728
```
2829

@@ -33,29 +34,112 @@ Let's use manage.py to get the database setup and populated
3334
```python
3435
# FILE: octofit-tracker/backend/octofit_tracker/management/commands/populate_db.py
3536

37+
# octofit_tracker/management/commands/populate_db.py
38+
3639
from django.core.management.base import BaseCommand
37-
from octofit_tracker.models import User, Team, Activity, Workout, Leaderboard
40+
from octofit_tracker.models import User, Team, Activity, Leaderboard, Workout
41+
from django.conf import settings
42+
from pymongo import MongoClient
3843
from datetime import timedelta
3944

4045
class Command(BaseCommand):
41-
help = 'Populate the database with initial data'
46+
help = 'Populate the database with superhero users, teams, activities, leaderboards, and workouts'
4247

4348
def handle(self, *args, **kwargs):
44-
# Create Superhero Users
49+
# Connect to MongoDB
50+
client = MongoClient(settings.DATABASES['default']['HOST'], settings.DATABASES['default']['PORT'])
51+
db = client[settings.DATABASES['default']['NAME']]
52+
53+
# Drop existing collections
54+
db.users.drop()
55+
db.teams.drop()
56+
db.activities.drop()
57+
db.leaderboards.drop()
58+
db.workouts.drop()
59+
60+
# Populate users
4561
users = [
4662
{'username': 'superman', 'email': '[email protected]', 'password': 'superpassword'},
4763
{'username': 'batman', 'email': '[email protected]', 'password': 'batpassword'},
4864
{'username': 'wonderwoman', 'email': '[email protected]', 'password': 'wonderpassword'},
65+
{'username': 'flash', 'email': '[email protected]', 'password': 'flashpassword'},
66+
{'username': 'aquaman', 'email': '[email protected]', 'password': 'aquapassword'},
4967
]
5068

69+
user_objects = []
5170
for user_data in users:
52-
user, created = User.objects.get_or_create(**user_data)
71+
user, created = User.objects.get_or_create(email=user_data['email'], defaults=user_data)
72+
user_objects.append(user)
5373
if created:
54-
self.stdout.write(self.style.SUCCESS(f"User {user.username} created"))
74+
self.stdout.write(self.style.SUCCESS(f'Successfully created user {user.username}'))
75+
else:
76+
self.stdout.write(self.style.WARNING(f'User {user.username} already exists'))
77+
78+
# Ensure all user objects are saved
79+
for user in user_objects:
80+
user.save()
5581

56-
# Add more data population logic here if needed
82+
# Populate teams
83+
teams = [
84+
{'name': 'Justice League', 'members': [user_objects[0], user_objects[1], user_objects[2], user_objects[3], user_objects[4]]},
85+
]
5786

58-
self.stdout.write(self.style.SUCCESS('Database populated successfully'))
87+
for team_data in teams:
88+
team, created = Team.objects.get_or_create(name=team_data['name'])
89+
if created:
90+
for member in team_data['members']:
91+
team.members.add(member)
92+
self.stdout.write(self.style.SUCCESS(f'Successfully created team {team.name}'))
93+
else:
94+
self.stdout.write(self.style.WARNING(f'Team {team.name} already exists'))
95+
96+
# Populate activities
97+
activities = [
98+
{'user': user_objects[0], 'activity_type': 'Flying', 'duration': timedelta(hours=1)},
99+
{'user': user_objects[1], 'activity_type': 'Martial Arts', 'duration': timedelta(hours=2)},
100+
{'user': user_objects[2], 'activity_type': 'Training', 'duration': timedelta(hours=1, minutes=30)},
101+
{'user': user_objects[3], 'activity_type': 'Running', 'duration': timedelta(minutes=30)},
102+
{'user': user_objects[4], 'activity_type': 'Swimming', 'duration': timedelta(hours=1, minutes=15)},
103+
]
104+
105+
for activity_data in activities:
106+
activity, created = Activity.objects.get_or_create(**activity_data)
107+
if created:
108+
self.stdout.write(self.style.SUCCESS(f'Successfully created activity for {activity.user.username}'))
109+
else:
110+
self.stdout.write(self.style.WARNING(f'Activity for {activity.user.username} already exists'))
111+
112+
# Populate leaderboards
113+
leaderboards = [
114+
{'user': user_objects[0], 'score': 100},
115+
{'user': user_objects[1], 'score': 90},
116+
{'user': user_objects[2], 'score': 95},
117+
{'user': user_objects[3], 'score': 85},
118+
{'user': user_objects[4], 'score': 80},
119+
]
120+
121+
for leaderboard_data in leaderboards:
122+
leaderboard, created = Leaderboard.objects.get_or_create(**leaderboard_data)
123+
if created:
124+
self.stdout.write(self.style.SUCCESS(f'Successfully created leaderboard entry for {leaderboard.user.username}'))
125+
else:
126+
self.stdout.write(self.style.WARNING(f'Leaderboard entry for {leaderboard.user.username} already exists'))
127+
128+
# Populate workouts
129+
workouts = [
130+
{'name': 'Super Strength Training', 'description': 'Training for super strength'},
131+
{'name': 'Martial Arts Training', 'description': 'Training for martial arts'},
132+
{'name': 'Amazonian Training', 'description': 'Training for Amazonian warriors'},
133+
{'name': 'Speed Training', 'description': 'Training for super speed'},
134+
{'name': 'Aquatic Training', 'description': 'Training for underwater activities'},
135+
]
136+
137+
for workout_data in workouts:
138+
workout, created = Workout.objects.get_or_create(**workout_data)
139+
if created:
140+
self.stdout.write(self.style.SUCCESS(f'Successfully created workout {workout.name}'))
141+
else:
142+
self.stdout.write(self.style.WARNING(f'Workout {workout.name} already exists'))
59143
```
60144

61145
![Migrate and populate db](./5_3_MigratePopulateDb.png)

0 commit comments

Comments
 (0)