Begin

Python下有许多款不同的 Web 框架。Django是重量级选手中最有代表性的一位。许多成功的网站和APP都基于Django。

项目目录结构


|--project

    |--__init__.py 空文件

    |--settings.py 项目的配置文件

    |--urls.py 路由定义

    |--wsgi.py 与服务器对接

本地化

settings.py


LANGUAGE_CODE = 'en-us'


TIME_ZONE = 'UTC'

修改为:


LANGUAGE_CODE = 'zh-hans'


TIME_ZONE = 'Asia/Shanghai'

新建静态目录

网站通常需要提供类似图片,JavaScript 或 CSS 的额外文件服务。在 Django 中,我们将这些文件称为“静态文件”。Django 提供了 django.contrib.staticfiles 帮你管理它们。

添加以下配置:


STATIC_URL = '/static/'

# 新建static文件夹

STATICFILES_DIRS = os.path.join(BASE_DIR, "static")

数据库配置


DATABASES = {

    'default': {

        'ENGINE': 'django.db.backends.postgresql',

        'NAME': 'mydatabase',

        'USER': 'mydatabaseuser',

        'PASSWORD': 'mypassword',

        'HOST': '127.0.0.1',

        'PORT': '5432',

    }

}

详见:https://docs.djangoproject.com/zh-hans/3.0/ref/settings/#std:setting-DATABASES

服务启动

python manage.py runserver 0.0.0.0:8080

外部访问:ALLOWED_HOSTS = ['*']

创建APP

python manage.py startapp user

创建后项目目录会存在user文件夹

Hello world

在user/views.py内


from django.http import HttpResponse


def index(request):

    return HttpResponse('Hello World!')

在urls.py内


from user import views


urlpatterns = [

    path('admin/', admin.site.urls),

    path('', views.index),

]

在Django2.0前用url(r'正则表达式', '视图函数')

路由

settings.py内的 ROOT_URLCONF = 'untitled1.urls'找到 urls.py路由表

路由传参

在views内


def show_article(requset, num, name):

    return HttpResponse(str(num)+name)

在urls内


    path('article/<int:num><str:name>', views.show_article),

主子路由

  1. 在APP里新建 urls.py
  2. 主路由中定义 path('user/', include('user.urls'))
  3. 配置APP内的路由 path('login', login)

视图

视图函数格式


    def xxx(request):

        return response对象

request请求

由请求行,请求头,请求体组成


def index(request):

    print(request.path)

    print(request.method)

    print(request.is_ajax())

    print(request.scheme)

    print(request.GET)

    print(request.POST)

    print(request.FILES)

    print(request.META.get('REMOTE_ADDR'))

    # 运行结果

    # /

    # GET

    # False

    # http

    # < QueryDict: {} >

    # < QueryDict: {} >

    # < MultiValueDict: {} >

    # 127.0.0.1

    return HttpResponse('Hello World!')

response响应

由响应行,响应头,响应体组成

reder函数

通过模板引擎Django加载模板,将模板加载完成后转成 str类,再将 strHttpResponse并返回 response对象。

redirect + reverse函数

先reverse反转,再由redirect进行重定向

  1. 在主路由上添加namespace。并在每个urls.py中添加 app_name
  2. 在子路由的urlpatterns每一个路由上定义name
  3. reverse('namespace:name')

模板

注释

{# #}

向模板传参

在views.py内


def test(request):

    name = 'admin'

    day = datetime.now()

    return render(request, 'index.html', context={'name': name, 'day': day})

模板内


<body>

用户:{{ name }}

当前时间:{{ day }}

</body>

支持的类型

str, int, float, list(name.no), tuple, dict, set, object

循环


<h1>{{ question.question_text }}</h1>

<ul>

{% for choice in question.choice_set.all %}

    <li>{{ choice.choice_text }}</li>

{% endfor %}

</ul>

过滤器

  1. lower
  2. upper
  3. title
  4. capfirst
  5. length
  6. default
  7. slive(切片)
  8. cut(删去指定字符)
  9. floatformat
  10. random(随机获取列表中值)
  11. join(列表中拼接并展示)
  12. date(格式化日期'Y/m/d', 'Y-m-d')
  13. time(格式化时间'H:i:s'大H表示24H制)
  14. add(整数)
  15. first
  16. last
  17. safe(不对字符进行转移,比如 <h1>)
  18. ...

{{ msg|lower }}

{{ msg|default:'msg' }}

{{ msg|floatformat:'2' }}

标签

不再自动转义


{% autoescape on %}

    {{ body }}

{% endautoescape %}

循环


{% for o in some_list %}

    <li>{{ forloop.revcounter0 }}{{ o }}</li>

{% empty %}

    <li>空!</li>

{% endfor %}

双层for循环


{% forloop.parentloop.counter %}

if

{% if %} 标签会判断给定的变量,当变量为True时(比如存在、非空、非布尔值False),就会输出块内的内容:


{% if athlete_list %}

    Number of athletes: {{ athlete_list|length }}

{% elif athlete_in_locker_room_list %}

    Athletes should be out of the locker room soon!

{% else %}

    No athletes.

{% endif %}




{% if athlete_list and coach_list %}

    Both athletes and coaches are available.

{% endif %}


{% if not athlete_list %}

    There are no athletes.

{% endif %}


{% if athlete_list or coach_list %}

    There are some athletes or some coaches.

{% endif %}


{% if not athlete_list or coach_list %}

    There are no athletes or there are some coaches.

{% endif %}


{% if athlete_list and not coach_list %}

    There are some athletes and absolutely no coaches.

{% endif %}

url


action中:

{% url 'user:login' %}


<form action="" method="post">

    {% csrf_token %}

    ....

</form>



views.py中:

def login(request):

    if request.method == 'POST':

        # TODO

    else:

        # 在模板中显示msg

        render(request, 'login.html', {'msg': 'error!'})

    return render(request, 'login.html')

CSRF(Cross-site request forgery)跨站请求伪造,是一种常见的网络攻击手段

当表单数据通过POST方法,发送到后台服务器的时候,除了正常的表单数据外,还会携带一个CSRF令牌随机字符串,用于进行csrf验证。

详见:https://docs.djangoproject.com/zh-hans/3.0/ref/templates/builtins/

模板继承


模板页面:

{% extends common.html %}


{% block title %}


子页面:

{% block title %}

body

{% endblock %}

static标签

static标签用于链接保存在 STATIC_ROOT中的静态文件。例如:


{% load static %}

<img src="{% static "images/hi.jpg" %}" alt="Hi!" />

还可以使用变量:


{% load static %}

<link rel="stylesheet" href="{% static user_stylesheet %}" type="text/css" media="screen" />

还可以像下面这么使用:


{% load static %}

{% static "images/hi.jpg" as myphoto %}

<img src="{{ myphoto }}"></img>

自定义标签和过滤器

详见:https://www.liujiangblog.com/course/django/150

模型

一个模型(model)就是一个单独的、确定的数据的信息源,包含了数据的字段和操作方法。通常,每个模型映射为一张数据库中的表。

  • 每个模型在Django中的存在形式为一个Python类
  • 每个模型都是django.db.models.Model的子类
  • 模型的每个字段(属性)代表数据表的某一列
  • Django将自动为你生成数据库访问API

from django.db import models


class User(models.Model):

    username = models.CharField(max_length=30, unique=True, error_messages='必须唯一!')

模型的元数据Meta

模型的元数据,指的是“除了字段外的所有内容”,例如排序方式、数据库表名、人类可读的单数或者复数名等等。所有的这些都是非必须的,甚至元数据本身对模型也是非必须的。

步骤

1 . 定义模型类

比如:

class User(models.Model):

    username = models.CharField(max_length=255, null=False)

    password = models.CharField(max_length=255, null=False)

    role = models.CharField(max_length=255, default='管理员')


    class Meta:

        db_table = 'user'

2 . 在 INSTALLED_APPS添加APP

比如:'dashboard.apps.DashboardConfig',

迁移和同步


# 同步

python manage.py makemigrations

# 在migrations文件夹产生一个文件

python manage.py migrate

执行后,数据库会自动新建表。

数据库的增删改查

查询指定关键字



        if request.method == 'POST':

            keyword = request.POST.get("keyword", None)

            result = ZhihuQue.objects.filter(title__contains=keyword)[:2000]

            return render(request, 'dashboard/search.html',

                          {'result': result, 'keyword': keyword, 'cnt': result.count()})

        else:

            return render(request, 'dashboard/search.html')

随机查询n条记录


        zhihuques = ZhihuQue.objects.order_by('?')[:100]

        return render(request, 'dashboard/zhihuque.html', {'zhihuques': zhihuques})

查询所有


        users = User.objects.all()

        return render(request, 'dashboard/users.html', {'users': users})

用户注册


        # 注册

        user = User()

        user.username = username

        user.password = hashlib.sha256(password.encode('utf-8')).hexdigest()

        user.save()

用户登录


        username = request.POST.get('username')

        password = request.POST.get('password')

        user = User.objects.filter(username=username).first()

        if user:

            if user.password == hashlib.sha256(password.encode('utf-8')).hexdigest():

                # 登陆成功

                request.session['username'] = user.username

                request.session['usersum'] = User.objects.count()

                return render(request, 'dashboard/dashboard.html')

            else:

                hashkey = CaptchaStore.generate_key()

                image_url = captcha_image_url(hashkey)

                captcha = {'hashkey': hashkey, 'image_url': image_url}

                return render(request, 'dashboard/login.html', {'msg': '用户名或密码错误!', "captcha": captcha})

        else:

            hashkey = CaptchaStore.generate_key()

            image_url = captcha_image_url(hashkey)

            captcha = {'hashkey': hashkey, 'image_url': image_url}

            return render(request, 'dashboard/login.html', {'msg': '用户名或密码错误!', "captcha": captcha})

修改


        user.password = hashlib.sha256(pwd.encode('utf-8')).hexdigest()

        user.save()

        return render(request, 'dashboard/edit.html', {'msg': '修改成功!', 'user': user})

删除


        user = User.objects.get(username=username)

        user.delete()

        # return redirect(users)

        return render(request, 'dashboard/users.html', {'msg': '删除成功!'})

使用Redis缓存

配置

在settings.py中插入:


CACHES = {

    "default": {

        'BACKEND': 'django_redis.cache.RedisCache',

        "LOCATION": "redis://ip:6379",

        "OPTIONS": {

            "CLIENT_CLASS": "django_redis.client.DefaultClient",

            "PASSWORD": "foobared"

        }

    }

}

使用


if cache.get('zhihuusers') is None:

    print('from db')

    zhihuusers = ZhihuUser.object.all()

    cache.set('zhihuusers', zhihuusers)

else:

    print('from cache')

return render(request, 'zhihuuser.html', {'zhihuusers': cache.get('zhihuusers')})

测试部署

只能测试使用,生产环境部署需要NGINX和uWSGI

nohup python3 manage.py runserver 0:80 &

记录下学习Django做的Web

大致实现了用户注册登录,验证码,数据库数据的分页显示。


参考链接:




扫一扫在手机打开当前页