+2347067162698
tclassified.com@gmail.com

Django Online School

Educational Technology and ICT

Created with Sketch.

Django Online School

here we use Django to build an online school

Create a folder on your Desktop and name  Onlineschool
open the folder in Visual Studio Code(VSCode)
pip install django

django-admin startproject onlineschool
cd onlineschool
python manage.py startapp main

main
    -main (directory, your "primary" app)
    -mysite (directory, this is your new app)
    -manage.py (helper python script)

python manage.py runserver


onlineschool/onlineschool/urls.py
...........................
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path("", include('main.urls')),
    path('admin/', admin.site.urls),
]
...........................

onlineschool/main/urls.py
..............
from django.urls import path
from . import views


app_name = 'main'  # here for namespacing of urls.

urlpatterns = [
    path("", views.homepage, name="homepage"),
]
.................................

onlineschool/main/views.py
..................................
from django.shortcuts import render
from django.http import HttpResponse

# Create your views here.
def homepage(request):
    return HttpResponse("pythonprogramming.net homepage! Wow so #amaze.")
..............................................


onlineschool/main/models.py
........................................
from django.db import models


class Tutorial(models.Model):
    tutorial_title = models.CharField(max_length=200)
    tutorial_content = models.TextField()
    tutorial_published = models.DateTimeField('date published')

    def __str__(self):
        return self.tutorial_title
............................................................



onlineschool/onlineschool/settings.py
...................................
INSTALLED_APPS = [
    'main.apps.MainConfig',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]
................................................


python manage.py makemigrations

python manage.py migrate

python manage.py shell
.....................................
>>>from main.models import Tutorial
>>> Tutorial.objects.all()
<QuerySet []>
>>>from django.utils import timezone
>>>new_tutorial = Tutorial(tutorial_title="To be", tutorial_content="or not to be.That is the question.", tutorial_published=timezone.now())
>>> new_tutorial.save()

>>> Tutorial.objects.all()
<QuerySet []>


>>> for t in Tutorial.objects.all():
...     print(t.tutorial_title)
...
To be
......................................



python manage.py createsuperuser

onlineschool/main/admin.py
...............................
from django.contrib import admin
from .models import Tutorial


admin.site.register(Tutorial)
..............................................



onlineschool/main/admin.py
....................................
from django.contrib import admin
from .models import Tutorial


class TutorialAdmin(admin.ModelAdmin):
    fields = ["tutorial_title",
              "tutorial_published",
              "tutorial_content"]

admin.site.register(Tutorial,TutorialAdmin)
...............................................







main/models.py
..............................
from django.db import models
from datetime import datetime

class Tutorial(models.Model):
    tutorial_title = models.CharField(max_length=200)
    tutorial_content = models.TextField()
    tutorial_published = models.DateTimeField('date published', default=datetime.now)

    def __str__(self):
        return self.tutorial_title
..........................................

.....................................


But wait, there's more!

Remember what I was saying about Django being a collection of apps and part of what makes the abstraction that Django forces upon you awesome is that apps are highly modular? Let's see just how easy that can really be.

One thing my tutorials desperately could use is an editor, not really just some text field. I can write HTML in here, sure, but that would be rather tedious, especially if I made some typo and then I wouldn't see it until I push to publish it! Instead, I would like a WYSIWYG (what you see is what you get) editor. Luckily many of these exist within the Django ecosystem. The one I will make use of is a branch off of TinyMCE. To get it, we just need to do:

python -m pip install django-tinymce4-lite
.........................................
onlineschool/onlineschool/settings.py file:


INSTALLED_APPS = (
    ...
    'tinymce',
    ...
)
............................................
Then, somewhere in the settings.py also add:
.............................................

TINYMCE_DEFAULT_CONFIG = {
    'height': 360,
    'width': 1120,
    'cleanup_on_startup': True,
    'custom_undo_redo_levels': 20,
    'selector': 'textarea',
    'theme': 'modern',
    'plugins': '''
            textcolor save link image media preview codesample contextmenu
            table code lists fullscreen  insertdatetime  nonbreaking
            contextmenu directionality searchreplace wordcount visualblocks
            visualchars code fullscreen autolink lists  charmap print  hr
            anchor pagebreak
            ''',
    'toolbar1': '''
            fullscreen preview bold italic underline | fontselect,
            fontsizeselect  | forecolor backcolor | alignleft alignright |
            aligncenter alignjustify | indent outdent | bullist numlist table |
            | link image media | codesample |
            ''',
    'toolbar2': '''
            visualblocks visualchars |
            charmap hr pagebreak nonbreaking anchor |  code |
            ''',
    'contextmenu': 'formats | link image',
    'menubar': True,
    'statusbar': True,
    }

...................................
onlineschool/onlineschool/urls.py

urlpatterns = patterns('',
    ...
    path('tinymce/', include('tinymce.urls')),
    ...
)
.................................................
onlineschool/main/admin.py

from django.contrib import admin
from .models import Tutorial
from tinymce.widgets import TinyMCE
from django.db import models


class TutorialAdmin(admin.ModelAdmin):

    fieldsets = [
        ("Title/date", {'fields': ["tutorial_title", "tutorial_published"]}),
        ("Content", {"fields": ["tutorial_content"]})
    ]

    formfield_overrides = {
        models.TextField: {'widget': TinyMCE()},
        }


admin.site.register(Tutorial,TutorialAdmin)
................................................................

Now, refresh http://127.0.0.1:8000/admin/main/tutorial/add/

.....................................................


Views and Templating

.........................................


onlineschool/main/templates/main/home.html

{% load static %}
<!-- Prism CSS -->
<link href="{% static "tinymce/css/prism.css" %}" rel="stylesheet">
</head>
<body>

{% for tut in tutorials %}
    <p>{{tut.tutorial_title}}</p>
    <p>{{tut.tutorial_published}}</p>
    <p>{{tut.tutorial_content|safe}}</p>
    <br><br>
{% endfor %}


<!-- Prism JS -->
<script src="{% static "tinymce/js/prism.js" %}"></script>
</body>

...................................................................

onlineschool/main/views.py

from django.shortcuts import render
from django.http import HttpResponse
from .models import Tutorial

# Create your views here.
def homepage(request):
    return render(request = request,
                  template_name='main/home.html',
                  context = {"tutorials":Tutorial.objects.all})

.......................................................................

onlineschool/main/templates/main/header.html

<head>
    {% load static %}
    <!-- Prism CSS -->
    <link href="{% static "tinymce/css/prism.css" %}" rel="stylesheet">
    <!-- Compiled and minified CSS -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
    <!-- Compiled and minified JavaScript -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
</head>


<body>
  <nav>
    <div class="nav-wrapper">
      <a href="/" class="brand-logo">Tutorials</a>
      <ul id="nav-mobile" class="right hide-on-med-and-down">
        <li><a href="/">Home</a></li>
        <li><a href="/community">Community</a></li>
        <li><a href="/login">Login</a></li>
        <li><a href="/register">Register</a></li>
      </ul>
    </div>
  </nav>
  {% block content %}
  {% endblock %}
</body>

<!-- Prism JS -->
<script src="{% static "tinymce/js/prism.js" %}"></script>
....................................................................

onlineschool/main/templates/main/home.html

{% extends 'main/header.html' %}

{% block content %}
  <div class="row">
    {% for tut in tutorials %}
        <div class="col s12 m6">
          <div class="card blue-grey darken-1 hoverable">
            <div class="card-content white-text">
              <span class="card-title">{{tut.tutorial_title}}</span>
              <p style="font-size:70%">Published {{tut.tutorial_published}}</p>
              <p>{{tut.tutorial_content|safe}}</p>
            </div>
          </div>
        </div>
    {% endfor %}
{% endblock %} 

........................................
making it look better


Head to the getting started section and then choose the source download under "Sass" to get a .zip file.

Extract the zip file.

Navigate into the folder, and into the materialize-src directory.

Then click sass > components.
open up: _color-variables.scss
play with it if you wish and have this as the final file
...........................
// Google Color Palette defined: http://www.google.com/design/spec/style/color.html

$materialize-red: (
  "base":       #003F72,
  "lighten-5":  #86bfee,
  "lighten-4":  #5494c7,
  "lighten-3":  #3a7cb2,
  "lighten-2":  #24659a,
  "lighten-1":  #0e4f83,
  "darken-1":   #003158,
  "darken-2":   #002440,
  "darken-3":   #001424,
  "darken-4":   #000406,
);

$red: (
  "base":       #F44336,
  "lighten-5":  #FFEBEE,
  "lighten-4":  #FFCDD2,
  "lighten-3":  #EF9A9A,
  "lighten-2":  #E57373,
  "lighten-1":  #EF5350,
  "darken-1":   #E53935,
  "darken-2":   #D32F2F,
  "darken-3":   #C62828,
  "darken-4":   #B71C1C,
  "accent-1":    #FF8A80,
  "accent-2":    #FF5252,
  "accent-3":    #FF1744,
  "accent-4":    #D50000
);

$pink: (
  "base":       #e91e63,
  "lighten-5":  #fce4ec,
  "lighten-4":  #f8bbd0,
  "lighten-3":  #f48fb1,
  "lighten-2":  #f06292,
  "lighten-1":  #ec407a,
  "darken-1":   #d81b60,
  "darken-2":   #c2185b,
  "darken-3":   #ad1457,
  "darken-4":   #880e4f,
  "accent-1":    #ff80ab,
  "accent-2":    #ff4081,
  "accent-3":    #f50057,
  "accent-4":    #c51162
);

$purple: (
  "base":       #9c27b0,
  "lighten-5":  #f3e5f5,
  "lighten-4":  #e1bee7,
  "lighten-3":  #ce93d8,
  "lighten-2":  #ba68c8,
  "lighten-1":  #ab47bc,
  "darken-1":   #8e24aa,
  "darken-2":   #7b1fa2,
  "darken-3":   #6a1b9a,
  "darken-4":   #4a148c,
  "accent-1":    #ea80fc,
  "accent-2":    #e040fb,
  "accent-3":    #d500f9,
  "accent-4":    #aa00ff
);

$deep-purple: (
  "base":       #673ab7,
  "lighten-5":  #ede7f6,
  "lighten-4":  #d1c4e9,
  "lighten-3":  #b39ddb,
  "lighten-2":  #9575cd,
  "lighten-1":  #7e57c2,
  "darken-1":   #5e35b1,
  "darken-2":   #512da8,
  "darken-3":   #4527a0,
  "darken-4":   #311b92,
  "accent-1":    #b388ff,
  "accent-2":    #7c4dff,
  "accent-3":    #651fff,
  "accent-4":    #6200ea
);

$indigo: (
  "base":       #3f51b5,
  "lighten-5":  #e8eaf6,
  "lighten-4":  #c5cae9,
  "lighten-3":  #9fa8da,
  "lighten-2":  #7986cb,
  "lighten-1":  #5c6bc0,
  "darken-1":   #3949ab,
  "darken-2":   #303f9f,
  "darken-3":   #283593,
  "darken-4":   #1a237e,
  "accent-1":    #8c9eff,
  "accent-2":    #536dfe,
  "accent-3":    #3d5afe,
  "accent-4":    #304ffe
);

$blue: (
  "base":       #003F72,
  "lighten-5":  #86bfee,
  "lighten-4":  #5494c7,
  "lighten-3":  #3a7cb2,
  "lighten-2":  #24659a,
  "lighten-1":  #0e4f83,
  "darken-1":   #003158,
  "darken-2":   #002440,
  "darken-3":   #001424,
  "darken-4":   #000406,

  "accent-1":    #B9D9F4,
  "accent-2":    #89C3F4,
  "accent-3":    #57ADF6,
  "accent-4":    #168EF4
);

$light-blue: (
  "base":       #03a9f4,
  "lighten-5":  #e1f5fe,
  "lighten-4":  #b3e5fc,
  "lighten-3":  #81d4fa,
  "lighten-2":  #4fc3f7,
  "lighten-1":  #29b6f6,
  "darken-1":   #039be5,
  "darken-2":   #0288d1,
  "darken-3":   #0277bd,
  "darken-4":   #01579b,
  "accent-1":    #80d8ff,
  "accent-2":    #40c4ff,
  "accent-3":    #00b0ff,
  "accent-4":    #0091ea
);

$cyan: (
  "base":       #00bcd4,
  "lighten-5":  #e0f7fa,
  "lighten-4":  #b2ebf2,
  "lighten-3":  #80deea,
  "lighten-2":  #4dd0e1,
  "lighten-1":  #26c6da,
  "darken-1":   #00acc1,
  "darken-2":   #0097a7,
  "darken-3":   #00838f,
  "darken-4":   #006064,
  "accent-1":    #84ffff,
  "accent-2":    #18ffff,
  "accent-3":    #00e5ff,
  "accent-4":    #00b8d4
);

$teal: (
  "base":       #009688,
  "lighten-5":  #e0f2f1,
  "lighten-4":  #b2dfdb,
  "lighten-3":  #80cbc4,
  "lighten-2":  #4db6ac,
  "lighten-1":  #26a69a,
  "darken-1":   #00897b,
  "darken-2":   #00796b,
  "darken-3":   #00695c,
  "darken-4":   #004d40,
  "accent-1":    #a7ffeb,
  "accent-2":    #64ffda,
  "accent-3":    #1de9b6,
  "accent-4":    #00bfa5
);

$green: (
  "base":       #4CAF50,
  "lighten-5":  #E8F5E9,
  "lighten-4":  #C8E6C9,
  "lighten-3":  #A5D6A7,
  "lighten-2":  #81C784,
  "lighten-1":  #66BB6A,
  "darken-1":   #43A047,
  "darken-2":   #388E3C,
  "darken-3":   #2E7D32,
  "darken-4":   #1B5E20,
  "accent-1":    #B9F6CA,
  "accent-2":    #69F0AE,
  "accent-3":    #00E676,
  "accent-4":    #00C853
);

$light-green: (
  "base":       #8bc34a,
  "lighten-5":  #f1f8e9,
  "lighten-4":  #dcedc8,
  "lighten-3":  #c5e1a5,
  "lighten-2":  #aed581,
  "lighten-1":  #9ccc65,
  "darken-1":   #7cb342,
  "darken-2":   #689f38,
  "darken-3":   #558b2f,
  "darken-4":   #33691e,
  "accent-1":    #ccff90,
  "accent-2":    #b2ff59,
  "accent-3":    #76ff03,
  "accent-4":    #64dd17
);

$lime: (
  "base":       #cddc39,
  "lighten-5":  #f9fbe7,
  "lighten-4":  #f0f4c3,
  "lighten-3":  #e6ee9c,
  "lighten-2":  #dce775,
  "lighten-1":  #d4e157,
  "darken-1":   #c0ca33,
  "darken-2":   #afb42b,
  "darken-3":   #9e9d24,
  "darken-4":   #827717,
  "accent-1":    #f4ff81,
  "accent-2":    #eeff41,
  "accent-3":    #c6ff00,
  "accent-4":    #aeea00
);

$yellow: (
  "base":       #F4EB16,
  "lighten-5":  #F9F48E,
  "lighten-4":  #F6F176,
  "lighten-3":  #F5EF5F,
  "lighten-2":  #F5EE44,
  "lighten-1":  #F6EE2F,

  "darken-1":   #E3DB15,
  "darken-2":   #D2CA13,
  "darken-3":   #C1BB22,
  "darken-4":   #B1AC29,
  "accent-1":    #ffff8d,
  "accent-2":    #ffff00,
  "accent-3":    #ffea00,
  "accent-4":    #ffd600
);

$amber: (
  "base":       #ffc107,
  "lighten-5":  #fff8e1,
  "lighten-4":  #ffecb3,
  "lighten-3":  #ffe082,
  "lighten-2":  #ffd54f,
  "lighten-1":  #ffca28,
  "darken-1":   #ffb300,
  "darken-2":   #ffa000,
  "darken-3":   #ff8f00,
  "darken-4":   #ff6f00,
  "accent-1":    #ffe57f,
  "accent-2":    #ffd740,
  "accent-3":    #ffc400,
  "accent-4":    #ffab00
);

$orange: (
  "base":       #ff9800,
  "lighten-5":  #fff3e0,
  "lighten-4":  #ffe0b2,
  "lighten-3":  #ffcc80,
  "lighten-2":  #ffb74d,
  "lighten-1":  #ffa726,
  "darken-1":   #fb8c00,
  "darken-2":   #f57c00,
  "darken-3":   #ef6c00,
  "darken-4":   #e65100,
  "accent-1":    #ffd180,
  "accent-2":    #ffab40,
  "accent-3":    #ff9100,
  "accent-4":    #ff6d00
);

$deep-orange: (
  "base":       #ff5722,
  "lighten-5":  #fbe9e7,
  "lighten-4":  #ffccbc,
  "lighten-3":  #ffab91,
  "lighten-2":  #ff8a65,
  "lighten-1":  #ff7043,
  "darken-1":   #f4511e,
  "darken-2":   #e64a19,
  "darken-3":   #d84315,
  "darken-4":   #bf360c,
  "accent-1":    #ff9e80,
  "accent-2":    #ff6e40,
  "accent-3":    #ff3d00,
  "accent-4":    #dd2c00
);

$brown: (
  "base":       #795548,
  "lighten-5":  #efebe9,
  "lighten-4":  #d7ccc8,
  "lighten-3":  #bcaaa4,
  "lighten-2":  #a1887f,
  "lighten-1":  #8d6e63,
  "darken-1":   #6d4c41,
  "darken-2":   #5d4037,
  "darken-3":   #4e342e,
  "darken-4":   #3e2723
);

$blue-grey: (
  "base":       #607d8b,
  "lighten-5":  #eceff1,
  "lighten-4":  #cfd8dc,
  "lighten-3":  #b0bec5,
  "lighten-2":  #90a4ae,
  "lighten-1":  #78909c,
  "darken-1":   #546e7a,
  "darken-2":   #455a64,
  "darken-3":   #37474f,
  "darken-4":   #263238
);

$grey: (
  "base":       #9e9e9e,
  "lighten-5":  #fafafa,
  "lighten-4":  #f5f5f5,
  "lighten-3":  #eeeeee,
  "lighten-2":  #e0e0e0,
  "lighten-1":  #bdbdbd,
  "darken-1":   #757575,
  "darken-2":   #616161,
  "darken-3":   #424242,
  "darken-4":   #212121
);

$shades: (
  "black":        #000000,
  "white":        #FFFFFF,
  "transparent":  transparent
);

$colors: (
  "materialize-red": $materialize-red,
  "red": $red,
  "pink": $pink,
  "purple": $purple,
  "deep-purple": $deep-purple,
  "indigo": $indigo,
  "blue": $blue,
  "light-blue": $light-blue,
  "cyan": $blue,
  "teal": $blue,
  "green": $green,
  "light-green": $blue,
  "lime": $lime,
  "yellow": $yellow,
  "amber": $amber,
  "orange": $orange,
  "deep-orange": $deep-orange,
  "brown": $brown,
  "blue-grey": $blue-grey,
  "grey": $grey,
  "shades": $shades
) !default;


// usage: color("name_of_color", "type_of_color")
// to avoid to repeating map-get($colors, ...)

@function color($color, $type) {
  @if map-has-key($colors, $color) {
    $curr_color: map-get($colors, $color);
    @if map-has-key($curr_color, $type) {
      @return map-get($curr_color, $type);
    }
  }
  @warn "Unknown `#{$color}` - `#{$type}` in $colors.";
  @return null;
}
...........................................................

Once you have your variables set, you're ready to compile to CSS. To do this, you need a Sass compiler. I personally used Koala. Download that, install.
On Windows, I just use the + button on the top left. Navigate to the Materialize-src folder and open that. Then, you can click once on the materialize-src/sass/materialize.scss to choose it, then click compile on the bottom right.

Now you can navigate to the materialize-src/css section to grab your customized materialize.css file. Great!
Now let's take that and place it into onlineschool/main/static/main/css/materialize.css. Once that's done, let's reference this new css rather than the hosted one. Go into your onlineschool/main/templates/main/header.html and swap the hosted CSS for:

<link rel="stylesheet" href="{% static "main/css/materialize.css" %}">


Refresh the homepage and now the navbar, for example, should be a different color. I am going to go ahead and change the color of the cards now to the default white, editing onlineschool/main/templates/main/home.html:

.........................................
onlineschool/main/templates/main/home.html

{% extends 'main/header.html' %}

{% block content %}
  <div class="row">
    {% for tut in tutorials %}
        <div class="col s12 m6">
          <div class="card hoverable">
            <div class="card-content">
              <span class="card-title">{{tut.tutorial_title}}</span>
              <p style="font-size:70%">Published {{tut.tutorial_published}}</p>
              <p>{{tut.tutorial_content|safe}}</p>
            </div>
          </div>
        </div>
    {% endfor %}
{% endblock %}
.....................................................

User Registration - Django Tutorial

..............................................
onlineschool/main/views.py

from django.shortcuts import render, redirect
from .models import Tutorial
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
from django.contrib.auth import logout, authenticate, login


# Create your views here.
def homepage(request):
    return render(request = request,
                  template_name='main/home.html',
                  context = {"tutorials":Tutorial.objects.all})

def register(request):
    if request.method == "POST":
        form = UserCreationForm(request.POST)
        if form.is_valid():
            user = form.save()
            username = form.cleaned_data.get('username')
            login(request, user)
            return redirect("main:homepage")

        else:
            for msg in form.error_messages:
                print(form.error_messages[msg])

            return render(request = request,
                          template_name = "main/register.html",
                          context={"form":form})

    form = UserCreationForm
    return render(request = request,
                  template_name = "main/register.html",
                  context={"form":form})

.......................................................................
onlineschool/main/templates/main/register.html

{% extends 'main/header.html' %}

{% block content %}
    <br>
    <form method="POST">
        {% csrf_token %}
        {{form.as_p}}
        <button style="background-color:#F4EB16; color:blue" class="btn btn-outline-info" type="submit">Sign Up</button>
    </form>

    If you already have an account <a href="/login" target="blank"><strong>login</strong></a> instead.

{% endblock %}


...........................................................
onlineschool/main/urls.py

from django.urls import path
from . import views


app_name = 'main'  # here for namespacing of urls.

urlpatterns = [
  path("", views.homepage, name="homepage"),
  path("register/", views.register, name="register"),
]
................................................................


Messages

....................................................
onlineschool/main/templates/main/header.html


<head>
    {% load static %}
    <!-- Prism CSS -->
    <link href="{% static "tinymce/css/prism.css" %}" rel="stylesheet">
    <!-- Compiled and minified CSS -->
    <link rel="stylesheet" href="{% static "main/css/materialize.css" %}">
    <!-- Compiled and minified JavaScript -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
</head>


<body>

  <nav>
    <div class="nav-wrapper"
      <a href="/" class="brand-logo">Tutorials</a>
      <ul id="nav-mobile" class="right hide-on-med-and-down">
        {% include 'main/includes/navbaritems.html' %}
      </ul>
    </div>
  </nav>

  {% include 'main/includes/messaging.html' %}

  <div class="container">
    {% block content %}
    {% endblock %}
  </div>
</body>

<!-- Prism JS -->
<script src="{% static "tinymce/js/prism.js" %}"></script>

..................................................................
onlineschool/main/templates/main/includes/messaging.html

{% if messages %}
        {% for message in messages %}
            {% if message.tags == 'success'%}
                <script>M.toast({html: "{{message}}", classes: 'green rounded', displayLength:2000});</script>
            {% elif message.tags == 'info'%}
                <script>M.toast({html: "{{message}}", classes: 'blue rounded', displayLength:2000});</script>
            {% elif message.tags == 'warning'%}
                <script>M.toast({html: "{{message}}", classes: 'orange rounded', displayLength:10000});</script>
            {% elif message.tags == 'error'%}
                <script>M.toast({html: "{{message}}", classes: 'red rounded', displayLength:10000});</script>
            {% endif %}
        {% endfor %}
    {% endif %}

....................................................................
onlineschool/main/templates/main/includes/navbaritems.html

        <li><a href="/">Home</a></li>
        <li><a href=" ">Community</a></li>
        {% if user.is_authenticated %}
             <li><a href="">{{user.username|title}}</a></li>
             <li><a href="/logout">Logout</a></li>
        {% else %}
            <li><a href="/login">Login</a></li>
            <li><a href="/register">Register</a></li>
        {% endif %}

.....................................................................
replace the register function in the views.py with this

from django.contrib import messages

def register(request):
    if request.method == "POST":
        form = UserCreationForm(request.POST)
        if form.is_valid():
            user = form.save()
            username = form.cleaned_data.get('username')
            messages.success(request, f"New account created: {username}")
            login(request, user)
            return redirect("main:homepage")

        else:
            for msg in form.error_messages:
                messages.error(request, f"{msg}: {form.error_messages[msg]}")

            return render(request = request,
                          template_name = "main/register.html",
                          context={"form":form})

    form = UserCreationForm
    return render(request = request,
                  template_name = "main/register.html",
                  context={"form":form})

...............................................................................
User login and Logout

.......................................................
onlineschool/main/urls.py


from django.urls import path
from . import views


app_name = 'main'  # here for namespacing of urls.

urlpatterns = [
    path("", views.homepage, name="homepage"),
    path("register/", views.register, name="register"),
    path("logout", views.logout_request, name="logout"),
    path("login", views.login_request, name="login"),
]


..............................................................
onlineschool/main/views.py

add this

from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
from .forms import NewUserForm
...
def logout_request(request):
    logout(request)
    messages.info(request, "Logged out successfully!")
    return redirect("main:homepage")
  ...



...

def login_request(request):
    if request.method == 'POST':
        form = AuthenticationForm(request=request, data=request.POST)
        if form.is_valid():
            username = form.cleaned_data.get('username')
            password = form.cleaned_data.get('password')
            user = authenticate(username=username, password=password)
            if user is not None:
                login(request, user)
                messages.info(request, f"You are now logged in as {username}")
                return redirect('/')
            else:
                messages.error(request, "Invalid username or password.")
        else:
            messages.error(request, "Invalid username or password.")
    form = AuthenticationForm()
    return render(request = request,
                    template_name = "main/login.html",
                    context={"form":form})
........................................................

onlineschool/main/templates/main/login.html

{% extends 'main/header.html' %}

{% block content %}

    <div class="container">
        <form method="POST">
        {% csrf_token %}
        {{form.as_p}}
            <button style="background-color:#F4EB16; color:blue" class="btn btn-outline-info" type="submit">Login</button>
        </form>
        Don't have an account? <a href="/register" target="blank"><strong>register here</strong></a>!
    </div>
{% endblock %}
................................................

onlineschool/main/forms.py

from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User

class NewUserForm(UserCreationForm):
    email = forms.EmailField(required=True)

    class Meta:
        model = User
        fields = ("username", "email", "password1", "password2")

    def save(self, commit=True):
        user = super(NewUserForm, self).save(commit=False)
        user.email = self.cleaned_data["email"]
        if commit:
            user.save()
        return user

..........................................................

lastly, in the views.py

Then replace the two instances of UserCreationForm with NewUserForm in the register function.

Now make sure you're logged out and register a new user. This time, there will be a password field.
........................................................


Foreign keys with models

...................................................
To begin, let's start by creating the TutorialCategory model.
.....................................
onlineschool/main/models.py

class TutorialCategory(models.Model):

    tutorial_category = models.CharField(max_length=200)
    category_summary = models.CharField(max_length=200)
    category_slug = models.CharField(max_length=200, default=1)

    class Meta:
        # Gives the proper plural name for admin
        verbose_name_plural = "Categories"

    def __str__(self):
        return self.tutorial_category


class TutorialSeries(models.Model):
    tutorial_series = models.CharField(max_length=200)

    tutorial_category = models.ForeignKey(TutorialCategory, default=1, verbose_name="Category", on_delete=models.SET_DEFAULT)
    series_summary = models.CharField(max_length=200)

    class Meta:
        # otherwise we get "Tutorial Seriess in admin"
        verbose_name_plural = "Series"

    def __str__(self):
        return self.tutorial_series
.........................................................
then modify tutorials model to
.........................................................
class Tutorial(models.Model):
    tutorial_title = models.CharField(max_length=200)
    tutorial_content = models.TextField()
    tutorial_published = models.DateTimeField('date published')
    #https://docs.djangoproject.com/en/2.1/ref/models/fields/#django.db.models.ForeignKey.on_delete
    tutorial_series = models.ForeignKey(TutorialSeries, default=1, verbose_name="Series", on_delete=models.SET_DEFAULT)
    tutorial_slug = models.CharField(max_length=200, default=1)
    def __str__(self):
        return self.tutorial_title


..................................
python manage.py makemigrations


python manage.py migrate

............................................
onlineschool/main/admin.py

from .models import Tutorial, TutorialSeries, TutorialCategory
...
class TutorialAdmin(admin.ModelAdmin):

    fieldsets = [
        ("Title/date", {'fields': ["tutorial_title", "tutorial_published"]}),
        ("URL", {'fields': ["tutorial_slug"]}),
        ("Series", {'fields': ["tutorial_series"]}),
        ("Content", {"fields": ["tutorial_content"]})
    ]

    formfield_overrides = {
        models.TextField: {'widget': TinyMCE(attrs={'cols': 80, 'rows': 30})},
        }


admin.site.register(TutorialSeries)
admin.site.register(TutorialCategory)
admin.site.register(Tutorial,TutorialAdmin)

...................................................


Working with foreign keys

..............................................
onlineschool/main/templates/main/category.html

{% extends 'main/header.html' %}

{% block content %}

    <div class="row">
        {% for tut, partone in part_ones.items %}

            <div class="col s12 m6 l4">
                <a href="{{partone}}", style="color:#000">
                    <div class="card hoverable">
                        <div class="card-content">
                            <div class="card-title">{{tut.tutorial_series}}</div>
                            <!--<p style="font-size:70%">Published {{tut.tutorial_published}}</p>-->
                            <p>{{tut.series_summary}}</p>
                        </div>
                    </div>
                </a>
            </div>
        {% endfor %}
    </div>
{% endblock %}

....................................................

in the views.py

from .models import Tutorial, TutorialCategory, TutorialSeries
from django.http import HttpResponse

def homepage(request):
    return render(request=request,
                  template_name='main/categories.html',
                  context={"categories": TutorialCategory.objects.all})

def single_slug(request, single_slug):
    # first check to see if the url is in categories.

    categories = [c.category_slug for c in TutorialCategory.objects.all()]
    if single_slug in categories:
        matching_series = TutorialSeries.objects.filter(tutorial_category__category_slug=single_slug)
        series_urls = {}

        for m in matching_series.all():
            part_one = Tutorial.objects.filter(tutorial_series__tutorial_series=m.tutorial_series).earliest("tutorial_published")
            series_urls[m] = part_one.tutorial_slug

        return render(request=request,
                      template_name='main/category.html',
                      context={"tutorial_series": matching_series, "part_ones": series_urls})
..............................................
 add this to main/urls.py

path("<single_slug>", views.single_slug, name="single_slug"),

.................................................................
onlineschool/main/templates/categories.html

{% extends 'main/header.html' %}

{% block content %}

    <div class="row">
        {% for cat in categories %}
            <div class="col s12 m6 l4">
                <a href="{{cat.category_slug}}", style="color:#000">
                    <div class="card hoverable">
                        <div class="card-content">
                            <div class="card-title">{{cat.tutorial_category}}</div>
                            <!--<p style="font-size:70%">Published {{tut.tutorial_published}}</p>-->
                            <p>{{cat.category_summary}}</p>
                        </div>
                    </div>
                </a>
            </div>
        {% endfor %}
    </div>
{% endblock %}
...............................................................

Dynamic Sidebar

......................................
hearder.html


<head>
    {% load static %}
    <!-- Prism CSS -->
    <link href="{% static "tinymce/css/prism.css" %}" rel="stylesheet">
    <!-- Compiled and minified CSS -->
    <link rel="stylesheet" href="{% static "main/css/materialize.css" %}">
    <!-- Compiled and minified JavaScript -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
</head>

<body>
  <nav>
    <div class="nav-wrapper"
      <a href="/" class="brand-logo">Tutorials</a>
      <ul id="nav-mobile" class="right hide-on-med-and-down">
        {% include 'main/includes/navbaritems.html' %}
      </ul>
    </div>
  </nav>

  {% include 'main/includes/messaging.html' %}

  <div class="container">
    {% block content %}
    {% endblock %}
  </div>
</body>

<script src="{% static "tinymce/js/prism.js" %}"></script>
<script>M.AutoInit();</script>

...............................................
templates/main/tutorial.html


{% extends 'main/header.html' %}

{% block content %}

    <div class="row">

        <div class="col s12, m8, l8">
            <h3>{{tutorial.tutorial_title}}</h3>
            <p style="font-size:70%">Published {{tutorial.tutorial_published}}</p>
            {{tutorial.tutorial_content|safe}}
        </div>

        <div class="col s12 m4 l4">
            <ul class="collapsible popout">
                {% for tutorial in sidebar %}
                    {% if forloop.counter0 == this_tut_idx %}
                        <li class="active">
                            <div class="collapsible-header">{{tutorial.tutorial_title}}<br>(currently viewing)</div>
                        </li>
                    {% else %}
                        <li>
                            <div class="collapsible-header">{{tutorial.tutorial_title}}</div>
                            <div class="collapsible-body">
                                <p><a href="/{{tutorial.tutorial_slug}}"><button class="btn waves-effect waves-light right-align" style="background-color:yellow; color:black">Go</button></a></p>

                            </div>
                        </li>
                    {% endif %}
                {% endfor %}
            </ul>
        </div>

    </div>

{% endblock %}
.................................................

in views.py at the single_slug function


    tutorials = [t.tutorial_slug for t in Tutorial.objects.all()]

    if single_slug in tutorials:
        this_tutorial = Tutorial.objects.get(tutorial_slug=single_slug)
        tutorials_from_series = Tutorial.objects.filter(tutorial_series__tutorial_series=this_tutorial.tutorial_series).order_by('tutorial_published')
        this_tutorial_idx = list(tutorials_from_series).index(this_tutorial)

        return render(request=request,
                      template_name='main/tutorial.html',
                      context={"tutorial": this_tutorial,
                               "sidebar": tutorials_from_series,
                               "this_tut_idx": this_tutorial_idx})
.......................................................................


notes.....

1. remove your text editor from save on edit
2. create the whole models first, then migrate, before adding data



Deploy your website to Linode, Heroku, Digital Ocean etc

Leave a Reply

Your email address will not be published. Required fields are marked *

Open chat