Okay my friend, thank you for trying so hard to help me.
I am sending everything.
First is models.py from Accounts app.
from django.db import models
from django.contrib.auth.models import AbstractUser
def file_upload_path(instance, filename):
return f"user-{instance.user.id}/files/{filename}"
class User(AbstractUser):
# DEFINE ROLES
class Role(models.TextChoices):
ADMIN = "ADMIN", "Admin"
# this Owner role is the client, she will upload her lessons, so we can say she is also the teacher.
OWNER = "OWNER", "Owner"
# these will be the employees. For another time i have to learn, how can the owner add her employees so they can do something
EMPLOYEE = "EMPLOYEE", "Employee"
# this is the student. We called it "Customer" in this eample
CUSTOMER = "CUSTOMER", "Customer"
email = models.EmailField(max_length=50, unique=True)
username = models.CharField(max_length=20, unique=True)
role = models.CharField(max_length=10, choices=Role.choices, blank=True, null=True)
image = models.ImageField(upload_to=file_upload_path, default='default/profile-demo.png')
USERNAME_FIELD = "email"
REQUIRED_FIELDS = ["username"]
agree_to_terms = models.BooleanField('I agree to TOS', default=False, blank=False, null=False)
def __str__(self):
return self.email
def show_full_name(self):
return f'{self.first_name} {self.last_name}'
def get_role(self):
if self.role == User.Role.ADMIN:
user_role = "Admin"
elif self.role == User.Role.CUSTOMER:
user_role = "Customer"
elif self.role == User.Role.OWNER:
user_role = "Owner"
return user_role
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
note = models.CharField(max_length=50)
#def __str__(self):
#return self.note
Views.py from Accounts app, for registering that Cusomer role
# CUSTOMER REGISTRATION
# REGISTER WITH EMAIL VERIFICATION
def register_view_customer(request):
if request.user.is_authenticated:
messages.warning(request, 'You are already logged in!')
return redirect('dashboard:dashboard')
if request.method == 'POST':
register_form = UserRegisterForm(request.POST)
if register_form.is_valid():
user = register_form.save(commit=False)
user.is_active = False
user.role = User.Role.CUSTOMER
user.save()
group = Group.objects.get(name='Customers')
group.user_set.add(user)
# send verification email
mail_subject = "Please activate your customer account"
email_template = 'accounts/verification/account_verification_email.html'
send_verification_email(request, user, mail_subject, email_template)
return redirect('accounts:email_verification_sent')
else:
register_form = UserRegisterForm()
context = {
'form': register_form
}
return render(request, 'accounts/register-customer.html', context)
# REGISTER OWNER WITH EMAIL VERIFICATION, this is our client registration view
def register_view(request):
if request.user.is_authenticated:
messages.warning(request, 'You are already logged in!')
return redirect('dashboard:dashboard')
if request.method == 'POST':
register_form = UserRegisterForm(request.POST)
if register_form.is_valid():
user = register_form.save(commit=False)
user.is_active = False
user.role = User.Role.OWNER
user.save()
group = Group.objects.get(name='Customers')
group.user_set.add(user)
# send verification email
#mail_subject = "Please activate your account"
#email_template = 'accounts/verification/account_verification_email.html'
#send_verification_email(request, user, mail_subject, email_template)
return redirect('accounts:email_verification_sent')
else:
register_form = UserRegisterForm()
context = {
'form': register_form
}
return render(request, 'accounts/register.html', context)
That is all working, i also have a function to check the role and redirect to Owner or Customer dashboard, now we are going to Courses app.
Site owner / client, can log in. Site owner IS the teacher/client. I have a new question about adding employees, but that is for another time.
She can create courses, add modules to courses and lessons to modules…
Courses can have modules, like module 1, module 2, module 3…
Each module will have lessons. Many Lessons belong only to ONE course.
So you can have a course for example:
“How to create a Django website”
Module 1
Module 2
Module 3
- lesson 5
- lesson 6
- lesson 7
So for example like above, we have a course, with 3 modules and 7 lessons in total (example).
Here is the models.py
from django.db import models
from django.urls import reverse
from django.conf import settings
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.contrib.auth import get_user_model
User = get_user_model()
class Pricing(models.Model):
name = models.CharField(max_length=100) # basic/pro/premium
def __str__(self):
return self.name
class Subscription(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
pricing = models.ForeignKey(Pricing, on_delete=models.CASCADE)
created = models.DateTimeField(auto_now_add=True)
stripe_subscription_id = models.CharField(max_length=100)
status = models.CharField(max_length=100)
def __str__(self):
return self.user.email
# Course model
class Course(models.Model):
name = models.CharField(max_length=100, unique=True)
slug = models.SlugField(max_length=100, unique=True, blank=True, null=True)
image = models.ImageField(upload_to='course/thumbnails')
pricing_tiers = models.ManyToManyField(Pricing, blank=True)
# relation to user
# teacher/company owner/ client who creates the course
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
# Customer user, how to connect?
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('courses:course', args=[str(self.slug)])
def clean(self):
self.name = self.name.capitalize()
self.slug = self.slug.lower()
# Module
class Module(models.Model):
name = models.CharField(max_length=100, default='Module name', unique=True)
# one Course can have many Modules
course = models.ForeignKey(Course, on_delete=models.CASCADE, related_name='modules')
def __str__(self):
return self.name
def clean(self):
self.name = self.name.capitalize()
# Lessons
class Lesson(models.Model):
title = models.CharField(max_length=100, unique=True)
slug = models.SlugField(max_length=110, unique=True)
content = models.TextField() # i will change this to ckeditor later
is_completed = models.BooleanField(default=False)
# Relation to Course
# Many lessons can belong to only one Course
course = models.ForeignKey(Course, on_delete=models.CASCADE, related_name="course_lessons")
# Relation to Module
module = models.ForeignKey(Module, on_delete=models.CASCADE, related_name='module_lessons')
# User? Should i connect the Lesson with Owner User who is creating it?
# for previous and next lesson in the template
order = models.IntegerField(default=1)
# Video
# each lesson will have one video, i don't know should i add a video here, on create a model for it, with a Foreign key?
# PDF materials
# same question like above
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('courses:view_lesson', args=[str(self.course.slug), str(self.slug)])
def clean(self):
self.title = self.title.capitalize()
self.slug = self.slug.lower()
# Do i need this?
# class Meta:
ordering = ['order']
class Video(models.Model):
title = models.CharField(max_length=100, unique=True)
# Relation to lesson
# considering the above mentioned, don't know yet how to approach
lesson = models.ForeignKey(Lesson, on_delete=models.CASCADE)
# should i connect this model with the Owner user?
vimeo_id = models.CharField(max_length=50)
def __str__(self):
return self.title
class PdfMaterial(models.Model):
title = models.CharField(max_length=100)
file = models.FileField(upload_to="uploads/pdf/%Y/%m/%d/")
# Relation to Lesson
# one lesson can have more pdf files for people to download
lesson = models.ForeignKey(Lesson, on_delete=models.CASCADE)
# should i connect this model with the Owner user?
def __str__(self):
return self.name
# This is a Signal to create a Subscription when the User is created, but i am not sure about this, because i already have UserProfile Signal in accounts...
'''
def post_save_user(sender, instance, created, *args, **kwargs):
if created:
free_trial_pricing = Pricing.objects.get(name="Free Trial")
Subscription.objects.create(user=instance, pricing=free_trial_pricing)
post_save.connect(post_save_user, sender=User)
'''
This is the Course Admin.py
from django.contrib import admin
from .models import Course, Module, Lesson, Video, PdfMaterial, Subscription, Pricing
@admin.register(Course)
class CourseAdmin(admin.ModelAdmin):
list_display = [
'name', 'slug',
]
@admin.register(Module)
class ModuleAdmin(admin.ModelAdmin):
list_display = [
'name', 'course'
]
@admin.register(Lesson)
class LessonAdmin(admin.ModelAdmin):
list_display = [
'name', 'course', 'module',
]
@admin.register(Video)
class VideoAdmin(admin.ModelAdmin):
list_display = [
'title', 'lesson',
]
@admin.register(PdfMaterial)
class PdfMaterialAdminAdmin(admin.ModelAdmin):
list_display = [
'name', 'lesson',
]
@admin.register(Pricing)
class PricingAdmin(admin.ModelAdmin):
list_display = [
'name'
]
@admin.register(Subscription)
class SubscriptionAdmin(admin.ModelAdmin):
list_display = [
'user', 'pricing'
]
This is the sidebar template which i am including in Course page and in Lesson page
{% for lesson in module.module_lessons.all %}
{{lesson.title}}
15:00 min
{% if lesson.completed %}
{% else %}
{% endif %}
{% endfor %}
…
This is the Lesson.html page where i extend the course base
<div class="completed-check">
{% if lesson.completed %}
<div class="completed-yes">
<div class="text-block-52"><span></span></div>
<div class="text-block-53">Completed</div>
</div>
{% else %}
<div class="completed-no">
<div class="w-form">
<form id="" name="" data-name="" method="get" data-wf-page-id="647661c0f546d8bc8cea2413" data-wf-element-id="6fb5eb60-1b28-c9f3-1a2f-3a7125640495"><input type="submit" value="Mark as complete" data-wait="Please wait..." class="mark-as-complete-btn w-button"></form>
</div>
</div>
{% endif %}
</div>
</div>
<a href="{{next_lesson.get_absolute_url}}" class="next-lesson-link w-inline-block">
<div class="backend-paragraph lctt__lesson-count">Next lesson:</div>
<div>{{next_lesson}}</div>
</a>
</div>
Now, i don’t understand:
if django is recommending to use only one User, how do i connect a Course with a Customer user, considering i have to connect the Course with the Owner user who is actually creating the course/modules/lessons.