【Django】快速入门_基本配置

前提

已安装python3.X

安装完django

创建项目

#在命令行执行
#HelloWorld 项目名称
django-admin startproject HelloWorld

#进入项目
cd HelloWorld

目录说明

|-- HelloWorld
| |-- init.py #空文件,告诉Python这是一个Python的包
| |-- asgi.py #一个 ASGI 兼容的 Web 服务器的入口,以便运行你的项目。
| |-- settings.py #该 Django 项目的设置/配置。
| |-- urls.py #该 Django 项目的 URL 声明; 一份由 Django 驱动的网站"目录"。
| -- wsgi.py-- manage.py #一个 WSGI 兼容的 Web 服务器的入口,以便运行你的项目。

运行项目

#确保已进入HelloWorld目录下

#多种运行项目的方式
python manage.py runserver
# 指定端口
python manage.py runserver 8080
# 任意ip接入
python manage.py runserver 0.0.0.0:8080
# 这里和settings.py的配置ALLOWED_HOSTS = []
# 不一样的地方在于,这个是服务器监听的IP,IP不对无法连接到服务;
# ALLOWED_HOSTS是已经连接到服务,但连接的IP不在ALLOWED_HOSTS范围内就无法正常提供服务

运行完项目访问 127.0.0.1:8000,就能看到一个绿色的小火箭!

视图和URL配置

注意import

HelloWorld 目录新建一个 views.py 文件

#目录:HelloWorld/HelloWorld/views.py

from django.http import HttpResponse
 
def hello(request):
    return HttpResponse("Hello world ! ")

绑定 URL 与视图函数

from django.conf.urls import url
 
from . import views
 
urlpatterns = [
    url(, views.hello),
]

path() 函数

path(route, view, kwargs=None, name=None)
  • route: 字符串,表示 URL 规则,与之匹配的 URL 会执行对应的第二个参数 view。(可用正则表达式)
  • view: 用于执行与正则表达式匹配的 URL 请求。
  • kwargs: 视图使用的字典类型的参数。
  • name: 用来反向获取 URL。

route:

views:

  • from . import views导入的
  • views.hello 对应的是views中的一个函数

kwargs:

  • 少用到,暂不学

模板

为什么需要模板?

在上文views的hello中使用 django.http.HttpResponse() 来输出 "Hello World!",该方式将数据与视图混合在一起,不符合 Django 的 MVC 思想

模板:模板是一个文本,用于分离文档的表现形式和内容。

建立模板

在 HelloWorld 目录底下创建 templates 目录并建立 runoob.html

项目结构

HelloWorld/
|-- HelloWorld
|   |-- __init__.py
|   |-- __init__.pyc
|   |-- settings.py
|   |-- settings.pyc
|   |-- urls.py
|   |-- urls.pyc
|   |-- views.py
|   |-- views.pyc
|   |-- wsgi.py
|   `-- wsgi.pyc
|-- manage.py
`-- templates
    `-- runoob.html

HelloWorld/templates/runoob.html 文件代码

<h1>{{ hello }}</h1>

修改HelloWorld/settings.py

修改 TEMPLATES 中的 DIRS 为 [os.path.join(BASE_DIR, 'templates')]

  • 注意导入:import os
...
import os
...
TEMPLATES = [
    {
        ...
        'DIRS': [os.path.join(BASE_DIR, 'templates')]
        ...
    },
]
...

修改 views.py

from django.shortcuts import render
 
def runoob(request):
    context          = {}
    context['hello'] = 'Hello World!'
    return render(request, 'runoob.html', context)

#context可换成{"name":views_name}

修改HelloWorld/HelloWorld/urls.py

from django.urls import path
 
from . import views
 
urlpatterns = [
    path('runoob/', views.runoob),
]

模板语法

views中的变量与html中变量“绑定”

view:{"HTML变量名" : "views变量名"}
HTML:{{变量名}}
#html页面中
<h1>{{HTML变量名}}</h1>

#在views中
return render(request, 'runoob.html', {"HTML变量名" : "views变量名"})

网页导航和页脚

使用子模版继承父模版,减少代码冗余

父模板

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>base</title>
</head>
<body>
    <h1>Hello World!</h1>
    <p>父模板测试</p>
    {% block mainbody %}
       <p>base template</p>
    {% endblock %}
</body>
</html>

子模板

{%extends "base.html" %}

  • 继承了一个父模板(网页)

父模板的{% block 名称%}{% 名称%}

  • 相当于留空位给子模版新增内容
  • 标签是可以被继承者们替换掉的部分
{%extends "base.html" %}
 
{% block mainbody %}
<p>继承了 base.html 文件</p>
{% endblock %}

模型

参考

Django 模型使用自带的 ORM。

  • 对象关系映射(Object Relational Mapping,简称 ORM )用于实现面向对象编程语言里不同类型系统的数据之间的转换。
image.png
# 安装 mysql 驱动
pip install pymysql

在数据库软件中新建数据库

-- runoob 数据库名
create database runoob default charset=utf8;  

修改 HelloWorld/HelloWorld/settings.py 中的DATABASES

DATABASES = { 
    'default': 
    { 
        'ENGINE': 'django.db.backends.mysql',    # 数据库引擎
        'NAME': 'runoob', # 数据库名称
        'HOST': '127.0.0.1', # 数据库地址,本机 ip 地址 127.0.0.1 
        'PORT': 3306, # 端口 
        'USER': 'root',  # 数据库用户名
        'PASSWORD': '123456', # 数据库密码
    }  
}

告诉 Django 使用 pymysql 模块连接 mysql 数据库

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

定义模型

Django 规定,如果要使用模型,必须要创建一个 app。

#命令行中输入
# TestModel与manage.py在同级目录下
django-admin.py startapp TestModel

创建表

修改 TestModel/models.py 文件

# models.py
from django.db import models
 
class Test(models.Model):
    name = models.CharField(max_length=20)

类名代表了数据库表名(Test)

类里面的字段代表数据表中的字段(name)

数据类型则由CharField(相当于varchar)、DateField(相当于datetime)

max_length 参数限定长度。

告诉django我们安装的app

在 settings.py 中找到INSTALLED_APPS

  • setting.py在HelloWorld目录下
INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'TestModel',               # 添加此项
)

命令行中运行

python manage.py migrate   # 创建表结构

python manage.py makemigrations TestModel  # 让 Django 知道我们在我们的模型有一些变更
python manage.py migrate TestModel   # 创建表结构
#如果代码有报异常,继续往下翻。

第二行代码执行后

image.png

第三行代码执行后

image.png

该表结构

Django 会自动添加一个 id 作为主键。

image.png

异常

django.db.utils.OperationalError:(1045,"Access denied for user 'root'@'localhost'

  • 确保用户名和密码正确后再试一次
    • 可以用命令行测试数据库连接
    • 开启服务:net start 服务名(例如:mysql5.7)
    • mysql -h 主机名(ip) -u 用户名 -P 端口 -p

其他解决方案

数据库操作

HelloWorld 目录中添加 testdb.py 文件,并修改 urls.py

#urls.py
from django.urls import path
 
from . import views,testdb
 
urlpatterns = [
    path('runoob/', views.runoob),
    path('testdb/', testdb.testdb),
]
添加数据
from django.http import HttpResponse
 
from TestModel.models import Test
 
# 数据库操作
def testdb(request):
    test1 = Test(name='runoob')
    test1.save()
    return HttpResponse("<p>数据添加成功!</p>")

启动服务器并访问

python manage.py runserver #启动服务器

#访问 http://127.0.0.1:8000/testdb/
#看到页面输出:数据添加成功

查看数据库

image.png
获取数据、删除、修改

参考

#获取
# 通过objects这个模型管理器的all()获得所有数据行,相当于SQL中的SELECT * FROM
list = Test.objects.all()

# filter相当于SQL中的WHERE,可设置条件过滤结果
response2 = Test.objects.filter(id=1) 

# 获取单个对象
response3 = Test.objects.get(id=1) 

# 限制返回的数据 相当于 SQL 中的 OFFSET 0 LIMIT 2;(分页)
Test.objects.order_by('name')[0:2]

#数据排序
Test.objects.order_by("id")

# 上面的方法可以连锁使用
Test.objects.filter(name="runoob").order_by("id")
#修改
#save() 或 update():
# 修改其中一个id=1的name字段,再save,相当于SQL中的UPDATE
test1 = Test.objects.get(id=1)
test1.name = 'Google'
test1.save()

# 另外一种方式
Test.objects.filter(id=1).update(name='Google')

# 修改所有的列
Test.objects.all().update(name='Google')
#删除
# 删除id=1的数据
test1 = Test.objects.get(id=1)
test1.delete()

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

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

异常

删除数据库表后无法更新

问题:修改模型后无法更新数据库表结构,删除后再执行命令也不行。参考

解决:

  1. 删除app/migrations/目录下 “_pycache_” 文件

  2. 删除app下面目录migrations下面除了init.py其他的所有文件

  3. 删除对应数据库中django_migrations表中app名称所在的列

    (或者delete from django_migrations where app=‘yourappname’;),解决无法生成表

表单

HTML表单是网站交互性的经典方式。

HTTP协议以"请求-回复"的方式工作。

  • 客户发送请求时,可以在请求中附加数据。
  • 服务器通过解析请求,就可以获得客户传来的数据,并根据URL来提供特定的服务。

GET

创建一个 search.py 文件,用于接收用户的请求

#/HelloWorld/HelloWorld/search.py 文件

from django.http import HttpResponse
from django.shortcuts import render

#表单
def search_form(request):
    return render(request,'search_form.html')

#接收请求数据
def search(request):
    request.encoding='utf-8'
    if('q' in request.GET and request.GET['q']):
        message = '您搜索的内容为:' + request.GET['q']
    else:
        message = '您提交了空表单'
    return HttpResponse(message)

模板目录 templates 中添加 search_form.html 表单

#/HelloWorld/templates/search_form.html 文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>form_test</title>
</head>
<body>
    <form action="/search/" method="GET">
        <input type="text" name="q">
        <input type="submit" value="搜索">
    </form>
</body>
</html>

urls.py 规则 添加以下代码

使用url能匹配正则表达式(path好像不行)

...
from django.conf.urls import url

urlpatterns = [
    ...,
    url(r'^search-form/$',search.search_form),
    url(r'^search/$',search.search)
]

访问 http://127.0.0.1:8000/search-form/,搜索后提交即可看到效果

GET请求 视图显示和请求处理分成两个函数处理。

POST

提交数据时更常用POST方法。

  • 一个URL和处理函数,同时显示视图和处理请求。

Request对象

表单form通过HTTP POST方法提交请求,但是表单中可以没有数据。

因此,不能使用语句if request.POST来判断是否使用HTTP POST方法;

应该使用if request.method == "POST"

参考1

参考2

参考3

路由

Django不会匹配域名和协议

举例:

请求:访问http://127.0.0.1:8000/polls/34/

Django项目到urls中顺序进行正则匹配/polls/34/,匹配到polls/,就切掉文本"polls/",剩余文本"34/"继续进行匹配

  • path('polls/',include('polls.urls'))
  • path('<int:question_id>/', views.detail, name='detail')

匹配到了views.detail

得到参数question_id=34<int:question_id> 匹配生成。

  • 使用尖括号“捕获”这部分 URL,且以关键字参数的形式发送给视图函数。
  • 上述字符串的 :question_id> 部分定义了将被用于区分匹配模式的变量名
  • int: 则是一个转换器决定了应该以什么变量类型匹配这部分的 URL 路径。

路由简单的来说就是根据用户请求的 URL 链接来判断对应的处理程序,并返回处理结果,

  • URL 与 Django 的视图建立映射关系。

Django 路由在 urls.py 配置,urls.py 中的每一条配置对应相应的处理方法。

Django 不同版本 urls.py 配置有点不一样

Django1.1.x 版本

url() 方法:普通路径和正则路径均可使用,需要自己手动添加正则首位限制符号。

from django.conf.urls import url # 用 url 需要引入 

urlpatterns = [ 
    url(r'^admin/$', admin.site.urls), 
    url(r'^index/$', views.index), # 普通路径 
    url(r'^articles/([0-9]{4})/$', views.articles), # 正则路径 
]

Django 2.2.x 之后

  • path:用于普通路径,不需要自己手动添加正则首位限制符号,底层已经添加。
  • re_path:用于正则路径,需要自己手动添加正则首位限制符号。
from django.urls import re_path # 用re_path 需要引入 
urlpatterns = [ 
    path('admin/', admin.site.urls), 
    path('index/', views.index), # 普通路径 
    re_path(r'^articles/([0-9]{4})/$', views.articles), # 正则路径 
]

总结:Django1.1.x 版本中的 url 和 Django 2.2.x 版本中的 re_path 用法相同。

分组

参考

正则还有分组的概念,但是在Django中把分组分为两种:

  • 无名分组
  • 有名分组

无名分组

无名分组:普通的正则匹配中加上()

作用:在后端的views上,会得到一个分组的参数

  • 访问views.login函数(下方)的参数除了request,还需要添加一个参数(名字随意)
  • 要设置几个参数就要多几个分组

以下代码访问:login/2222,那么xxx的值为2222

#urls.py
urlpatterns = [
 url(r'^login/([0-9]{4})$',views.login),
]

#views.py
def login(request,xxx):
    print(xxx)

举例参考

#search2.py
def divede_group_year(request,year):
    return HttpResponse('您的选择是:%s' % year)
def divede_group_month(request,year,month):
    return HttpResponse('选择的月份是:%s-%s' %(year,month))

#urls.py
from django.urls import path,re_path
...

urlpatterns = [
    ...,
    # 记得添加结束标签 $
    re_path(r'^divede-group/([0-9]{4})/$',search2.divede_group_year),
    re_path(r'^divede-group/([0-9]{4})/([0-9]{2})/$',search2.divede_group_month)
]
image.png
image.png

有名分组

有名分组: 有名分组其实就是在无名的分组的基础上加上了名字

语法为:(?P<名字> 正则表达式)

#urls.py
...,

urlpatterns = [
    ...,
 url(r'^login/(?P<year>[0-9]{4})$',views.login),
]

#views.py
...,
def login(request,year):
     print(year)

举例

#search2.py
from django.http import HttpResponse
def divede_group_name(request,name):
    return HttpResponse('有名分组:%s' %(name))

#urls.py
from . import search2
re_path(r'^divede-group/(?P<name>[a-z]{4})/$',search2.divede_group_name)
image.png

视图函数的参数name 要和有名参数的名字name一致,否则会报错!

注意:官方规定,有名分组和无名分组不能一起使用!

路由分发(include)

问题:

  • 项目里多个app目录共用一个 urls 容易造成混淆
  • 后期维护不方便

解决:

  • 使用路由分发(include),让每个app目录都单独拥有自己的 urls。

步骤:

  • 1、在每个 app 目录里都创建一个 urls.py 文件。
  • 2、在项目名称目录下的 urls 文件里,统一将路径分发给各个 app 目录。
举例:

有两个app,都有index.html页面

  • 如果在项目的urls中配置,则会造成混淆
  • 且如果有太多的url,则维护十分难

所以应该把各种的url分给各自去管理

#路由 未分发
#项目主目录下的urls.py
urlpatterns = [
    url(r'^app-one/index/$',views.index),
    url(r'^app-two/index/$',views.index)
]

新建两个app

# 语法:python manage.py startapp <app名称>
# 命令行中运行
python manage.py startapp app01
python manage.py startapp app02

app1目录下

1.views文件

from django.http import HttpResponse

def index(request):
    return HttpResponse('app01的index页面!')

2.新建urls.py文件

from . import views
from django.conf.urls import url #没有引入会报错:NameError: name 'url' is not defined django
urlpatterns = [
    url(r'^index/$',views.index)
]

app2目录下

1.views文件

from django.http import HttpResponse

def index(request):
    return HttpResponse('app2:index!')

2.新建urls.py文件

from . import views
from django.conf.urls import url

urlpatterns = [
    url(r'^index/$',views.index)
]

项目主目录下的urls.py

urlpatterns = [
    url(r'^app-one/',include('app01.urls')),
    url(r'^app-two/',include('app02.urls'))
]

访问

注意访问路径:

  • app-one/index/
  • 对照上面的urls.py文件,就能理解路由转发了!

app01

运行项目:python manage.py runserver

image.png

app02

image.png

反向解析

目的:解耦

  • 路由层的 url 发生变化,就需要去更改对应的视图层和模板层的 url,不便维护

反向解析

  • 当路由层 url 发生改变,在视图层和模板层动态反向解析出更改后的 url,免去修改的操作。
  • 一般用在模板中的超链接及视图中的重定向

问题举例

#urls.py 中的一条url
...
url(r'^login/$',views.login)
...
#html页面中的提交表单
<form action="/login/" method="P=post">
    ...
</form>

当更改路由中的url时,需要在html页面也做相应的更改!

解耦目的:只更改路由中的url,html中会自动做出更改,我们无需去改变!

反向解析

方法:给路由器起别名

应用:

举例参考

1.普通路径:name="路由别名

重定向:

  • redirect(reverse("login"))

超链接:

  • <form action="{% url 'login' %}" method="post">

2.正则路径:无名分组

re_path(r"^login/([0-9]{2})/$", views.login, name="login")

重定向:

  • reverse("路由别名",args=(符合正则匹配的参数,))
    • redirect(reverse("login",args=(10,)))

超链接:

  • {% url "路由别名" 符合正则匹配的参数 %}
    • {% url 'login' 10 %}

3.正则路径:有名分组

re_path(r"^login/(?P<year>[0-9]{4})/$", views.login, name="login")

重定向:

  • reverse("路由别名",kwargs={"分组名":符合正则匹配的参数})
    • redirect(reverse("login",kwargs={"year":3333}))

超链接:

  • {% url "路由别名" 分组名=符合正则匹配的参数 %}
    • {% url 'login' year=3333 %}

命名空间

命名空间(英语:Namespace)是表示标识符可见范围

一个标识符可在多个命名空间中定义,它在不同命名空间中的含义是互不相干的。

一个新的命名空间中可定义任何标识符,它们不会与任何重复的标识符发生冲突,因为重复的定义都处于其它命名空间中。

存在问题:路由别名 name 没有作用域,Django 在反向解析 URL 时,会在项目全局顺序搜索,当查找到第一个路由别名 name 指定 URL 时,立即返回。当在不同的 app 目录下的urls 中定义相同的路由别名 name 时,可能会导致 URL 反向解析错误。

解决:使用命名空间。

普通路径

方式一:

#主目录下的urls
urlpatterns = [
    path('admin/', admin.site.urls),
    path('polls/',include('polls.urls'))
]
# polls中的urls.py
from django.urls import path
from . import views

app_name = 'polls' #命名空间
urlpatterns = [
    ...
    # ex: /polls/5/
    path('<int:question_id>/', views.detail, name='detail'),
    ...
]
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>

方式二:

定义命名空间(include 里面是一个元组)

include(("app名称:urls","app名称"))

实例

path("app01/", include(("app01.urls","app01"))) 
path("app01/", include(("app02.urls","app02")))

起别名

path("login/", views.login, name="login")

调用

#重定向
redirect(reverse("app01:login")
         
#超链接
{% url "app名称:路由别名" %}

视图

每个视图必须要做的只有两件事:

  • 返回一个包含被请求页面内容的 HttpResponse 对象
  • 或者抛出一个异常,比如 Http404

基于类的视图

Admin 管理工具

介绍

Django 提供了基于 web 的管理工具。

Django 自动管理工具是 django.contrib 的一部分。

在项目的 settings.py 中的 INSTALLED_APPS 可以看到

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
)

django.contrib是一套庞大的功能集,它是Django基本代码的组成部分。

激活管理工具

在生成项目时会在 urls.py 中自动设置好,我们只需去掉注释即可。

配置如下

# urls.py
from django.conf.urls import url
from django.contrib import admin
 
urlpatterns = [
    url(r'^admin/', admin.site.urls),
]

使用管理工具

创建超级用户

# python manage.py createsuperuser
Username (leave blank to use 'root'): admin
Email address: 
Password:admin
Password (again):
Superuser created successfully.
  1. 创建模型(model)
  2. 修改admin.py
  3. 告知Django模型有更改
  4. 创建表

之前在 TestModel 中已经创建了模型 Test 。修改 TestModel/admin.py:

from django.contrib import admin
from TestModel.models import Test
 
# Register your models here.
admin.site.register(Test)

复杂模型

TestModel/models.py 中增加一个更复杂的数据模型

from django.db import models

# Create your models here.
class Test(models.Model):
    name = models.CharField(max_length=20)

class Contact(models.Model):
    name = models.CharField(max_length=20)
    age = models.IntegerField(default=0)
    email = models.EmailField()
    def __unicode__(self):
        return self.name

class Tag(models.Model):
    concate = models.ForeignKey(Contact,on_delete=models.CASCADE)
    name = models.CharField(max_length=50)
    def __unicode__(self):
        return self.name

TestModel/admin.py中修改

from django.contrib import admin
from TestModel.models import Test,Contact,Tag

# Register your models here.
admin.site.register([Test,Contact,Tag])

刷新 http://127.0.0.1:8000/admin/ 页面

image.png

现在只是有了Concate和Tag模型,在数据库中还没有对应的表

(Test是文章前面建的)

image.png

使用以下命令创建表结构

python manage.py makemigrations TestModel  # 让 Django 知道我们在我们的模型有一些变更
python manage.py migrate TestModel   # 创建表结构

第一条命令执行完,多了一个文件

image.png

第二条命令执行完,创建了对应的表

(有关数据库连接请看“模型”)

image.png

自定义admin界面

自定义表单

1.把Age隐藏起来
image.png

修改 TestModel/admin.py:

from django.contrib import admin
from TestModel.models import Test,Contact,Tag

# Register your models here.
class ContactAdmin(admin.ModelAdmin):  #新增代码
    fields = ('name','email')         #新增代码

admin.site.register(Contact,ContactAdmin) #新增代码
admin.site.register([Test,Tag])          #删除",Contact"

代码说明

定义了一个 ContactAdmin 类,用以说明管理页面的显示格式。

  • fields 属性定义了要显示的字段
  • 该类对应的是 Contact 数据模型,我们在注册的时候,需要将它们一起注册

刷新后显示效果如下

image.png
2.将输入栏分块,每个栏也可以定义自己的格式。

注意字母拼写不要错误!!!

from django.contrib import admin
from TestModel.models import Test,Contact,Tag
 
# Register your models here.
class ContactAdmin(admin.ModelAdmin):
    fieldsets = (
        ['Main',{
            'fields':('name','email'),
        }],
        ['Advance',{
            'classes': ('collapse',), # CSS
            'fields': ('age',),
        }]
    )

admin.site.register(Contact, ContactAdmin)
admin.site.register([Test, Tag])

刷新页面

image.png

点击“Show”

image.png

说明

上面的栏目分为了 Main 和 Advance 两部分。

classes 说明它所在的部分的 CSS 格式。这里让 Advance 部分隐藏

内联(Inline)显示

上面的 Contact 是 Tag 的外部键,所以有外部参考的关系。

问题:在默认的页面显示中,将两者分离开来,无法体现出两者的从属关系。

解决:可以使用内联显示,让 Tag 附加在 Contact 的编辑页面上显示。

修改TestModel/admin.py

from django.contrib import admin
from TestModel.models import Test,Contact,Tag

# Register your models here.
class TagInline(admin.TabularInline): #新增代码
    model = Tag                     #新增代码

class ContactAdmin(admin.ModelAdmin):
    inlines = [TagInline] #Inline   #修改代码
    fieldsets = (
    ['Main',{
        'fields':('name','email'),
    }],
    ['Advance',{
        'classes':('cpllapse',), #CSS
        'fields':('age',),
    }]
)
        

admin.site.register(Contact,ContactAdmin)
admin.site.register([Test])         #修改代码

刷新显示

image.png

列表页的显示

在 Contact 输入数条记录后,Contact 的列表页看起来如下

image.png

目的:在列表中显示更多的栏目

  • 在 ContactAdmin 中增加 list_display 属性
from django.contrib import admin
from TestModel.models import Test,Contact,Tag

# Register your models here.
class TagInline(admin.TabularInline):
    model = Tag

class ContactAdmin(admin.ModelAdmin):
    list_display = ('name','age','email') #新增list_display属性
    inlines = [TagInline] #Inline
    fieldsets = (
    ['Main',{
        'fields':('name','email'),
    }],
    ['Advance',{
        'classes':('cpllapse',), #CSS
        'fields':('age',),
    }]
)
        

admin.site.register(Contact,ContactAdmin)
admin.site.register([Test])

刷新显示

image.png

app

一个项目中可以创建很多个app

app可以用路由分发解决url冲突

使用命名空间也可以减少模板冲突等等

应用1

image.png

qyvxtest:项目名

charlist:新建的app

app可以成为绝对路径的引入,解决的导入模块时的问题

例如:在一个项目中,新建了一个app,在该app的views中

from . import models

#异常
#RuntimeError: Model class chatlist.models.User doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS

在setting中

INSTALLED_APPS = [
    ...,
    'chatlist',
]

则在该app的view中可以

from . import models
#或者
from chatlist import models
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容