Skip to content

Reworked to improve flexibility #5

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*__pycache__*
.env
Binary file modified db.sqlite3
Binary file not shown.
8 changes: 6 additions & 2 deletions home/admin.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from django.contrib import admin
from django import forms
from home.models import Blog
from home.models import Blog, Project, Skill, About, Category

# Register your models here.
class BlogAdminForm(forms.ModelForm):
Expand All @@ -13,4 +13,8 @@ class Meta:
class BlogAdmin(admin.ModelAdmin):
form = BlogAdminForm

admin.site.register(Blog, BlogAdmin)
admin.site.register(Blog, BlogAdmin)
admin.site.register(Project)
admin.site.register(Skill)
admin.site.register(About)
admin.site.register(Category)
26 changes: 0 additions & 26 deletions home/migrations/0001_initial.py

This file was deleted.

18 changes: 0 additions & 18 deletions home/migrations/0002_blog_category.py

This file was deleted.

19 changes: 0 additions & 19 deletions home/migrations/0003_blog_remark.py

This file was deleted.

17 changes: 0 additions & 17 deletions home/migrations/0004_remove_blog_remark.py

This file was deleted.

18 changes: 0 additions & 18 deletions home/migrations/0005_blog_thumbnail_url.py

This file was deleted.

83 changes: 80 additions & 3 deletions home/models.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,93 @@
from typing import Iterable
from django.db import models
from django.utils import timezone
import random

ALPHA = "abcdefghijklmnopqrstuvwxyz "

# Create your models here.
class Project(models.Model):
title = models.CharField(max_length=200)
description = models.CharField(max_length=300)
features = models.TextField(null=True, blank=True)
thumbnail_url = models.URLField(blank=True, null=True)
technologies = models.CharField(max_length=255)
demo_url = models.URLField(blank=True, null=True)
github_url = models.URLField(blank=True, null=True)
date = models.DateTimeField(auto_now_add=True)

def __str__(self):
return self.title

class Skill(models.Model):
name = models.CharField(max_length=200)
rate = models.IntegerField(verbose_name="Rate (out of 100)", default=0, null=False, blank=0)
tag = models.CharField(max_length=200, editable=False, default="", null=False)

def clamp_rate(self):
self.rate = min(100, max(0, self.rate))

def save(self, *args) -> None:
self.tag = "".join([char.lower() for char in self.tag if char.lower() in ALPHA])

if self.tag == "":
for _ in range(15):
self.tag += random.choice(ALPHA)

self.tag = self.tag.replace(" ", "_")

self.clamp_rate()
return super().save(*args)

def __str__(self):
return self.name

class About(models.Model):
text = models.TextField(blank=True, null=True)

def __str__(self):
return self.text.split("\n")[0][:20] # first line until 2Oth char

class Category(models.Model):
name = models.CharField(max_length=200)

def __str__(self) -> str:
return self.name

class Blog(models.Model):
sno = models.AutoField(primary_key=True)
title = models.CharField(max_length=200)
meta = models.CharField(max_length=300)
content = models.TextField()
thumbnail_img = models.ImageField(null=True, blank=True, upload_to="images/")
thumbnail_url = models.URLField(blank=True, null=True)
category = models.CharField(max_length=255, default="uncategorized")
slug = models.CharField(max_length=100)
categories = models.ManyToManyField("Category", blank=False) # TODO: Auto set to uncategorized
slug = models.CharField(max_length=100, unique=True)
time = models.DateField(auto_now_add=True)

def __str__(self):
return self.title
categories = list(self.categories.all())
print(self.title, categories)
categories = [c.name for c in categories]
return f"{self.title} || {'-'.join(categories)}"

""" def save(self, *args, **kwargs):
# Appel à super() pour sauvegarder l'objet dans la base de données
super().save(*args, **kwargs)

categories = list(self.categories.all())
if not categories:
# get the default category
default = Category.objects.filter(name="Uncategorized").first()

# Vérifiez si l'objet a un ID (c'est-à-dire s'il a été enregistré dans la base de données)
if self.pk:
# Ajoutez la catégorie par défaut
self.categories.add(default)
self.save(update_fields=['categories'])

print(f"Added category {default.name} to the post {self.title}")
print([c for c in self.categories.all()])
else:
print("Object not saved yet, cannot add default category.")"""

2 changes: 1 addition & 1 deletion home/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
urlpatterns = [
path('', views.index, name='home'),
path('about', views.about, name='about'),
path('contact', views.contact, name='contact'),
#path('contact', views.contact, name='contact'),
path('blog', views.blog, name='blog'),
path('projects', views.projects, name='projects'),
path('blogpost/<str:slug>', views.blogpost, name='blogpost'),
Expand Down
108 changes: 90 additions & 18 deletions home/views.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,66 @@
from django.shortcuts import render, HttpResponse, HttpResponseRedirect, redirect, get_object_or_404
from django.http import Http404
from home.models import Blog
from django.shortcuts import render
from home.models import Blog, Project, Skill, About, Category
from django.contrib import messages
from django.core.paginator import Paginator
from django.core.mail import send_mail
from django.db.models import Q
import random
import re


# manually defined tags for most commons techs
TECHNOLOGIES = {
'python': '<span class="text-xs bg-gradient-to-r from-cyan-500 to-blue-500 py-1 px-4 rounded-full"><i class="fa-brands fa-python"></i> Python</span>',
'sql': '<span class="text-xs bg-gradient-to-r from-cyan-500 to-blue-500 py-1 px-4 rounded-full"><i class="fa-brands fa-database"></i> SQL</span>',
'django': '<span class="text-xs bg-gradient-to-r from-cyan-500 to-blue-500 py-1 px-4 rounded-full"><i class="fa-brands fa-django"></i> Django</span>',
'html': '<span class="text-xs bg-gradient-to-r from-cyan-500 to-blue-500 py-1 px-4 rounded-full"><i class="fa-brands fa-html5"></i> HTML</span>',
'css': '<span class="text-xs bg-gradient-to-r from-cyan-500 to-blue-500 py-1 px-4 rounded-full"><i class="fa-brands fa-css3"></i> CSS</span>',
'js': '<span class="text-xs bg-gradient-to-r from-cyan-500 to-blue-500 py-1 px-4 rounded-full"><i class="fa-brands fa-square-js"></i> JavaScript</span>',
}

def get_tech_tags(tech:str):
if tech in TECHNOLOGIES:
return TECHNOLOGIES[tech.lower()]
else:
return f'<span class="text-xs bg-gradient-to-r from-cyan-500 to-blue-500 py-1 px-4 rounded-full"><i class="fa-brands fa-{tech.lower()}"></i> {tech}</span>'

def get_search_categories():
CATEGORIES_PER_LINE = 3
tabled_categories = [[] for i in range(CATEGORIES_PER_LINE)]

categories = Category.objects.all()

i = row = 0
while i < len(categories):
tabled_categories[row].append(categories[i])
i += 1
if i%CATEGORIES_PER_LINE == 0:
row += 1
return tabled_categories

# Create your views here.
def index (request):
blogs = Blog.objects.all()
random_blogs = random.sample(list(blogs), 3)
context = {'random_blogs': random_blogs}

context = {'random_blogs': random_blogs, "categories": get_search_categories()}
return render(request, 'index.html', context)

def about (request):
return render(request, 'about.html')
skills = Skill.objects.all()
about = About.objects.first()
about.text = about.text.replace("\n", "<br>")

NB_COLUMNS = 2
columns = [[] for _ in range(NB_COLUMNS)]

for i in range(len(skills)):
columns[i%NB_COLUMNS].append(skills[i])

return render(request, 'about.html', context={"about": about, "skills": columns, "categories": get_search_categories()})

def thanks(request):
return render(request, 'thanks.html')
return render(request, 'thanks.html', context={ "categories": get_search_categories()})

def contact (request):
if request.method == 'POST':
Expand Down Expand Up @@ -52,32 +93,62 @@ def contact (request):
# return HttpResponseRedirect('/thanks')
else:
messages.error(request, 'Email or Phone is Invalid!')
return render(request, 'contact.html', {})
return render(request, 'contact.html', context={"categories": get_search_categories()})

def projects(request):
limit = 5
if request.method == 'GET':
if 'all' in request.GET:
if request.GET['all'] == '1':
limit = None

projects_items = Project.objects.all().order_by('-date')

total_projects = len(projects_items)

# Limit the number of projects to display
if limit:
projects_items = projects_items[:limit]

def projects (request):
return render(request, 'projects.html')
all_there = len(projects_items) == total_projects

# Convert technologies to HTML tags
for project in projects_items:
techs = project.technologies.split(',')
project.technologies = [get_tech_tags(tech) for tech in techs]

# split the featured projects from lines to list
for project in projects_items:
project.features = project.features.split('\n')

return render(request, 'projects.html', {'projects': projects_items, "all": all_there, "categories": get_search_categories()})

def blog(request):
blogs = Blog.objects.all().order_by('-time')
paginator = Paginator(blogs, 3)
paginator = Paginator(blogs, 5)
page = request.GET.get('page')
blogs = paginator.get_page(page)
context = {'blogs': blogs}
context = {'blogs': blogs, "categories": get_search_categories()}
return render(request, 'blog.html', context)

def category(request, category):
category_posts = Blog.objects.filter(category=category).order_by('-time')
category = Category.objects.filter(name=category)
posts = Blog.objects.all()
category_posts = []
for post in posts:
if category in post.categories.all():
category_posts.append(post)
if not category_posts:
message = f"No posts found in category: '{category}'"
return render(request, "category.html", {"message": message})
paginator = Paginator(category_posts, 3)
page = request.GET.get('page')
category_posts = paginator.get_page(page)
return render(request, "category.html", {"category": category, 'category_posts': category_posts})
return render(request, "category.html", {"category": category, 'category_posts': category_posts, "categories": get_search_categories()})

def categories(request):
all_categories = Blog.objects.values('category').distinct().order_by('category')
return render(request, "categories.html", {'all_categories': all_categories})
all_categories = Category.objects.values('name')
return render(request, "categories.html", {'all_categories': all_categories, "categories": get_search_categories()})

def search(request):
query = request.GET.get('q')
Expand All @@ -92,18 +163,19 @@ def search(request):
message = "Sorry, no results found for your search query."
else:
message = ""
return render(request, 'search.html', {'results': results, 'query': query, 'message': message})
return render(request, 'search.html', {'results': results, 'query': query, 'message': message, "categories": get_search_categories()})


def blogpost (request, slug):
try:
blog = Blog.objects.get(slug=slug)
context = {'blog': blog}
context = {'blog': blog, "categories": get_search_categories()}
return render(request, 'blogpost.html', context)
except Blog.DoesNotExist:
context = {'message': 'Blog post not found'}
context = {'message': 'Blog post not found', "categories": get_search_categories()}
return render(request, '404.html', context, status=404)


# def blogpost (request, slug):
# blog = Blog.objects.filter(slug=slug).first()
# context = {'blog': blog}
Expand Down
Binary file added media/images/modem.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added media/images/reading_translucent.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified requirements.txt
Binary file not shown.
Loading