1-django使用
# Django
# 常用命令快捷复制
python manage.py makemigrations
python manage.py migrate
python manage.py runserver 0.0.0.0:38090
find . -name 00*.py
find . -name 00*.py | xargs rm
python manage.py createsuperuser
django-admin startapp product
python manage.py makemigrations & python manage.py migrate --run-syncdb
2
3
4
5
6
7
8
9
10
11
# 参考网址链接
django官方文档,最全 https://docs.djangoproject.com/en/2.2/
刘江的django的中文系列教程,非常好,比较基础,admin自定义的部分比较少:https://www.liujiangblog.com/course/django/157
django rest framework 的一个中文博客系列教程,看起来不错,也不知道这个rest framework到底有啥用 https://www.cnblogs.com/yuzhenjie/p/10343016.html
另一个高级的教程,看起来更好,有很多自定义后台的部分: https://blog.csdn.net/weixin_42134789/article/details/83686703
自定义标签和修改listhttps://blog.csdn.net/u013378306/article/details/79030385
代理model实现一个model多个admin:https://www.it1352.com/634205.html
官方的QuickSrart教程
- 英文教程: https://www.django-rest-framework.org/tutorial/quickstart/
- 中文翻译: https://www.django.cn/course/show-20.html 翻译的不怎么样,看英文的更好
# Django创建项目
参考其GitHub主页,https://github.com/encode/django-rest-framework 创建了一个简单示例。
# 创建proj和app
django-admin startproject server . # Note the trailing '.' 在根目录创建名为server的project,会创建server文件夹
django-admin startapp product #在根目录下创建名为product的app,会创建product文件夹。也可以剪切到其他地方,比如创建apps文件夹,放进去
# 在上面创建的server/settings.py中找到INSTALLED_APPS字段,加入我们创建的app,
INSTALLED_APPS = [
'apps.product',
...
]
# 配置数据库连接 在server/settings.py中。默认是sqllite,如果要修改为mysql,则修改为:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'db_name', #你的数据库名称
'USER': 'root', #你的数据库用户名
'PASSWORD': 'abcd1234', #你的数据库密码
'HOST': '127.0.0.1', #你的数据库主机,留空默认为localhost
'PORT': '3306', #你的数据库端口
}
# 'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
# 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
# }
}
# 数据库创建。若执行错误 Did you install mysqlclient? 则安装: pip install mysqlclient
python manage.py makemigrations # 创建migrations文件,会在各个app对应的文件夹下创建migrations文件夹,并在里面生成一些0001_***.py文件
python manage.py migrate #执行migrate,会执行sql语句
# 如果要查看某个app的某个迁移版本对应的sql语句:
python manage.py sqlmigrate product 0003
# 如果migrations执行失败时,可在数据库中直接删除该表,然后执行下面的语句,它会直接重新生成表。
python manage.py migrate --run-syncdb
# 创建superuser 和run debug server
python manage.py createsuperuser
python manage.py runserver 8090
# 如果run时端口号被占用,会提示,Error: [WinError 10013] 以一种访问权限不允许的方式... 那就换个端口号试试
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
41
42
43
44
45
46
平时更新数据库可用这个:
python manage.py makemigrations & python manage.py migrate --run-syncdb
# 将默认sqllite更换成mysql数据库
https://blog.csdn.net/qq_37969201/article/details/87161794
pip install mysqlclient
# 不要搞这个 import pymysql pymysql.install_as_MySQLdb()
# 在settings.py中找到DATABASE
DATABASES = { 'default': {
'ENGINE': 'django.db.backends.mysql', #数据库引擎
'NAME': 'dj_experiment_db', #数据库名
'USER': 'root', #账户名
'PASSWORD': 'password', #密码
'HOST': 'localhost', #主机
'PORT': '3306', #端口
}
}
# 然后在settings.py文件中设置TIME_ZONE为自己的时区
TIME_ZONE = 'Asia/Shanghai'
# 最后执行数据库迁移命令
python manage.py makemigrations
python manage.py migrate
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# simpleui 使用方法-更换后台主题
# django-simpleui 简介
django-simpleui是对django-admin的美化版本。
django-admin是django自带的admin后台网站管理模块,可以将用户创建的数据库model自动转换成网页,对数据进行编辑管理,非常方便,节约大量的开发时间。
GitHub地址: https://github.com/newpanjing/simpleui 官网: https://simpleui.88cto.com/
vue-element-admin的GitHub地址:https://github.com/PanJiaChen/vue-element-admin
# 将simple-ui移植到自己的工程文件夹中
simple-ui默认是通过pip安装的,官方的介绍中,对其进行修改时,要在pip安装目录进行修改,不方便。这种方法参考simpleui文档:
https://simpleui.88cto.com/docs/simpleui/QUICK.html#开发调试
如果想在simpleui的基础上进行一些修改,可以参考以下步骤
安装simpleui到项目中
找到simpleui的目录,然后删除
克隆simpleui源码到本地
Linux、Unix、macOS环境下用软连接的方式,把项目依赖包中的simpleui目录指定到源码的simpleui目录
2
3
4
5
6
GitHub上的一个项目将其移植到了自己的工程中: https://github.com/Ryuchen/Bistu 参考该项目,用下面方法实现了将其移植到自己的工程中。
创建一个django工程,或者django-rest-framework工程 (首先需要对django有基本的了解。)
定义自己的templates模板,参考: https://www.jianshu.com/p/a61da9ff9fd6 在自己项目的根目录下创建templates文件夹, 并修改django的setting.py配置文件
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')], # 只用改这一行
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
pip安装simple-ui,然后打开其安装目录, 一般是位于python的安装目录下,
\Lib\site-packages\simpleui
将simpleui安装目录下的templates文件夹下面的文件拷贝到自己的templates文件夹下面,里面只有admin和registration两个文件夹
将simple-ui安装目录下的templatetags文件夹拷贝到自己的某个已安装的app文件夹下面。已安装的app就是settings的install_apps中注册过的。可以是任意一个app,比如创建一个通用的app叫comapp:
jango-admin startapp comapp
,然后将templatetags拷贝到comapp文件夹下。不管放在哪个app下面,它都会生效。将simpleui安装目录下的static文件夹拷贝到项目根目录下,并在server/setting.py中添加:
STATICFILES_DIRS = [ os.path.join(BASE_DIR, "static"), ] STATIC_ROOT = os.path.join(BASE_DIR, "/static/")
1
2
3
4在项目根目录执行
python manage.py runserver 8090
运行网站,查看是否是simpleui的样式。然后修改template/admin/index.html
,查看修改是否生效。在server/settings中自定义simple-ui的一些设置,具体用法参考simple-ui官方文档
# SimpleUI settings # https://github.com/newpanjing/simpleui/blob/master/QUICK.md SIMPLEUI_STATIC_OFFLINE = True # SIMPLEUI_FAVICON_ICON = "/static/bistu/img/logo.png" SIMPLEUI_LOGIN_LOGO = "/static/img/loginlogo.png" SIMPLEUI_INDEX_LOGO = "/static/img/logo.png" SIMPLEUI_LOGO = "/static/img/logo.png" SIMPLEUI_HOME_TITLE = '后台管理' SIMPLEUI_HOME_ICON = 'fas fa-tachometer-alt' SIMPLEUI_HOME_QUICK = True SIMPLEUI_HOME_INFO = False SIMPLEUI_HOME_ACTION = True SIMPLEUI_HOME_PAGE = 'comapp/home/' SIMPLEUI_HOME_TITLE = '首页' SIMPLEUI_HOME_ICON = 'fa fa-home' SIMPLEUI_CONFIG = { 'system_keep': False, 'menus': [ { 'app': 'news', 'name': '文章管理', 'icon': 'fa fa-book', 'models': [ { 'name': '文章管理', 'icon': 'fa fa-cube', 'url': 'product/product/' }, { 'name': '写文章', 'icon': 'fa fa-bell', 'url': 'product/riskcontrol/' } ] }, { 'app': 'auth', 'name': '账户管理', 'icon': 'fas fa-user-shield', 'models': [ { 'name': '用户', 'icon': 'fa fa-user', 'url': 'comapp/userprofile/' }, { 'name': '用户组', 'icon': 'fa fa-users-cog', 'url': 'auth/group/' } ] }, ] }
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# 其他用法
# 修改后台标题
https://www.cnblogs.com/yoyoketang/p/10345623.html (opens new window)
在server/urls.py中添加:
admin.site.site_header = 'xx 项目管理系统'
admin.site.site_title = '登录系统后台'
admin.site.index_title = '后台管理'
2
3
# 设置语言
在server/settings.py中修改:
# LANGUAGE_CODE = 'en-us'
LANGUAGE_CODE = 'zh-Hans'
TIME_ZONE = 'Asia/Shanghai'
2
3
# admin 列表字段显示
admin列表显示只显示名称,其他列不显示 https://blog.csdn.net/kong2030/article/details/82319936 解决方法: 在admin.py中添加
list_display = ('id', 'underwriter', 'shortname', 'telephone')
编辑字段显示:
fields = ['prod_no', 'freq_type', 'repo_date', 'repo_file']
各种属性: https://www.cnblogs.com/LLBFWH/articles/10427754.html
(editable, 表示Admin中是否可以编辑)
# 自定义user和登录验证
自定义user,这篇文章非常棒: https://www.jianshu.com/p/bf7f15cc1130
自定义登录验证: https://blog.csdn.net/weixin_30735745/article/details/95486489
# 数据库model属性和添加约束、外键等
https://blog.csdn.net/Great_Zhou/article/details/82560343
class Product(models.Model):
def __str__(self):
return self.prod_name
prod_name = models.CharField(max_length=200, unique=True)
founded_date = models.DateField() #2018/1/24
manager = models.CharField(max_length=200)
class HistValue(models.Model):
def __str__(self):
return self.prod_no
# 指定外键名db_column为 prod_no ,此时在本表中创建的列名就是db_column指定的pord_no,而不是前面的变量名
prod_no = models.ForeignKey(Product, on_delete=models.DO_NOTHING, db_column='prod_no')
hist_date = models.DateField('日期', null=False)
unit_value = models.FloatField('价格', null=False) # 4位小数
# 指定联合约束,django中不支持联合主键,只能创建联合约束
class Meta:
constraints = [models.UniqueConstraint(fields=['hist_date', 'prod_no'], name='unique_product_histdate')]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
定义模型的__str__()
,可以使其作为外键被编辑时显示自己定义的名称。
# makemigrations和migrate
# 修改字段名
这是某次修改主键后,执行makemigrations时,它提示是否rename主键,选择是,生成的迁移文件。可参考此文件自己创建migarion文件来修改字段名
# Generated by Django 2.2.5 on 2020-02-19 07:40
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('product', '0008_product_invest_manager'),
]
operations = [
migrations.AlterField(
model_name='product',
name='record_no',
field=models.CharField(max_length=200, unique=True, verbose_name='代码'),
),
]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 设置默认值
model中增加一个联合约束后执行makemigrations,提示没有默认值,让选两个选项: 1. 设置一个默认值, 2 中止执行,在model.py中设置默认值。此时生成的migraion文件如下:
class Migration(migrations.Migration):
dependencies = [
('product', '0011_auto_20200221_1058'),
('cust', '0002_auto_20200221_1203'),
]
operations = [
migrations.AddField(
model_name='custinfo',
name='prod_no',
field=models.ForeignKey(db_column='prod_no', default=1, on_delete=django.db.models.deletion.DO_NOTHING, to='product.Product'),
preserve_default=False,
),
migrations.AddConstraint(
model_name='custinfo',
constraint=models.UniqueConstraint(fields=('cust_id', 'prod_no'), name='unique_product_cust'),
),
]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 执行makemigration不生效的原因:
http://www.chenxm.cc/article/187.html
自己手动添加的app,app文件夹下面没有migration文件夹,以及migration下的__inin__.py
,加上就好了。
# post添加csrf权限验证
在post发送的header或者params或者data中添加下面的字段,{{ csrf_token }
会被django自动渲染。 参考:https://www.cnblogs.com/wangwei916797941/p/9283776.html
param_data.append('csrfmiddlewaretoken', '{{ csrf_token }}')
# post上传文件
html
<span class="file-upload" style="float: right;">
<div class="file-upload-text">上传文件</div>
<input class="file-upload-input" name="file" type="file" @change="upload"/>
</span>
2
3
4
js,向vue的methods中添加上传函数
upload(e) {
let file_obj = e.target.files[0];
let param_data = new FormData(); //创建form对象
param_data.append('file_obj',file_obj)//通过append向form对象添加数据
console.log(param_data.get('file_obj')) //FormData私有类对象,访问不到,可以通过get判断值是否传进去
param_data.append('csrfmiddlewaretoken', '{{ csrf_token }}') //django身份认证参数
console.log(param_data.get('csrfmiddlewaretoken'), this.csrf_token)
// 上传选择的文件
axios({
method: 'post',
url: "{% url '/do/something' %}",
data: param_data,
headers: {'Content-Type':'multipart/form-data'}
})
.then(res => {
console.log(res)
if(res.data.mycode)
this.$notify({
title: '成功',
message: res.data.mymsg,
type: 'success',
position: 'top-left'
});
else
this.$notify({
title: '失败',
message: res.data.mymsg,
type: 'error',
position: 'top-left'
});
})
.catch(error => {
console.log('get err: ', error)
this.$notify({
title: '导入失败,内部错误',
message: '',
type: 'error',
position: 'top-left'
});
});
}
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
41
42
43
css美化上传按钮
<style type="text/css">
.file-upload {
width: 120px;
height: 30px;
position: relative;
overflow: hidden;
border: 1px solid #317EF3 ;
display: inline-block;
border-radius: 4px;
font-size: 16px;
color: #317EF3;
text-align: center;
line-height: 26px;
/* float: right; */
margin: 10px 10px auto auto;
}
.file-upload-input {
background-color: transparent;
position: absolute;
width: 999px;
height: 999px;
top: -10px;
right: -10px;
cursor: pointer;
}
.file-upload-text {
padding-top: 2px;
}
</style>
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
# 后台管理文件
- 下载文件时中文文件名下载不显示名称, 使用urlquote对文件名处理即可。
https://www.jianshu.com/p/aa4c54f5e25d
from django.utils.http import urlquote
def download_file(request,file_name):
full_file_name = 'file_src/'+ file_name
file=open(full_file_name,'rb')
response =FileResponse(file)
response['Content-Type']='application/octet-stream'
response['Content-Disposition']='attachment;filename="{}"'.format(urlquote(pure_filename))
return response
2
3
4
5
6
7
8
9
- 修改FileField在文件django-admin中自动生成的下载链接: https://www.cnblogs.com/zhaozhenguo666/p/9117709.html
# markdown
https://blog.csdn.net/duke10/article/details/81033686
# debug时使用static文件
https://docs.djangoproject.com/en/2.2/howto/static-files/
# urls.py
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
path('admin/product/', include('apps.product.urls')),
...
] + static('/static/', document_root='/static/')
2
3
4
5
6
7
8
9
在urls.py中的urlpatterns后面加上一句,这样debug时,通过runserver启动后
python manage.py runserver 127.0.0.1:8090
也可以直接访问静态资源:127.0.0.1:8090/static/test.html
# url跳转
https://docs.djangoproject.com/en/2.2/ref/class-based-views/base/
urls.py
from django.urls import path
from django.views.generic.base import RedirectView
urlpatterns = [
path('counter/<int:pk>/', ArticleCounterRedirectView.as_view(), name='article-counter'),
path('details/<int:pk>/', ArticleDetail.as_view(), name='article-detail'),
path('go-to-django/', RedirectView.as_view(url='https://djangoproject.com'), name='go-to-django'),
]
2
3
4
5
6
7
8
# render pdf
- one way: by pdfkit.from_string(content)
def html_to_pdf(content):
options = {
'page-size': 'A4',
}
# pdfkit.from_string(content, 'out_1.pdf', options=options) #generate file
file_bytes = pdfkit.from_string(content, False, options=options)
return file_bytes
def get_report_html(request):
if not request.user.has_perm('customer.view_customertoproduct'):
return HttpResponse('forbidden', status=403)
step = int(get_param(request, 'step'))
prod_no = get_param(request, 'prod_no')
customer_id = get_param(request, 'customer_id')
return_type = get_param(request, 'type')
upload_system_path = os.path.join(settings.BASE_DIR, 'upload', 'customer_material')
cp:CustomerToProduct = CustomerToProduct.objects.get(customer_id=customer_id, prod_no=prod_no)
prod_name = str(cp.prod_no.prod_name)
# variables can be used in report.html like {{prod_name}}, {{cp.next_step}}
t = TemplateResponse(request, f'report.html', locals())
if return_type=='html':
return t
# default return pdf preview
t.render()
pdf = html_to_pdf(t.content.decode('utf-8'))
response = HttpResponse(pdf)
response['Content-Type'] = "application/pdf"
if return_type=='download':
response['Content-Disposition'] = 'attachment;filename="{}"'.format(urlquote(f'步骤{step+1}.pdf'))
return response
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
- another way: by pdfkit.from_url(url)
访问html连接,生成pdf,返回:
def a_view(request):
pdf_bytes = pdfkit.from_url(html_url, False)
response = HttpResponse(pdf_bytes)
response['Content-Type'] = "application/pdf"
if 'download':
response['Content-Disposition'] = 'attachment;filename="{}"'.format(urlquote('文件A.pdf'))
return response
2
3
4
5
6
7
# check_perm
# contrib\admin\options.py
@csrf_protect_m
def changelist_view(self, request, extra_context=None):
"""
The 'change list' admin view for this model.
"""
from django.contrib.admin.views.main import ERROR_FLAG
opts = self.model._meta
app_label = opts.app_label
if not self.has_view_or_change_permission(request):
raise PermissionDenied
2
3
4
5
6
7
8
9
10
11
12
# 扩展阅读
Django中的JWT(Json Web Token认证机制) (opens new window)
# 设置server/settings.py
按照下面的设置,少踩坑。
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.2/howto/static-files/
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "static"),
]
STATIC_ROOT = os.path.join(BASE_DIR, "/static/")
STATIC_URL = '/static/'
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
TIME_FORMAT = '%Y-%m-%d %H:%M:%S'
DATE_TIME_FORMAT = '%Y-%m-%d'
# Internationalization
# https://docs.djangoproject.com/en/2.2/topics/i18n/
# LANGUAGE_CODE = 'en-us'
# TIME_ZONE = 'UTC'
LANGUAGE_CODE = 'zh-Hans'
TIME_ZONE = 'Asia/Shanghai'
USE_I18N = True
USE_L10N = True
# USE_TZ = True
USE_TZ = False
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