Django学习笔记02 构建后端

构建后端

之前启动服务的时候会看到

F:\company\study\autotest\autotest>python manage.py runserver
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).

You have 18 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.
March 19, 2022 - 10:20:31
Django version 4.0.3, using settings 'autotest.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.

也就是告诉你有些migration没有安装,本身Django就自带一套组合权,能让你快速构造后端与后端管理页

F:\company\study\autotest\autotest>python manage.py makemigrations
No changes detected
F:\company\study\autotest\autotest>python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying auth.0012_alter_user_first_name_max_length... OK
  Applying sessions.0001_initial... OK

创建admin超级用户

F:\company\study\autotest\autotest>python manage.py createsuperuser
Username (leave blank to use 'Admin'):
Email address: [email protected]
Password:
Password (again):
The password is too similar to the username.
Bypass password validation and create user anyway? [y/N]: y
Superuser created successfully.

打开后台首页

  1. 启动服务器
  2. 打开后台首页 http://127.0.0.1:8000/admin
  3. 尝试登陆验证超管账号密码是否正常。

汉化后台

  1. 修改autotest/setttings.py
# LANGUAGE_CODE = 'en-us'
LANGUAGE_CODE = 'zh-Hans'

# TIME_ZONE = 'UTC'
TIME_ZONE = 'Asia/Shanghai'
  1. 重启服务

创建应用

  1. 创建应用
PS F:\company\study\autotest\autotest> python .\manage.py startapp apitest
  1. 修改settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'apitest',
]
  1. 修改views.py
from django.http import HttpResponse
from django.shortcuts import render

# Create your views here.

def test(request):
    return HttpResponse("hello test")
  1. 修改urls.py
from apitest import views #apittest 的 views要对应
from django.contrib import admin
from django.urls import path

urlpatterns = [
    path('admin/', admin.site.urls),
    path('test/', views.test), # 加入关联路径及函数
]

使用Mysql

  1. 安装pymysql
# 安装
# F:\company\study\autotest\autotest>pip install pymysql
F:\company\study\autotest\autotest>pip install -U pymysql
Requirement already satisfied: pymysql in e:\users\gorgage\appdata\local\programs\python\python39\lib\site-packages (0.7.11)
Collecting pymysql
  Using cached PyMySQL-1.0.2-py3-none-any.whl (43 kB)
Installing collected packages: pymysql
  Attempting uninstall: pymysql
    Found existing installation: PyMySQL 0.7.11
    Uninstalling PyMySQL-0.7.11:
      Successfully uninstalled PyMySQL-0.7.11
Successfully installed pymysql-1.0.2
  1. 修改/init.py
import pymysql

pymysql.install_as_MySQLdb()
  1. 修改/settings.py
    默认是sqllite改为mysql
# Database
# https://docs.djangoproject.com/en/4.0/ref/settings/#databases

# DATABASES = {
#     'default': {
#         'ENGINE': 'django.db.backends.sqlite3',
#         'NAME': BASE_DIR / 'db.sqlite3',
#     }
# }

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'autotest',
        'USER': 'autotest',
        'PASSWORD': 'Gorgage753951',
        'HOST': '192.168.0.30',
        'PORT': '51345',
    }
}
  1. 重新初始化数据库与创建超级用户
F:\company\study\autotest\autotest>python manage.py makemigrations
No changes detected

F:\company\study\autotest\autotest>python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying auth.0012_alter_user_first_name_max_length... OK
  Applying sessions.0001_initial... OK

F:\company\study\autotest\autotest>python manage.py createsuperuser
用户名 (leave blank to use 'admin'):
电子邮件地址: [email protected]
Password:
Password (again):
密码跟 用户名 太相似了。
Bypass password validation and create user anyway? [y/N]: y
Superuser created successfully.
  1. 重启服务,尝试登陆管理后台

升级后的pymysql,好像不需要像2.0和3.0那样,注释掉mysqlclient
E:\Users\gorgage\AppData\Local\Programs\Python\Python39\Lib\site-packages\django\db\backends\mysql\base.py

django.core.exceptions.ImproperlyConfigured: mysqlclient 1.4.0 or newer is required; you have 0.7.11.None.

F:\company\study\autotest\autotest>pip install -U pymysql
Requirement already satisfied: pymysql in e:\users\gorgage\appdata\local\programs\python\python39\lib\site-packages (0.7.11)
Collecting pymysql
  Using cached PyMySQL-1.0.2-py3-none-any.whl (43 kB)
Installing collected packages: pymysql
  Attempting uninstall: pymysql
    Found existing installation: PyMySQL 0.7.11
    Uninstalling PyMySQL-0.7.11:
      Successfully uninstalled PyMySQL-0.7.11
Successfully installed pymysql-1.0.2

从上面的终端可以看出,我原来是pymysql-0.7.11版本,这个时候是会报错的,想不报错就要注释掉下面的语句,但我更新到pymysql-1.0.2后没报错就不用注释

if version < (1, 4, 0):
    raise ImproperlyConfigured(
        "mysqlclient 1.4.0 or newer is required; you have %s." % Database.__version__
    )

建表

class Meta:
db_table = '重置表名'

admin后台配置

如果需要在后台显示出来,就需要对每个模块的admin.py进行注册

  • list_display 显示字段
  • list_per_page 每页的记录数,默认100条
  • ordering 排序 -为倒序
  • list_editable 设置默认可编译的字段,条件是显示的
  • list_filter 过滤查询
  • search_fields 查询字段
  • date_hierarchy 时间聚合
  • extra
  • admin.site.site_header 后台名称
  • admin.site.site_title 设置title名称
  • admin.site.register 注册模块

django.contrib.admin.ModleAdmin 的选项

以下内容转载*
官网相关说明*

  1. actions
    给列表页面上提供额外操作功能
    定义一个模型DataBaseA,其中包含一个字符字段A,A有两用取值 y与n
    为amdin页面添加一个批量操作 “将选择的内容改为y”
# models.py
class DataBaseA(models.Model):
    A = models.CharField(max_length=50, choices=[('y', 'yes'), ('n', 'no')])

    def __str__(self):
        return self.A

# admin.py
from django.contrib import admin
from .models import DataBaseA

def make_data(modeladmin, request, queryset):
    queryset.update(A='y')

make_data.short_description = "将选择的内容改为y"

class DataBaseAdminA(admin.ModelAdmin):
    actions = [make_data]

admin.site.register(DataBaseA, DataBaseAdminA)

运行后可以看到自定义的批量操作


image
  1. actions_on_top 和 actions_on_bottom
    动作模块置顶还是置底,默认值
actions_on_top = True
actions_on_bottom = False
# 如果只设置actions_on_bottom = True,那么操作栏将在列表上方和下方同时显示;同样,你也可以是它在上方或下方都不显示。
  1. actions_selection_counter
  • 控制选择计数器是否显示在操作下拉列表旁边

默认情况下,操作了旁边显示列表总数与已选择的数目,如果将此属性设置为False 将不显示

image

  1. date_hierarchy
    设置为模型中的DateField或DateTimeField字段基于日期的分层筛选导航
    为DataBaseA 添加一个日期字段 B,设置此属性的值为字段B,将为当前模型建立一个基于此日期字段的筛选导航
list_display = ('A', 'B')
date_hierarchy = 'B'
image.png

5.empty_value_display
设置记录字段为空(None,空字符串等)的默认显示值
添加一个字符字段C并设置其允许为空,如果记录该字段内容为空是设置该属性进行显示一个其他值,默认为-

empty_value_display = "空"
image.png
  1. exclude
    表单中不展示的字段
exclude = ('B',)

此属性设置后在添加数据页面不显示其设置的字段,不显示的字段将被编辑为空。


image
image
  1. fields
    在“添加”和“编辑”页面上的表单中进行简单的布局更改
    fields 决定对表进行编辑时展示哪些字段
fields = ('A', 'C')
image.png

同时也可设置字段处于同一行

fields = (('A', 'B'), 'C')
image.png
  1. fieldsets
    控制“添加”和“编辑”页面的布局,fieldsets是一个二元组列表,其中每个二元组代表管理表单页面上的
    , 这两个元组的格式为(name,field_options),其中name是代表字段集标题的字符串,field_options是有关字段集的信息词典,包括要在其中显示的字段的列表
    field_options字典可以具有以下键
fields 要在此字段集中显示的字段名称的元组。此键是必需的
classes 包含要应用于该字段集的额外CSS类的列表或元组
description 一串可选的额外文本,将显示在每个字段集顶部,字段集标题下;默认样式collapse和wide。collapse样式的字段集将折叠,并替换为一个小的“单击以展开”链接。wide样式的字段集将获得额外的水平空间。
fieldsets = (('内容1', {'fields': ('A', 'B'),
                      'classes': ('wide',)}),
             ('内容2', {'fields': ('C',),
                      'classes': ('collapse',),
                      'description': '这是额外的描述信息'}))

image.png

9.filter_horizontal 和 filter_vertical
水平(垂直)显示过滤器, 用于多对多模型(ManyToMany)
为模型DataBaseA添加一个多对对字段D,关联到新创建模型DataBaseB,DataBaseB内含有有个字符字段X;

# models.py
from django.db import models

class DataBaseA(models.Model):
    A = models.CharField(max_length=50, choices=[('y', 'yes'), ('n', 'no')])
    B = models.DateField(blank=True, null=True)
    C = models.CharField(max_length=50, blank=True, null=True)
    D = models.ManyToManyField('DataBaseB', blank=True)
    
    def __str__(self):
        return self.A

class DataBaseB(models.Model):
    X = models.CharField(max_length=50)

    def __str__(self):
        return self.X

默认视图


image

设置此属性为多对多字段,为该字段添加一个水平过滤器

filter_horizontal = ('D',)
image

当设置 filter_vertical = ('D',) 后显示为垂直过滤器

image

  1. form
  • 用于定制用户请求时候表单验证

给字段C增加一个验证,让其只能接收四位数字

from django.contrib import admin
from .models import DataBaseA
from django import forms

def validate(value): # 验证数据
    try:
        v = int(value)
    except:
        raise forms.ValidationError(u'输入四位数字')
    if len(value) != 4:
        raise forms.ValidationError(u'输入四位数字')

class MyForm(forms.ModelForm):
    code = forms.CharField(validators=[validate], widget=forms.TextInput(attrs={'placeholder': u'输入四位数字填充字段C'}))

    class Meta: # 不展示字段C
        exclude = ['C']

class DataBaseAdminA(admin.ModelAdmin):
    list_display = ('A', 'C')
    form = MyForm

    def save_model(self, request, obj, form, change): # 自定义save_model()给字段C填充数据
        code = request.POST.get('code')
        obj.C = code
        obj.save()
        
admin.site.register(DataBaseA, DataBaseAdminA)

当字段C接收非四位数子提示警告


image
  1. formfield_overrides
  • 提供了一种快捷方式来覆盖某些在管理员中使用的“Field”选项

将默认TextField字段的文本框改小一点

from django.contrib import admin
from .models import DataBaseA
from django.db import models
from django.forms import Textarea

class DataBaseAdminA(admin.ModelAdmin):
    list_display = ('A', 'C', 'E')
    formfield_overrides = {
        models.TextField: {'widget': Textarea(attrs={'rows': 2, 'cols': 25})},
    }

admin.site.register(DataBaseA, DataBaseAdminA)

默认:


image

改变后:


image

官方给出的实例是这个样子的

from django.contrib import admin
from django.db import models

# Import our custom widget and our model from where they're defined
from myapp.models import MyModel
from myapp.widgets import RichTextEditorWidget

class MyModelAdmin(admin.ModelAdmin):
    formfield_overrides = {
        models.TextField: {'widget': RichTextEditorWidget},
    }

  1. inlines
    模型内联
    DataBaseA 和 DataBaseB 是一对多关系,在模型DataBaseA中内联DataBaseB,将其内容添加到DataBaseA进行动态编辑
# models.py
from django.db import models

class DataBaseA(models.Model):
   A = models.CharField(max_length=100)

   def __str__(self):
      return self.A

class DataBaseB(models.Model):
   X = models.ForeignKey(DataBaseA, on_delete=models.CASCADE)
   Y = models.CharField(max_length=100)

   def __str__(self):
      return self.Y

# admin.py
class DataBaseAdminB(admin.TabularInline):
    model = DataBaseB
    extra = 1 # 默认为3

class DataBaseAdminA(admin.ModelAdmin):
    inlines = [DataBaseAdminB]

admin.site.register(DataBaseA, DataBaseAdminA)
admin.site.register(DataBaseB)
image

Django提供了InlineModelAdmin的两个子类,它们是: TabularInlineStackedInline;他们略有区别

TabularInline:


image

StackedInline:


image
  1. list_display
    控制列表页面上显示哪些字段
    可以使用四种类型的值list_display:

模型字段的名称

list_display = ('A', 'B', 'C')

  • 接受一个参数(模型实例)的可调用对象
def upper_case_name(obj):
    return ("%s : %s" % (obj.A, obj.B)).upper()

upper_case_name.short_description = 'A 和 B'

class DataBaseAdminA(admin.ModelAdmin):
    list_display = (upper_case_name,)

image
  • 一个字符串,表示ModelAdmin接受一个参数(模型实例)的方法
class DataBaseAdminA(admin.ModelAdmin):
    list_display = ('upper_case_name',)

    def upper_case_name(self, obj):
        return ("%s : %s" % (obj.A, obj.B)).upper()

    upper_case_name.short_description = 'A 和 B'

image
  • 代表模型属性或方法的字符串(不带任何必需的参数)
# models.py
from django.db import models

class DataBaseA(models.Model):
   D = models.DateField(blank=True, null=True)

   def decade_born_in(self):
      return self.D.strftime('%Y')[:4]

   decade_born_in.short_description = '年'   

# admin.py
from django.contrib import admin
from .models import DataBaseA

class DataBaseAdminA(admin.ModelAdmin):
    list_display = ('decade_born_in', 'D')
    
admin.site.register(DataBaseA, DataBaseAdminA)

image
  1. list_display_links
    控制是否将list_display中的哪些字段链接到编辑页面
list_display = ('A', 'B', 'C')
list_display_links = ('C',)

image
  1. list_editable
    设置模型的字段允许在列表页面上进行编辑
list_display = ('A', 'B', 'C')
list_editable = ('B',)

image.png
  1. list_filter
    激活过滤器, 显示列表页面右侧栏中的过滤器
image.png
  1. list_max_show_all
    控制列表页面上的“显示全部”可以显示多少条数据(默认200)
    设置list_per_page 后 设置list_max_show_all将不起效果,可能数据量少的原因,此属性有待探究

  2. list_per_page
    控制每个分页的列表页面上显示多少条数据(默认100)

list_per_page = 5

image.png
  1. list_select_related
    select_related()在列表页面上检索对象列表时使用
    设置list_select_related为告诉Django select_related()在列表页面上检索对象列表时使用。这样可以为您节省大量数据库查询

该值应该是布尔值,列表或元组。默认值为False。
当值为True时,将始终调用select_related()。当值设置为False时,Django将查看list_display并调用select_related()(如果存在任何ForeignKey)
如果需要更精细的控制,请使用元组(或列表)作为list_select_related的值。空元组将完全阻止Django调用select_related()。任何其他元组将直接传递给select_related作为参数

  1. ordering
    设置默认排序字段
ordering = ['B']

image.png
  1. paginator
    用于分页的分页器类
    暂无查到关于admin分页器的内容
    官方介绍:

默认情况下,使用django.core.paginator.Paginator。如果自定义paginator类与django.core.paginator.Paginator没有相同的构造函数接口,则还需要提供ModelAdmin.get_paginator() 的实现。

  1. prepopulated_fields
    将字段名称映射到应预填充的字段
    添加页面,当在某字段填入值后,自动会将值填充到指定字段
prepopulated_fields = {"A": ("B", "C",)}

当对字段B与C输入内容时,A字段将会自动填充B或C的内容,多个字段会使用-来分割


image.png
  1. preserve_filters
    在创建,编辑或删除对象后在列表视图上保留过滤器
    详细页面,删除、修改,更新后跳转回列表后,是否保留原搜索条件,默认True

  2. radio_fields
    把外键或choice字段由下拉框变成单选框
    原样式:


    image.png
radio_fields = {"A": admin.VERTICAL}

image.png
radio_fields = {"A": admin.HORIZONTAL}

image.png
  1. autocomplete_fields
    自动补全, 针对外键设置
    注意:此属性设置的值绑定的外键必须启用search_fields
autocomplete_fields = ['X']

image
  1. raw_id_fields
  • 自动补全外键或多对多字段内容,并且设置显示其id
raw_id_fields = ['X']

image
image
  1. readonly_fields
  • 设置为只读字段
readonly_fields = ('B',)
image
image
  1. save_as
  • 在表单上启用“另存为”功能(默认False)

在编辑页面将”保存并添加另一个“ 更改为“保存成新的”

save_as = True
image.png
  1. save_as_continue
    点击保存为新的后是否跳转
    当save_as=True,节省了新对象后的默认重定向是该对象的编辑视图。如果设置了 save_as_continue=False,重定向将转到编辑列表视图。(默认True)

  2. save_on_top
    在表单顶部添加保存按钮(默认False)

save_on_top = True
image
  1. search_fields
  • 启用搜索框
image
  1. show_full_result_count
  • 控制是否应在过滤的页面上显示对象的全部数量(默认True)

True显示为“总共”多少; False显示为“显示全部”

show_full_result_count = False
image.png
  1. sortable_by
    允许的字段参与排序
sortable_by = ('B', )

只让其元组内的字段参与排序 ,其余字段将不可进行排序


image.png
  1. view_on_site
    控制是否显示“在站点上查看”按钮是否显示(默认True)
    当在模型中有get_absolute_url() 方法,则在修改页面显示 “在站点上查看”,可以通过将view_on_site 设置为False 不显示此按钮
    注:关于get_absolute_url() 请自行阅读路由反向解析
# models.py
from django.db import models
from django.urls import reverse

class DataBaseA(models.Model):
   A = models.CharField(max_length=100, choices=(('a', 'A'), ('b', 'B'), ('c', 'C')))
   B = models.CharField(max_length=100, blank=True, null=True)
   C = models.CharField(max_length=100, blank=True, null=True)
   D = models.DateField(blank=True, null=True)

   def get_absolute_url(self):
       return reverse('home')
image.png

在 amdin.py 中存在view_on_site() 方法也会显示此功能

class DataBaseAdminA(admin.ModelAdmin):

    def view_on_site(self, obj):
        url = reverse('home')
        return 'http://127.0.0.1:8000' + url
        
    list_display = ('A', 'B', 'C')
    
admin.site.register(DataBaseA, DataBaseAdminA)        
image.png

StackedInline 效果

class ApistepAdmin(admin.StackedInline):
    list_display = ['apiname', 'apiparamvalue', 'apimethod',
                    'apiresult', 'apistatus', 'create_time', 'id', 'apitest']
    model = Apistep
    extra = 1
image.png

TabularInline效果

class ApistepAdmin(admin.TabularInline):
    list_display = ['apiname', 'apiparamvalue', 'apimethod',
                    'apiresult', 'apistatus', 'create_time', 'id', 'apitest']
    model = Apistep
    extra = 1
image.png

image.png

image.png

第三方后台界面
xadmin*

查询

Django有两种过滤器用于筛选记录
filter: 返回符合筛选条件的数据集
exclude: 返回不符合筛选条件的数据集
多个filter和exclude可以连接在一起查询。

你可能感兴趣的:(Django学习笔记02 构建后端)