学习朔宁夫开发工程师课程笔记。

0架构:

01. MyDoc\PycharmProjects\ProjOnline,注册一个index app备主页用。

02. python manage.py startapp users, python manage.py startapp course. install apps.

03. total url

urlpatterns = [
    # http://127.0.0.1:8000/
    path("", include("index.urls", namespace="index")),
    path("admin/", admin.site.urls),
    path("user/", include("users.urls", namespace="user")),
    path("course/", include("course.urls", namespace="course")),
]

04. sub url 创建。

架构完成。

1 index_app编码:(main task:渲染主页。4个temp已经写好了,涉及2个文件夹’templates,static‘放到app目录下。删除temp下4个temp以外的文件。将temp文件夹复制到corse及user app下,然后3个app只保留相关temp即可。本次演示用默认的sqlite,不用mysql。setting LANGUAGE_CODE = "en-us" # "zh-hans" TIME_ZONE = "Asia/shanghai" # "UTC"

11.  views 类视图

from django.shortcuts import render
from django.views import View


class IndexView(View):
    def get(self, request):
        return render(self.request, 'index.html', locals())

12. urls

from django.urls import path

from index.views import IndexView


app_name = 'index'

urlpatterns = [
    path("", IndexView.as_view(), name="home")
]

13. 加载static index.html

<!doctype html>
{% load static %}
<html lang="zxx">

修改为正确{% static 'subpath' %}

可创建一个新的base_template,把公用模块写成block,用于后续course继承。

2 user_app编码(①记录用户登录状态;②登录/注册按钮显示为用户名):

21. views

from django.shortcuts import render
from django.views import View


class LoginRegisterView(View):
    def get(self, request):
        return render(request, 'my-account.html')

22. url

from django.urls import path

from users.views import LoginRegisterView


app_name = 'users'

urlpatterns = [
    path("login_register/", LoginRegisterView.as_view(), name='login_register')
]

23. html相应post表单中加入登录或注册链接

24. proj层new utils pack/ new py: utils.py

import hashlib


def gen_md5(string: str) -> str:
    md5 = hashlib.md5()
    md5.update(string.encode('utf-8'))
    return md5.hexdigest()

25. models 迁移

from django.db import models


class User(models.Model):
    user_name = models.CharField(max_length=64, verbose_name="User's name", unique=True)
    password = models.CharField(max_length=128, verbose_name="User's password")
    token = models.CharField(max_length=256, verbose_name="User's token", null=True)

    class Meta:
        db_table = 'users'
        verbose_name = 'users'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.user_name

    @classmethod
    def get_list(cls, **kwargs):
        filters = {}
        if kwargs.get('user_name'):
            filters['user_name'] = kwargs.get('user_name')
        if kwargs.get('password'):
            filters['password'] = kwargs.get('password')
        return cls.objects.filter(**filters)
    

26. 完善views

import time

from django.http import HttpResponseRedirect, HttpResponse
from django.shortcuts import render, redirect
from django.urls import reverse
from django.views import View

from users.models import User
from utils.utils import gen_md5


class LoginRegisterView(View):
    def get(self, request):
        return render(self.request, 'my_account.html', locals())


class LoginView(View):
    def post(self, request):
        name = self.request.POST.get('name')
        password = gen_md5(request.POST.get('password'))
        users = User.objects.filter(user_name=name, password=password)  # queryset
        if users:
            user = users.filter()
            user.token = gen_md5(user.user_name) + str(time.time())
            user.save()
            self.request.session['user_name'] = user.user_name
            self.request.session['user_token'] = user.token
            return redirect(reverse("index:home"))
        else:
            return HttpResponse("Invalid username or wrong password.")


class RegisterView(View):
    def post(self, request):
        name = self.request.POST.get('name')
        password = gen_md5(request.POST.get('password'))
        users = User.objects.filter(user_name=name)
        if users:
            return HttpResponse("Occupied name.")
        User.create_one(user_name=name, password=password)
        return redirect(reverse("users:login_register"))
        

注意之后写的所有接口都需要从session中获取user name。

以下对主页写session验证(后端获取user name,前端作判断和选择展示):

27. index views

from django.shortcuts import render
from django.views import View


class IndexView(View):
    def get(self, request):
        user_name = self.request.session["user_name"]
        return render(self.request, 'index.html', locals())

28. index temps

                        <div class="register">
                            {% if user_name %}
                            {{ user_name }}
                            {% else %}
                            <a href="{% url 'users:login_register' %}" class="default-btn">
                                Login / Register
                            </a>
                            {% endif %}
                        </div>

3 course_app编码(①名称、分类、售价、日期;②可以admin后台管理;③验证登录,否则跳转;④查询页面有搜索及排序功能):

31.  models 一对多,在多方 课程 写入外键。便于维护:将课程的固定信息和变动信息写成一对一的两张表。迁移。

from django.db import models


class CourseCategory(models.Model):
    category_name = models.CharField(max_length=32, unique=True, verbose_name='Category name')

    class Meta:
        db_table = 'course_category'
        verbose_name = 'course categories'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.category_name

    @classmethod
    def get_one_by_name(cls, category_name):
        return cls.objects.filter(category_name=category_name).first()

    @classmethod
    def get_all(cls):
        return cls.objects.all()


class Course(models.Model):
    name = models.CharField(max_length=32, unique=True, verbose_name='Course name')
    price = models.FloatField(verbose_name='Course price')
    category = models.ForeignKey(CourseCategory, on_delete=models.CASCADE)

    class Meta:
        db_table = 'course'
        verbose_name = 'Courses'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name

    @classmethod
    def get_list(cls, **kwargs):
        #  courses = []  # 实例化。避免报错。
        filters = {}
        if kwargs.get('name'):
            filters['name__contains'] = kwargs.get('name')
        if kwargs.get('category'):
            filters['category'] = kwargs.get('category')
        return cls.objects.filter(**filters)



class CourseInfo(models.Model):
    start_date = models.DateField(verbose_name='Start date')
    end_date = models.DateField(verbose_name='End date')
    course = models.OneToOneField(Course, on_delete=models.CASCADE)

    class Meta:
        db_table = 'course_info'
        verbose_name = 'course info'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.course.name

32. 视图类

from django.core.paginator import Paginator, InvalidPage
from django.shortcuts import render
from django.views import View

from course.models import *
from djangoProject.settings import PAGE_SIZE


class CourseListView(View):
    def get(self, request):
        category_name = request.GET.get('category', "")
        name = request.GET.get('name', "")
        page_num = self.request.GET.get("page", 1)
        courses = Course.get_list(category_name=category_name, name=name)
        # 注意这里查询是有bug。若同时传了两个参数,则name优先。应当q查询。
        categories = CourseCategory.get_all()
        filters = {}
        if category_name:
            filters['category'] = CourseCategory.get_one_by_name(category_name)
        if name:
            filters['name'] = name
        courses = Course.get_list(**filters)
        paginator = Paginator(courses, PAGE_SIZE)
        try:
            courses = paginator.page()
        except InvalidPage:
            courses = paginator.page(1)
        return render(request, 'courses.html', locals())

33. 课程详情页

models中写入course的get_one方法:


class Course(models.Model):
    name = models.CharField(max_length=32, unique=True, verbose_name='Course name')
    price = models.FloatField(verbose_name='Course price')
    category = models.ForeignKey(CourseCategory, on_delete=models.CASCADE)

    class Meta:
        db_table = 'course'
        verbose_name = 'Courses'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name

    @classmethod
    def get_one(cls, category_id):
        try:
            return cls.objects.get(pk=category_id)
        except Exception:
            return None

写入courseinfo的查找方法:

class CourseInfo(models.Model):
    start_date = models.DateField(verbose_name='Start date')
    end_date = models.DateField(verbose_name='End date')
    course = models.OneToOneField(Course, on_delete=models.CASCADE)

    class Meta:
        db_table = 'course_info'
        verbose_name = 'course info'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.course.name

    @classmethod
    def get_list(cls, **kwargs):
        filters = {}
        if kwargs.get('course'):
            filters['course'] = kwargs.get('course')
        return cls.objects.filter(**filters)

视图类:

class CourseDetailView(View):
    def get(self, request, course_id):
        course = Course.get_one(course_id)
        course_info = CourseInfo.get_list(course=course)
        return render(self.request, "single-course.html", locals())

urls:

from django.urls import path

from course.views import CourseListView, CourseDetailView

app_name = 'course'

urlpatterns = [
    path('list/', CourseListView.as_view(), name='list'),
    path('detail/<course_id>/', CourseDetailView.as_view(), name='detail')
]

完善html

4 功能联调

41. course_app 下new middleware.py

from django.shortcuts import redirect
from django.urls import reverse
from django.utils.deprecation import MiddlewareMixin


class CourseDetailsMiddleware(MiddlewareMixin):
    def process_request(self, request):
        if "/course/detail/" in request.path:
            user_name = request.session["user_name"]
            if not user_name:
                return redirect(reverse("user:login_register"))

注册 setting

MIDDLEWARE = [,
    "course.middleware.CourseDetailsMiddleware",
]

“无论什么语言的后端,无非“增删改查”。”

02-04 09:01