Django笔记:3.创建模型

建库建用户

1
2
3
4
5
6
7
8
-- 建库
create database djtest default charset=utf8;

-- 创建用户
CREATE USER 'djadmin'@'%' IDENTIFIED BY 'yourpasswd';

-- 为用户添加权限
GRANT ALL ON djtest.* TO 'djadmin'@'%';

项目配置

在项目的 settings.py 文件中找到 DATABASES 配置项,将其信息修改为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
DATABASES = {
# 'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
# 'NAME': BASE_DIR / 'db.sqlite3',
# }
'default' : {
'ENGINE': 'django.db.backends.mysql', # 数据库引擎
'NAME': 'djtest', # 数据库名称
'HOST': '127.0.0.1', # 数据库地址,本机 ip 地址 127.0.0.1
'PORT': 3316, # 端口
'USER': 'djadmin', # 数据库用户名
'PASSWORD': 'yourpasswd', # 数据库密码
}
}

接下来,告诉 Django 使用 pymysql 模块连接 mysql 数据库:

1
2
3
# 在与 settings.py 同级目录下的 __init__.py 中引入模块和进行配置
import pymysql
pymysql.install_as_MySQLdb()

如果没有pymysql模块,请使用pip安装

定义模型

创建app

Django中如果要使用模型,必须先创建一个app,使用下面命令创建一个TestModel的app

1
django-admin.py startapp TestModel

安装mysqlclient,报找不到mysql_config的错误请参考本文最后的常见错误及解决方法1

在命令行中运行python3 manage.py migrate 来创建表结构

执行成功后生成了这些表结构

1
2
# 让 Django 知道我们在我们的模型有一些变更
python3 manage.py makemigrations TestModel

1
2
# 创建表结构
python3 manage.py migrate TestModel

数据库上也可以看到已经生成了新的数据表:TestModel_test,表名的组成结构为:应用名_类名(如:TestModel_test)

添加数据

djtest/djtest/目录下新建testdb.py,内容如下

1
2
3
4
5
6
7
8
9
10
from django.http import HttpResponse

from TestModel.models import Test


# 数据库操作
def insdb(request):
test1 = Test(name='moonwhite')
test1.save()
return HttpResponse("<p>数据添加成功!</p>")

urls.py中添加如下内容:

1
path('insdb/', testdb.insdb),

浏览器访问localhost:8080/testdb,即可向数据库中添加一条记录

登陆数据库查看:

获取数据

Django提供了多种方式来获取数据库的内容,如下代码所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
def seldb(request):
# 通过objects这个模型管理器的all()获得所有数据行,相当于SQL中的SELECT * FROM
list = Test.objects.all()
str = ""
for var in list:
str += var.name + " "
return HttpResponse("<p>" + str +"</p>")

def seldb1(request):
# filter相当于SQL中的WHERE,可设置条件过滤结果
qs = Test.objects.filter(id=1)
str=""
for var in qs:
str += var.name + " "
return HttpResponse("<p>" + str +"</p>")

def seldb2(request):
# 获取单个对象
test2 = Test.objects.get(id=2)

return HttpResponse("<p>" + test2.name +"</p>")

def seldb3(request):
# 限制返回的数据 相当于 SQL 中的 OFFSET 0 LIMIT 2;
# Test.objects.order_by('name')[0:2]
# # 数据排序
# qs = Test.objects.order_by("id")

# 上面的方法可以连锁使用
qs = Test.objects.order_by("id")[0:4]

str = ""
for var in qs:
str += var.name + " <br>"


return HttpResponse("<p>" + str +"</p>")

更新数据

1
2
3
4
5
6
7
8
9
10
11
12
13

def upddb(request):
# 修改其中一个ID=2的记录的name字段,再save,相当于SQL: update table set name='newvalue' where id = 2
test1 = Test.objects.get(id = 2)
test1.name = 'moonwhite02'
test1.save()
# 另外一种方式
# Test.objects.filter(id=1).update(name='Google')

# 修改所有的列
# Test.objects.all().update(name='Google')
return HttpResponse('<p>' + "update success " + '</p>')

删除数据

1
2
3
4
5
6
7
8
9
10
11
12
def deldb(request):
# 删除id=1的数据
test1 = Test.objects.get(id=1)
test1.delete()

# 另外一种方式
# Test.objects.filter(id=1).delete()

# 删除所有数据
# Test.objects.all().delete()

return HttpResponse("<p>删除成功</p>")

常见错误及解决方法

1. pip install mysqlclient 报找不到mysql_config

pip install mysqlclient 后报错信息如下:

1
2
3
4
5
6
7
8
9
10
11
Collecting mysqlclient
Using cached mysqlclient-2.0.1.tar.gz (87 kB)
......
File "/private/var/folders/7p/r7xrt8r50l1cd6dh0dtz2n940000gp/T/pycharm-packaging/mysqlclient/setup_posix.py", line 65, in get_config
libs = mysql_config("libs")
File "/private/var/folders/7p/r7xrt8r50l1cd6dh0dtz2n940000gp/T/pycharm-packaging/mysqlclient/setup_posix.py", line 31, in mysql_config
raise OSError("{} not found".format(_mysql_config_path))
OSError: mysql_config not found
----------------------------------------
ERROR: Command errored out with exit status 1: python setup.py egg_info Check the logs for full command output.

解决方法:

1
2
3
4
brew install mysql-client
echo 'export PATH="/usr/local/opt/mysql-client/bin:$PATH"' >> ~/.bash_profile
export PATH="/usr/local/opt/mysql-client/bin:$PATH"
pip install mysqlclient

2

运行时可能报下面的错误:

1
2
3
4
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/django/db/backends/mysql/base.py", line 36, in <module>
raise ImproperlyConfigured('mysqlclient 1.4.0 or newer is required; you have %s.' % Database.__version__)
django.core.exceptions.ImproperlyConfigured: mysqlclient 1.4.0 or newer is required; you have 0.10.1.

解决方法是在__init__.py文件中添加下面三行:

1
2
3
import pymysql
pymysql.version_info = (1, 4, 13, "final", 0)
pymysql.install_as_MySQLdb()

常用MySQL操作及问题备忘

常见安装配置问题

安装

ubuntu安装命令:

1
sudo apt-get install mysql-server mysql-common

安装后使用/etc/mysql/debian.cnf中记录的用户(debian-sys-maint)和密码登陆

1
mysql -u debian-sys-maint -p

常见登陆问题

1. 不可以使用密码登陆的问题

1
2
3
4
5
6
7
8
--修改root用户属性
update mysql.user set authentication_string=PASSWORD('yourpassword'),plugin='mysql_native_password' where user='root';

-- (1)修改host允许远程登录
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'yourpassword' WITH GRANT OPTION;

-- (2)修改验证方式允许密码登录
update mysql.user set authentication_string=PASSWORD('yourpassword'),plugin='mysql_native_password' where user='root';

注意:!!!上面(1)和(2)都需要执行,而且需要按顺序执行

2. 连接报10060错误

使用服务商提供的服务器还需要在服务上控制台开通3306端口的入站规则(否则连接会报10060错误),比如腾讯云的在实例->安全组->入站规则里面,选择添加规则。

1
0.0.0.0/0    TCP:3306    允许

2. 连接报10061错误

解决方法:修改配置文件mysqld.cnf ,注释掉下面这行:
bind-address = 127.0.0.1

上面允许远程登陆、使用默认3306端口和解除绑定IP等配置是存在一定安全隐患和风险的,生产环境不建议这样使用。

常用SQL操作

1
2
3
4
5
6
7
8
9
10
-- 创建数据库
create database dbname default charset=utf8;

-- 创建用户并授权;
use mysql;
CREATE USER 'username'@'%' IDENTIFIED BY 'yourpassword';

-- 为用户添加权限
GRANT ALL ON pwnner.* TO 'pwnner'@'%';

表相关操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
-- 建表
DROP TABLE IF EXISTS `yx_user`;
CREATE TABLE `yx_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`create_time` int(11) NOT NULL DEFAULT 0,
`update_time` int(11) NOT NULL DEFAULT 0,
`delete_time` int(11) NULL DEFAULT NULL,
`time` int(11) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = MyISAM AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- 修改表结构
ALTER TABLE `yx_user` ADD COLUMN `exam_cnt_s` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '10道' COMMENT '考试模式单选题数量';

-- 建索引
CREATE INDEX yx_user_index ON yx_user (`cid`,`username`);

Django笔记:2.视图和URL配置

视图一般都写在app的views.py中,视图的第一个参数永远都是request(一个HttpRrequest对象),这个对象存储了请求过来的所有信息。返回结果必须是HttpResponseBase对象或者子类的对象。

添加views视图

工程目录下新建一个views.py,添加如下内容

1
2
3
4
from django.http import HttpResponse

def hello(request):
return HttpResponse("Hello Django!")

urls.py文件中添加如下内容:

1
2
3
4
5
6
7
8
9
10
11
12

from django.contrib import admin
from django.urls import path
from django.conf.urls import url

from . import views

urlpatterns = [
path('admin/', admin.site.urls),
url('^$', views.hello),
url('hello/', views.hello),
]

浏览器访问localhost:8080或者localhost:8080/hello查看效果:

项目目录

1
2
3
4
5
6
7
8
9
$ tree
.
|-- HelloWorld # 项目容器
| |-- __init__.py # 一个空文件,告诉 Python 该目录是一个 Python 包
| |-- settings.py # 项目的设置/配置文件
| |-- urls.py # url 配置
| |-- views.py # 视图文件
| |-- wsgi.py # 一个 ASGI 兼容的 Web 服务器的入口,以便运行你的项目。
`-- manage.py # 一个实用的命令行工具,可让你以各种方式与该 Django 项目进行交互

添加templates模版

在templates目录下新建一个about.html,添加如下内容:

1
{{ about }}

在views.py中添加如下代码:

1
2
3
4
5
6
from django.shortcuts import render

def about(request):
context = {}
context['about'] = 'Hello Django in the about page!'
return render(request, 'about.html', context)

urls.py中添加映射

1
2
3
4
urlpatterns = [
...
path('about/', views.about),
]

访问localhost:8000/about,可以看到模版中的内容被view的内容替换了。

如何在URL中添加参数

传统的Http的GET和POST方式了。

1
2
3
4
5
6
7
8
# views.py
def paramtest1(request):
text = "您输入的URL - id是:{}".format(request.GET.get('id'))
return HttpResponse(text)

#urls.py
path('paramtest1', views.paramtest1),

另外一种传递参数的方式为采用在url中使用变量的方式,使用<参数名>的方式可以传递参数,参数名称必须和视图中保持一致,可以传递多个参数。

1
2
3
4
5
6
7
# views.py
def paramtest(request,req_id='123'):
text = "您输入的id是:%s" % req_id
return HttpResponse(text)

# urls.py
path('paramtest/<req_id>', views.paramtest),

可以使用<type:param>的方式来指定参数的类型,比如<str:param><int:param>或者<uuid:param>等。支持的类型转换器如下:

  • str : 除了斜杠’/‘以外的所有的字符都是可以的;
  • int :一个或者多个阿拉伯数字;
  • path :所有的字符都可以;
  • uuid :只有满足uuid.uuid4()这个函数返回的字符串的格式;
  • slug :英文中的横杠或者英文字符或者阿拉伯数字或者下划线。

另一个例子:

1
2
3
4
5
urlpatterns = [
path('articles/<int:year>/', views.year_archive),
path('articles/<int:year>/<int:month>/', views.month_archive),
path('articles/<int:year>/<int:month>/<int:pk>/', views.article_detail),
]

URL模块化

当项目中存在多个应用时,URL映射的管理如果都放在主urls.py文件中的话会比较杂乱不好管理。可以采用模块化的方式分散到各个app自己的urls.py中来管理。方法如下:

主urls.py中添加include使app01相关的url映射都转到app01应用下的urls.py中。应该使用include函数包含子urls.py,并且这个urls.py的路径是相对于项目的路径。

1
2
3
4
5
6
7
8
from django.contrib import admin
from django.urls import path, include
from django.conf.urls import url

urlpatterns = [
path('app01/', include('app01.urls')),
]

然后在app01下的urls.py文件中,所有url匹配也要放在一个urlpatterns中,添加如下内容就可以了

1
2
3
4
5
6
7
8
9
from django.urls import path

from . import views

urlpatterns = [
path('', views.book),
path('list/', views.book_list),
path('add_book/', views.add_book),
]

url是会根据主urls.py和app中的urls.py进行拼接,因此注意不要多加斜杠。

URL命名

为什需要URL命名?

因为url是经常变化的,如果代码中写死,当url需要变更是会比较麻烦,可能会需要经常批量修改。给url取个名字,以后使用url的时候就使用它的名字进行反转,这样当url变更时不需要大量修改代码中写死的url内容。实现方式是在path函数中传递一个name参数就可以了。

1
2
3
4
5
6
7
8
9
10
11
# urls.py
urlpatterns = [
path('login/', views.login, name='login'),
]

# 使用的地方,比如原来使用
from django.shortcuts import redirect
redirect('/login/')
# 修改为
from django.shortcuts import redirect, reverse
redirect(reverse('login'))

使用应用命名空间,避免不同app之间url命名重复的问题

定义应用命名空间非常简单,只要在app的urls.py中定义一个叫做app_name的变量,来指定这个应用的命名空间,这样在做反转的时候就可以使用 应用命名空间:URL名称的方式进行反转。

1
2
3
4
5
6
7
8
9
10
# urls.py
app_name = 'front' # 定义app的命名空间为front

urlpatterns = [
path('login/', views.login, name='login'),
]

# 使用的地方
from django.shortcuts import redirect, reverse
redirect(reverse('front:login'))

使用实例命名空间

一个app可以创建多个实例,可以使用多个url映射同一个app,同一个app下有两个实例的情况,在做反转的时候,如果使用应用命名空间,就会发生混淆,比如:

1
2
3
path('cms/', include('cms.urls')),
path('cms1/', include('cms.urls')),
path('cms2/', include('cms.urls')),

如果访问:http://localhost:8000/cms1,会重定向到http://localhost:8000/cms/login 而不是http://localhost:8000/cms1/login

可以使用实例命名空间来解决这个问题,只需要在include函数中传递一个namespace变量即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# urls.py
path('cms/', include('cms.urls', namespace='cms')),
path('cms1/', include('cms.urls', namespace='cms1')),
path('cms2/', include('cms.urls', namespace='cms2')),

# views.py
from django.shortcuts import render, redirect, reverse
def index(request):
username = request.GET.get('username')
if username:
return HttpResponse("后台主页")
else:
# 取得实例命名空间
current_namespace = request.resolver_match.namespace
# 在做反转的时候,就可以根据实例命名空间来指定具体的url
login_url = reverse('{}:login'.format(current_namespace))
return redirect(login_url)

inlcude函数的用法

  1. include(module, namespace=None)
    • module : 子url的模块字符串
    • namespace : 实例命名空间,这个地方需要注意一点,如果指定实例命名空间,那么前提必须要先指定应用命名空间,也就是在子urls.py中添加app_name变量。
  2. include((pattern_list), app_namespace), namespace=None)
  3. include(pattern_list)

re_path 的用法

re_path的作用和path一样,不同的是re_path可以使用正则表达式,功能更强大。推荐使用原生字符串(字符串前面加r)。正则表达式中定义变量,需要使用圆括号括起来,如果参数有名字,需要使用(?P<参数名称>)的格式。

1
2
3
4
5
6
7
8
9
10
11
12
# urls.py
urlpatterns = [
re_path(r'^$', views.article),
re_path(r"^list/(?P<year>\d{4})/$", views.article_list),
]

# views.py
def article(request):
return HttpResponse("文章主页")

def article_list(request, year):
return HttpResponse("{} 年文章列表".format(year))

reverse 传递参数

试想实现一个功能,满足条件时redirect到一个需要传递参数的页面。
比如下面的功能:当输入http://localhost:8080/article/index时,若参数username为空则自动跳转到 http://localhost:8080/article/detail/1,而detail的URL是需要一个article_id作为参数的,这个时候就可以使用reverse函数的第二个参数kwargs来传递参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# urls.py
path('detail/<article_id>', views.article_detail, name='detail'),
path('login/', views.login, name='login'),
path('index/', views.index, name='index'),


# views.py
def index(request):
username = request.GET.get('username')
if username:
return HttpResponse("文章首页")
else:
# kwarg : keyword arguments.
detail_url = reverse('detail', kwargs={"article_id": 1}) # /detail/1
return redirect(detail_url)

Django笔记:1. 开发环境及常用命令

1.Pycharm搭建开发环境

pycharm 中新建工程,选择Existing interpreter。

如果没有Django环境,Pycharm会自动下载安装:

设置一下项目的interpreter,如果设置过了可省略

运行/调试配置,勾选run browser选项:

点击Pycharm右上角的运行按钮,或者使用快捷键Control + R 运行项目,正常就可以看到下面的厨师画面了:

如果出现了下面的错误,在settings.py文件中加上import os就可以了

2. 常用命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# 新建项目
django-admin startproject [项目名称]
django-admin startproject djproject

# 新建应用
django-admin.py startapp [应用名称]
# 或者
python manage.py startapp [应用名称]

# 运行项目
python manage.py runserver localhost:8000
# 这里如果需要使项目在本机意外可以访问的话,需要把localhost修改为0.0.0.0
# 同时在settings.py中设置ALLOWED_HOSTS添加本机IP。


# 让 Django 知道我们的模型有一些变更,自动生成迁移脚本:
# 该 makemigrations 命令查找所有可用的models,为任意一个在数据库中不存在对应数据表的model创建 migrations 脚本文件。
# migrate 命令则运行这些 migrations 自动创建数据库表。
python manage.py makemigrations TestModel
python manage.py makemigrations
常用选项:
app_label : 后面可以跟一个或多个app,那么就只会针对这几个app生成迁移脚本。
-name:指定迁移脚本的名字
-empty:生成一个空的迁移脚本。

# 执行迁移脚本,创建表结构
python manage.py migrate
# 或者后面添加app_label,只执行指定app的迁移脚本。
python manage.py migrate TestModel

python manage.mp migrate app_label migrationname # 将某个app下指定名字的migration文件映射到数据库中。

--fake : 可以讲指定的迁移脚本名字添加到数据库中。但是并不会真正的执行迁移脚本。
--fake-initial : 将第一次生成的迁移文件版本号记录在数据库中,但是并不会真正的执行迁移脚本。

# 使用已有数据库表生成ORM模型
python manage.py inspectdb > models.py

# 查看某个app下的迁移文件。
python manage.py showmigrations

vscode 常用快捷键

多列选择和编辑

方式1:Option➕鼠标左键依次点选

方式2:OptionShift + 鼠标滚动(tuchbar三指移动)来进行多列选择

方式3:
选中一个字符后按Command + Shift + L 组合按键可以全选选中字符,再按一下左或者右方向键,就可以在选中字符的左侧或者右侧插入多列光标了。

Command + Shift + -> 组合按键可以选中至行末尾。不带Shift,只使用Command➕左右箭头是移动光标至行首或行尾。

WordPress笔记

安装

可以在MAMP的Hosts设定中添加WordPress支持,点击Extras下面的➕按钮,添加额外功能,选择WordPress后点击Continue:

然后就自动下载了Wordpress的代码在本地工程目录中。

效果

可以在phpstorm中直接使用浏览器预览效果:

laravel笔记

安装

使用composer下载laravel,composer的安装请参考这里

1
composer create-project laravel/laravel laravel.test "5.5.*"

运行

下面命令会在本地8000端口开启一个laravel服务。

1
php artisan serve

PHP 笔记

文件操作

  • 读取文件内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 方法1:直接readfile
echo readfile("test.txt");

# 方法2: fopen -> fread -> fclose
$myfile = fopen("test.txt","r") or die("Unable to open file.");
echo fread($myfile, filesize('test.txt'));
fclose($myfile);

# 方法3: fopen后循环fgets每次读取一行,也可以fgetc每次读取单字符
$myfile = fopen("test.txt","r") or die("Unable to open file.");
while ( !feof($myfile) ){
echo fgets($myfile) . "<br>";
}
fclose($myfile);

  • 写入文件内容
1
2
3
4
5
$myfile = fwrite("test.txt","w") or die("Unable to open file.");
$txt = "Write file test\n";
fwrite($myfile, $txt);
fwrite($myfile, "Write by php\n");
fclose($myfile);
1
2
3
4
5
6
7
8
9
10
11
12
13
# 设置cookie
setcookie("user", "Mooonwhite", time()+3600);

# 获取cookie
if (isset($_COOKIE["user"])) {
echo "Welcome ".$_COOKIE["user"]. "! <br/>";
}
else {
echo "Welcome guest!<br/>";
}

# 删除cookie(设置超市时间为一小时之前)。
setcookie("user", "", time()-3600);

时间日期

  • 获取时间和日期
1
2
3
4
5
6
7
8
# 获取格式化日期时间字符串
$dt = date("Y-m-d h:i:sa");
echo $dt;

# 获取19700101到现在的秒数(时间戳)。
$tm = time();
echo $tm;

Composer安装

1. Composer 安装

可以复制如下脚本保存并本地执行,用来下载composer.phar文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/bin/sh

EXPECTED_CHECKSUM="$(wget -q -O - https://composer.github.io/installer.sig)"
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
ACTUAL_CHECKSUM="$(php -r "echo hash_file('sha384', 'composer-setup.php');")"

if [ "$EXPECTED_CHECKSUM" != "$ACTUAL_CHECKSUM" ]
then
>&2 echo 'ERROR: Invalid installer checksum'
rm composer-setup.php
exit 1
fi

php composer-setup.php --quiet
RESULT=$?
rm composer-setup.php
exit $RESULT

执行

1
2
chmod a+x install.sh
./install.sh

执行之后会看到本地目录下载好了composer.phar,
然后执行

1
mv composer.phar /usr/local/bin/composer

使得composer可以在任意目录使用,这样就安装完成了。

敲入composer命令,或者composer -V来确认composer是否安装成功。

2. PHPStorm配置Composer

Preference -> Languages & Frameworks -> PHP -> Composer