{"id":19435782,"url":"https://github.com/tigeryant/sei-project-four-be","last_synced_at":"2026-05-18T01:02:27.317Z","repository":{"id":127747883,"uuid":"450446679","full_name":"tigeryant/sei-project-four-be","owner":"tigeryant","description":"CryptoAcademy back end - General Assembly software engineering project","archived":false,"fork":false,"pushed_at":"2022-02-21T16:34:55.000Z","size":65,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-02-25T06:45:08.558Z","etag":null,"topics":["back-end","django","sei"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tigeryant.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-01-21T10:24:34.000Z","updated_at":"2022-01-31T00:42:39.000Z","dependencies_parsed_at":null,"dependency_job_id":"384788d6-13f3-4f9f-9fd4-5ce71211c16c","html_url":"https://github.com/tigeryant/sei-project-four-be","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/tigeryant/sei-project-four-be","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tigeryant%2Fsei-project-four-be","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tigeryant%2Fsei-project-four-be/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tigeryant%2Fsei-project-four-be/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tigeryant%2Fsei-project-four-be/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tigeryant","download_url":"https://codeload.github.com/tigeryant/sei-project-four-be/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tigeryant%2Fsei-project-four-be/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263975332,"owners_count":23538305,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["back-end","django","sei"],"created_at":"2024-11-10T15:07:58.312Z","updated_at":"2026-05-18T01:02:20.241Z","avatar_url":"https://github.com/tigeryant.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"## Overview\nI completed this solo project as part of the General Assembly Software Engineering Immersive course. The course was split into four modules, and this was my submission for the final module. During module four, we learnt how to use Django - a back end framework for Python. Having already used Python for various different projects prior to the course, I was pleased to have the opportunity to apply my knowledge of Python in a different way. The finished project is to be deployed with Netlify and Heroku. This is the back end repository, the front end can be found [here](https://github.com/tigeryant/sei-project-four-fe).\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://i.imgur.com/eqBONp7.jpg\" height=\"450px\"\u003e\u003c/img\u003e\n  \u003cp\u003e\n\n## Brief\nWe were tasked with using the skills we had learnt throughout the twelve week course to build a full stack web application using React, Django, the Django REST framework and PostgreSQL. As we were given free reign over which CSS framework we used (if at all), I chose to use Bootstrap. We were also allowed to choose whether we worked in groups, pairs or solo. I decided to work solo, so that I could test my abilities in all areas - front and back end.\n  \n## Timeframe\nWhile there was no ‘hard’ deadline set for the final version, we were given one week to produce a minimum viable product (MVP).\n  \n## Technologies used\n* React.js\n* Django\n* Django REST framework\n* PostgreSQL\n* Bootstrap\n* JSON Web Tokens\n* Git\n* GitHub\n\n## Approach\nFor this project, I knew I wanted to find a way to blend my interest in cryptography with the skills I had learnt throughout the course. Cryptography is a somewhat esoteric and arcane field. Yet, in light of the emergence of cryptocurrencies in recent years, an understanding of this subject is becoming increasingly more important in society. This led me to the decision to build CryptoAcademy, a Coursera/Udacity/Udemy style web app that allows users to browse and enrol on courses related to mathematical cryptography.\n  \n## Planning\nI began my initial planning by taking some general notes with pen and paper. I did this to try and pin down exactly what functionality I wanted to include in the MVP, and what features I wanted to include as ‘stretch goals’. Ultimately I decided to give the app the following pages/features:\n* Landing page\n* Index page\n* Show page (with a hero banner, overview, skills, prerequisites, instructor, syllabus, reviews)\n* Full syllabus page\n* Navbar and footer on each page\n* User authentication\n  \n### Wireframes\nI then used Figma to produce the following wireframe diagrams:\n  \n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://i.imgur.com/xyjnyC5.png\" height=\"350px\"\u003e\u003c/img\u003e\n  \u003cimg src=\"https://i.imgur.com/zZQfL2F.png\" height=\"350px\"\u003e\u003c/img\u003e\n  \u003cimg src=\"https://i.imgur.com/GLvMx8p.png\" height=\"350px\"\u003e\u003c/img\u003e\n  \u003cimg src=\"https://i.imgur.com/8t6oLM3.png\" height=\"350px\"\u003e\u003c/img\u003e\n  \u003cimg src=\"https://i.imgur.com/yCfKiSt.png\" height=\"350px\"\u003e\u003c/img\u003e\n  \u003cp\u003e\n  \n### Entity Relationship Diagram\nDuring the planning phase, I also thought about the relationships between models in the database. This involved careful consideration of the difference between one-to-one, one-to-many and many-to-many relationships. Finally, I drew this Entity Relationship Diagram (ERD) to express the structure of the database:\n  \n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://i.imgur.com/zQUi0Sm.png\" height=\"400px\"\u003e\u003c/img\u003e\n  \u003cp\u003e\n  \n## Build\n### Back end\nI spent the first two days focusing purely on the back end. This involved building models and serializers, setting up routes and user authentication, and performing data entry. Here are two examples of models I built - the ‘Course’ and ‘Review’:\n\n```python\nclass Course(models.Model):\n   '''Course Model'''\n   name = models.CharField(max_length=100, unique=True)\n   image = models.CharField(max_length=300)\n   length = models.PositiveIntegerField()\n   overview = models.TextField(max_length=300)\n   prerequisites = models.ManyToManyField('self')\n   instructor_name = models.CharField(max_length=100)\n   instructor_image = models.CharField(max_length=300)\n   instructor_bio = models.TextField(max_length=300)\n\n   def __str__(self):\n       return f'{self.name}'\n\nclass Review(models.Model):\n   ''' Review Model '''\n   content = models.TextField(max_length=300)\n   rating = models.PositiveIntegerField()\n   course = models.ForeignKey(\n       Course,\n       related_name='reviews',\n       on_delete=models.CASCADE\n   )\n   owner = models.ForeignKey(\n       'jwt_auth.User',\n       related_name='reviews_posted',\n       on_delete=models.CASCADE\n   )\n\n   def __str__(self):\n       return f'Review {self.id} of Course {self.course}'\n```\n\nTheir respective serializers, for parsing data as it is stored in and retrieved from the database, were built like this:\n```python\nclass CourseSerializer(serializers.ModelSerializer):\n   ''' Serializer for outgoing course response '''\n   reviews = ReviewSerializer(many=True, read_only=True)\n   weekly_syllabuses = WeeklySyllabusSerializer(many=True, read_only=True)\n   skills = SkillSerializer(many=True, read_only=True)\n\n   class Meta:\n       model = Course\n       fields = '__all__'\n\nclass NestedUserSerializer(serializers.ModelSerializer):\n   ''' Serializer for users '''\n  \n   class Meta:\n       model = User\n       fields = ('id', 'username', 'email') \n\nclass ReviewSerializer(serializers.ModelSerializer):\n   ''' Serializer for reviews '''\n  \n   class Meta:\n       model = Review\n       fields = '__all__' \n\nclass NestedReviewSerializer(serializers.ModelSerializer):\n   ''' Serializer for nested reviews '''\n   owner = NestedUserSerializer()\n\n   class Meta:\n       model = Review\n       fields = '__all__'\n```\n  \nThe routes for interacting with the API were set up as follows:\n```python\nurlpatterns = [\n   path('', CourseListView.as_view()),\n   path('\u003cint:pk\u003e/', CourseDetailView.as_view()),\n   path('\u003cint:pk\u003e/reviews/', ReviewListView.as_view()),\n   path('\u003cint:course_pk\u003e/reviews/\u003cint:pk\u003e/', ReviewDetailView.as_view())\n]\n```\n\nPart of the user authentication process involved using JSON Web Tokens to verify the user. The snippet below shows how user authentication works on the back end:\n```python\nclass JWTAuthentication(BasicAuthentication):\n   def authenticate(self, request):\n       header = request.headers.get('Authorization')\n  \n       if not header:\n           return None\n  \n       if not header.startswith('Bearer'):\n           raise PermissionDenied({'detail':'Invalid Auth Header'})\n  \n       token = header.replace('Bearer ', '')\n       try:\n           payload = jwt.decode(token, settings.SECRET_KEY, algorithms=['HS256'])\n           user = User.objects.get(pk=payload.get('sub'))\n       except jwt.exceptions.InvalidTokenError:\n           raise PermissionDenied({'detail':'Invalid Token Error'})\n       except User.DoesNotExist:\n           raise PermissionDenied({'detail':'User Not Found'})\n\n       return (user, token)\n```\n  \n  \n### Front end\nAfter I had completed most of the work on the back end, I set about connecting the client and server side software. On the front end, I used the React framework. I set up each component so that it displayed some placeholder text. Once I was satisfied that each component was working correctly, I set up React hooks that made API calls from the index, show and syllabus page to retrieve information. Two of the hooks I used that are worthy of note were implemented in the show page (the CourseShow.js component). The following hook retrieves the data relating to the course being shown.\n  \n```javascript\n React.useEffect(() =\u003e {\n   const getData = async () =\u003e {\n     try {\n       const res = await getSingleCourse(courseId)\n       res.data.weeklySyllabuses.map((syllabus) =\u003e {\n         if (syllabus.week === 1) {\n           syllabus.isFirstWeek = true\n         } else {\n           syllabus.isFirstWeek = false\n         }\n       })\n       setCourse(res.data)\n     } catch {\n       console.error('error fetching course data')\n     }\n   }\n   getData()\n }, [courseId])\n\n```\n  \nEach course may have ‘prerequisite’ courses that are also displayed on the show page. For example, a student should learn about number theory and abstract algebra before they take the course on elliptic curves. The following hook fetches the course prerequisites, making use of promises to wait until all the data has been fetched before setting a state variable that contains this data.\n  \n```javascript\n // FETCH COURSE PREREQUISITES\n React.useEffect(() =\u003e {\n   if (course) {\n     const promises = course.prerequisites.map((id) =\u003e getSingleCourse(id))\n     Promise.all([...promises])\n       .then((values) =\u003e values.map((value) =\u003e value.data))\n       .then((data) =\u003e\n         data.map((course, index) =\u003e\n           index === 0\n             ? { ...course, isFirstSlide: true }\n             : { ...course, isFirstSlide: false }\n         )\n       )\n       .then((data) =\u003e setPrereqs(data))\n   }\n }, [course])\n```\n  \n### Styling\nThis project gave me a great opportunity to practise using the Bootstrap CSS framework to create a modern and responsive design. I learnt a great deal about Bootstrap utility and layout classes, including breakpoints, containers, icons and the grid system. I also tried out a lot of built in components, such as cards, accordions, list groups, breadcrumbs and heroes. Containers and the grid system in particular helped to develop a responsive application. The best example of extensive use of Bootstrap for styling is the show page. It features two navbars, a hero, a breadcrumb, a carousel, a list group and an accordion.\n  \n## Known bugs\nThis project is still a work in progress, so some features still need to be implemented or modified. While user authentication works on the back end, this functionality still needs to be implemented on the front end. This should not be too big a challenge as it will only involve building form components for login and registration, as well as making two API calls. \nA slightly more time consuming task (though not very difficult either) that needs to be done is data entry for each of the courses. This involves adding their name, image, description, syllabus information and more.\nA minor styling issue that needs to be addressed is the displaying of the images on the carousel. They need to be displayed with uniform sizing, but they are currently displayed in an irregular way.\n\n  \n## Challenges\nOne of the biggest challenges I faced during this project was building a useEffect hook to retrieve the prerequisites data on the show page. My initial approach was to set the ‘prerequisites’ state after each individual API call to retrieve the prerequisite data. This turned out to be very inefficient as the API was being called far more than necessary, and each state update was causing a re-render. After realising how inefficient this was, I used JavaScript promises to call the API once for each prerequisite, waiting for the data to be returned, and then assigning the data to the prerequisites state variable afterwards. This is the hook that calls the API and sets the state:\n  \n```javascript\n // FETCH COURSE PREREQUISITES\n React.useEffect(() =\u003e {\n   if (course) {\n     const promises = course.prerequisites.map((id) =\u003e getSingleCourse(id))\n     Promise.all([...promises])\n       .then((values) =\u003e values.map((value) =\u003e value.data))\n       .then((data) =\u003e\n         data.map((course, index) =\u003e\n           index === 0\n             ? { ...course, isFirstSlide: true }\n             : { ...course, isFirstSlide: false }\n         )\n       )\n       .then((data) =\u003e setPrereqs(data))\n   }\n }, [course])\n\n```\n  \nAnother challenge I faced was displaying the carousel on the show page. Initially, I tried to use a Bootstrap carousel component. This proved more difficult than expected, as it threw an error each time the carousel reached the end of its first display cycle. Following this, I used the react-slick package instead. Here is the implementation of the carousel using react-slick:\n  \n```javascript\nconst Prerequisites = ({ slides }) =\u003e {\n const settings = {\n   arrows: true,\n   dots: true,\n   infinite: true,\n   speed: 500,\n   slidesToShow: 1,\n   slidesToScroll: 1,\n }\n return (\n   \u003csection id=\"prerequisites\" className=\"pb-5\"\u003e\n     \u003ch2 style={{ display: \"inline\" }}\u003e\u003ci className=\"bi bi-file-earmark-check\"\u003e\u003c/i\u003ePrerequisites\u003c/h2\u003e\n     \u003cdiv\u003e\n       \u003cSlider {...settings}\u003e\n         {slides.map((slide) =\u003e (\n           \u003cdiv key={slide.id} className=\"slide-container\" \u003e\n             \u003cimg src={slide.image} alt=\"\" /\u003e\n           \u003c/div\u003e\n         ))}\n       \u003c/Slider\u003e\n     \u003c/div\u003e\n   \u003c/section\u003e\n )\n}\n```\n  \n## Wins\nOne of the biggest wins I got from this project was gaining the confidence to build a full stack app from scratch. I was confident that I understood how each part of the application worked, both on the front and back end, and at multiple levels of abstraction.\n  \n## Future Features\nFuture developments could include the following: an FAQs section, a further reading page and email notification system that sends an email to the user when they register for the first time and when they enrol on a course.\n  \n## Key Learnings\nThis was an interesting project which consolidated my knowledge in all the technologies I had learnt throughout the course, but most notably in Django and Bootstrap. It was very valuable to see the different trade offs that have to be made when selecting a back end framework.\nAnother notable example of something I learnt was promises. Before this project, I had only understood how promises worked in a hypothetical sense. It was extremely beneficial to be able to apply this knowledge in a practical way. \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftigeryant%2Fsei-project-four-be","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftigeryant%2Fsei-project-four-be","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftigeryant%2Fsei-project-four-be/lists"}