• django项目mysite


    项目建立

    建立项目mysite

    各文件和目录解释:

    • 外层的mysite/目录与Django无关,只是你项目的容器,可以任意重命名。
    • manage.py:一个命令行工具,用于与Django进行不同方式的交互脚本,非常重要!
    • 内层的mysite/目录是真正的项目文件包裹目录,它的名字是你引用内部文件的包名,例如:mysite.urls
    • mysite/__init__.py:一个定义包的空文件。
    • mysite/settings.py:项目的主配置文件,非常重要!
    • mysite/urls.py:路由文件,所有的任务都是从这里开始分配,相当于Django驱动站点的内容表格,非常重要!
    • mysite/wsgi.py:一个基于WSGI的web服务器进入点,提供底层的网络通信功能,通常不用关心。

     启动开发服务器

    或进入mystie项目的根目录,输入下面的命令:

    $ python manage.py runserver

    Django提供了一个用于开发的web服务器,使你无需配置一个类似Ngnix的生产服务器,就能让站点运行起来。这是一个由Python编写的轻量级服务器,简易并且不安全,因此不要将它用于生产环境。

    打开浏览器,访问http://127.0.0.1:8000/,你将看到Django的火箭欢迎界面,一切OK!

    创建投票应用(app)

    在 Django 中,每一个应用(app)都是一个 Python 包,并且遵循着相同的约定。Django 自带一个工具,可以帮你生成应用的基础目录结构。

    app应用与project项目的区别:

    • 一个app实现某个功能,比如博客、公共档案数据库或者简单的投票系统;
    • 一个project是配置文件和多个app的集合,这些app组合成整个站点;
    • 一个project可以包含多个app;
    • 一个app可以属于多个project!

    通常app将它们放在与manage.py脚本同级的目录下,这样方便导入文件。

    进入mysite项目根目录,确保与manage.py文件处于同一级,输入下述命令

    python manage.py startapp polls
    

      系统会自动生成 polls应用的目录,其结构如下

    在Pycharm中,没有可以创建app的图形化按钮,需要在下方的Terminal终端中输入命令

    编写视图

    polls/views.py文件中,编写代码

    from django.http import HttpResponse
    
    
    def index(request):
        return HttpResponse("Hello, world. You're at the polls index.")

    为了调用该视图,我们还需要编写urlconf,也就是路由。现在,在polls目录中新建一个文件,名字为urls.py,在其中输入代码如下:

    from django.urls import path
    
    from . import views
    
    urlpatterns = [
        path('', views.index, name='index'),
    ]

    接下来,在项目的主urls.py文件中添加urlpattern条目,指向我们刚才建立的polls这个app独有的urls文件,

    这里需要导入include模块。打开mysite/urls.py文件,代码如下

    from django.contrib import admin
    from django.urls import include, path
    
    urlpatterns = [
        path('polls/', include('polls.urls')),
        path('admin/', admin.site.urls),
    ]

    include语法相当于多级路由,它把接收到的url地址去除与此项匹配的部分,将剩下的字符串传递给下一级路由

    include的背后是一种即插即用的思想。项目根路由不关心具体app的路由策略,只管往指定的二级路由转发,实现了应用解耦。

    app所属的二级路由可以根据自己的需要随意编写,不会和其它的app路由发生冲突。app目录可以放置在任何位置,而不用修改路由。这是软件设计里很常见的一种模式。

    好了,路由设置成功后,启动服务器,然后在浏览器中访问地址http://localhost:8000/polls/。一切正常的话,你将看到“Hello, world. You’re at the polls index.”

    path()方法

    路由系统中最重要的path()方法可以接收4个参数,其中2个是必须的:routeview,以及2个可选的参数:kwargsname

    route:

    route 是一个匹配 URL 的准则(类似正则表达式)。当 Django 响应一个请求时,它会从 urlpatterns 的第一项开始,按顺序依次匹配列表中的项,直到找到匹配的项,

    然后执行该条目映射的视图函数或下级路由,其后的条目将不再继续匹配。因此,url路由的编写顺序非常重要!

    需要注意的是,route不会匹配 GET 和 POST 参数或域名。例如,URLconf 在处理请求 https://www.example.com/myapp/时,

    它会尝试匹配 myapp/。处理请求 https://www.example.com/myapp/?page=3 时,也只会尝试匹配 myapp/

    view:

    view指的是处理当前url请求的视图函数。当Django匹配到某个路由条目时,自动将封装的HttpRequest对象作为第一个参数,被“捕获”的参数以关键字参数的形式,传递给该条目指定的视图view。

    kwargs:

    任意数量的关键字参数可以作为一个字典传递给目标视图。

    name:

    对你的URL进行命名,让你能够在Django的任意处,尤其是模板内显式地引用它。这是一个非常强大的功能,相当于给URL取了个全局变量名,不会将url匹配地址写死

    数据库配置

    打开mysite/settings.py配置文件,这是整个Django项目的设置中心。Django默认使用SQLite数据库,

    因为Python源生支持SQLite数据库,所以你无须安装任何程序,就可以直接使用它。当然,如果你是在创建一个实际的项目,可以使用类似PostgreSQL的数据库

    # Database
    # https://docs.djangoproject.com/en/2.1/ref/settings/#databases
    
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
        }
    }

    如果你想使用其他的数据库,请先安装相应的数据库操作模块,并将settings文件中DATABASES位置的’default’的键值进行相应的修改,用于连接你的数据库。其中:

    • ENGINE(引擎):可以是django.db.backends.sqlite3django.db.backends.postgresqldjango.db.backends.mysqldjango.db.backends.oracle,当然其它的也行。

    • NAME(名称):类似Mysql数据库管理系统中用于保存项目内容的数据库的名字。如果你使用的是默认的SQLite,那么数据库将作为一个文件将存放在你的本地机器内,

               此时的NAME应该是这个文件的完整绝对路径包括文件名,默认值os.path.join(BASE_DIR, ’db.sqlite3’),将把该文件储存在你的项目目录下。

    基于pymysql操作Mysql数据库的例子

    # Database
    # https://docs.djangoproject.com/en/1.11/ref/settings/#databases
    
    import pymysql         # 一定要添加这两行!通过pip install pymysql!
    pymysql.install_as_MySQLdb()
    
    
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'NAME': 'cnblog',
            'USER': 'root',
            'PASSWORD': '111',
            'HOST': '127.0.0.1',
            'PORT': 3306
          
        }
    }
    
    
    # mysql orm转换sql日志
    LOGGING = {
        'version': 1,
        'disable_existing_loggers': False,
        'handlers': {
            'console':{
                'level':'DEBUG',
                'class':'logging.StreamHandler',
            },
        },
        'loggers': {
            'django.db.backends': {
                'handlers': ['console'],
                'propagate': True,
                'level':'DEBUG',
            },
        }
    }

    注意:

    • 在使用非SQLite的数据库时,请务必预先在数据库管理系统的提示符交互模式下创建数据库,你可以使用命令:CREATE DATABASE database_name;。Django不会自动帮你做这一步工作。
    • 确保你在settings文件中提供的数据库用户具有创建数据库表的权限,因为在接下来的教程中,我们需要自动创建一个test数据表。(在实际项目中也需要确认这一条要求。)
    • 如果你使用的是SQLite,那么你无需做任何预先配置,直接使用就可以了。

    在修改settings文件时,请顺便将TIME_ZONE设置为国内所在的时区Asia/Shanghai

    同时,请注意settings文件中顶部的INSTALLED_APPS设置项。它列出了所有的项目中被激活的Django应用(app)。你必须将你自定义的app注册在这里。每个应用可以被多个项目使用,并且可以打包和分发给其他人在他们的项目中使用。

    默认情况,INSTALLED_APPS中会自动包含下列条目,它们都是Django自动生成的:

    • django.contrib.admin:admin管理后台站点
    • django.contrib.auth:身份认证系统
    • django.contrib.contenttypes:内容类型框架
    • django.contrib.sessions:会话框架
    • django.contrib.messages:消息框架
    • django.contrib.staticfiles:静态文件管理框架

    上面的一些应用也需要建立一些数据库表,所以在使用它们之前我们要在数据库中创建这些表。使用下面的命令创建数据表:

    python manage.py migrate
    

      

    创建模型

    现在,我们来定义模型model,模型本质上就是数据库表的布局,再附加一些元数据。

    Django通过自定义Python类的形式来定义具体的模型,每个模型的物理存在方式就是一个Python的类Class,每个模型代表数据库中的一张表,每个类的实例代表数据表中的一行数据,类中的每个变量代表数据表中的一列字段。

    Django通过模型,将Python代码和数据库操作结合起来,实现对SQL查询语言的封装。也就是说,你可以不会管理数据库,可以不会SQL语言,你同样能通过Python的代码进行数据库的操作。

    Django通过ORM对数据库进行操作,奉行代码优先的理念,将Python程序员和数据库管理员进行分工解耦。

    在这个简单的投票应用中,我们将创建两个模型:QuestionChoice。Question包含一个问题和一个发布日期。Choice包含两个字段:该选项的文本描述和该选项的投票数。

    每一条Choice都关联到一个Question。这些都是由Python的类来体现,编写的全是Python的代码,不接触任何SQL语句。现在,编辑polls/models.py文件

    from django.db import models
    
    
    class Question(models.Model):
        question_text = models.CharField(max_length=200)
        pub_date = models.DateTimeField('date published')
    
    
    class Choice(models.Model):
        question = models.ForeignKey(Question, on_delete=models.CASCADE)
        choice_text = models.CharField(max_length=200)
        votes = models.IntegerField(default=0)

    上面的代码非常简单明了。每一个类都是django.db.models.Model的子类。每一个字段都是Field类的一个实例,例如用于保存字符数据的CharField和用于保存时间类型的DateTimeField,它们告诉Django每一个字段保存的数据类型。

    每一个Field实例的名字就是字段的名字(如: question_text 或者 pub_date )。在你的Python代码中会使用这个值,你的数据库也会将这个值作为表的列名。

    一些Field类必须提供某些特定的参数。例如CharField需要你指定max_length。这不仅是数据库结构的需要,同样也用于数据验证功能。

    有必填参数,当然就会有可选参数,比如在votes里我们将其默认值设为0.

    最后请注意,我们使用ForeignKey定义了一个外键关系。它告诉Django,每一个Choice关联到一个对应的Question(注意要将外键写在‘多’的一方)。Django支持通用的数据关系:一对一,多对一和多对多。

    启用模型

    上面的代码看着有点少,其实包含了大量的信息,据此,Django会做下面两件事:

    • 创建该app对应的数据库表结构
    • 为Question和Choice对象创建基于Python的数据库访问API

    但是,首先我们得先告诉Django项目,我们要使用投票app。

    要将应用添加到项目中,需要在INSTALLED_APPS设置中增加指向该应用的配置文件的链接。对于本例的投票应用,它的配置类文件PollsConfig是polls/apps.py

    所以它的点式路径为polls.apps.PollsConfig。我们需要在INSTALLED_APPS中,将该路径添加进去,实际上,在多数情况下,我们简写成‘polls’就可以了:

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'polls'
    ]

    现在Django已经知道你的投票应用的存在了,并把它加入了项目大家庭。

    我们需要再运行下一个命令:

     python manage.py makemigrations polls
    

      

    通过运行makemigrations命令,Django 会检测你对模型文件的修改,也就是告诉Django你对模型有改动,并且你想把这些改动保存为一个“迁移(migration)”。

    migrations是Django保存模型修改记录的文件,这些文件保存在磁盘上。在例子中,它就是polls/migrations/0001_initial.py,你可以打开它看看,里面保存的都是人类可读并且可编辑的内容,方便你随时手动修改。

    接下来有一个叫做migrate的命令将对数据库执行真正的迁移动作。但是在此之前,让我们先看看在migration的时候实际执行的SQL语句是什么。有一个叫做sqlmigrate的命令可以展示SQL语句

    python manage.py sqlmigrate polls 0001
    

      

    请注意:

    • 实际的输出内容将取决于您使用的数据库会有所不同。上面的是mySQL的输出。
    • 表名是自动生成的,通过组合应用名 (polls) 和小写的模型名questionchoice 。 ( 你可以重写此行为。)
    • 主键 (IDs) 是自动添加的。( 你也可以重写此行为。)
    • 按照惯例,Django 会在外键字段名上附加 "_id" 。 (你仍然可以重写此行为。)
    • 生成SQL语句时针对你所使用的数据库,会为你自动处理特定于数据库的字段,例如 auto_increment (MySQL), serial (PostgreSQL), 或integer primary key (SQLite) 。 在引用字段名时也是如此 – 比如使用双引号或单引号。
    • 这些SQL命令并没有在你的数据库中实际运行,它只是在屏幕上显示出来,以便让你了解Django真正执行的是什么。

    如果你感兴趣,也可以运行python manage.py check命令,它将检查项目中的错误,并不实际进行迁移或者链接数据库的操作。

    $ python manage.py migrate
    

      

    migrate命令对所有还未实施的迁移记录进行操作,本质上就是将你对模型的修改体现到数据库中具体的表上面。Django通过一张叫做django_migrations的表,记录并跟踪已经实施的migrate动作,通过对比获得哪些migrations尚未提交。

    migrations的功能非常强大,允许你随时修改你的模型,而不需要删除或者新建你的数据库或数据表,在不丢失数据的同时,实时动态更新数据库。我们将在后面的章节对此进行深入的阐述,但是现在,只需要记住修改模型时的操作分三步:

    • 在models.py中修改模型;
    • 运行python manage.py makemigrations为改动创建迁移记录;
    • 运行python manage.py migrate,将操作同步到数据库。
    mysql> show tables;
    +----------------------------+
    | Tables_in_poll             |
    +----------------------------+
    | auth_group                 |
    | auth_group_permissions     |
    | auth_permission            |
    | auth_user                  |
    | auth_user_groups           |
    | auth_user_user_permissions |
    | django_admin_log           |
    | django_content_type        |
    | django_migrations          |
    | django_session             |
    | polls_choice               |
    | polls_question             |
    +----------------------------+
    12 rows in set (0.00 sec)

    使用模型的API

    下面,让我们进入Python交互环境,尝试使用Django提供的数据库访问API。要进入Python的shell,请输入命令

     python manage.py shell
    

      

    相比较直接输入“python”命令的方式进入Python环境,调用manage.py参数能将DJANGO_SETTINGS_MODULE环境变量导入,

    它将自动按照mysite/settings.py中的设置,配置好你的python shell环境,这样,你就可以导入和调用任何你项目内的模块了。

    先进入一个纯净的python shell环境,然后启动Django。

    当你进入shell后,尝试一下下面的API吧:

    >>> from polls.models import Question, Choice # 导入我们写的模型类
        # 现在系统内还没有questions对象
        >>> Question.objects.all()
        <QuerySet []>
    
        # 创建一个新的question对象
        # Django推荐使用timezone.now()代替python内置的datetime.datetime.now()
        # 这个timezone就来自于Django的依赖库pytz
        from django.utils import timezone
        >>> q = Question(question_text="What's new?", pub_date=timezone.now())
    
        # 你必须显式的调用save()方法,才能将对象保存到数据库内
        >>> q.save()
    
        # 默认情况,你会自动获得一个自增的名为id的主键
        >>> q.id
        1
    
        # 通过python的属性调用方式,访问模型字段的值
        >>> q.question_text
        "What's new?"
        >>> q.pub_date
        datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=<UTC>)
    
        # 通过修改属性来修改字段的值,然后显式的调用save方法进行保存。
        >>> q.question_text = "What's up?"
        >>> q.save()
    
        # objects.all() 用于查询数据库内的所有questions
        >>> Question.objects.all()
        <QuerySet [<Question: Question object>]>

    上面的<Question: Question object>是一个不可读的内容展示,你无法从中获得任何直观的信息,为此我们需要一点小技巧,让Django在打印对象时显示一些我们指定的信息。

    返回polls/models.py文件,修改一下question和Choice这两个类,代码如下:

    from django.db import models
    
    
    class Question(models.Model):
        question_text = models.CharField(max_length=200)
        pub_date = models.DateTimeField('date published')
    
        def __str__(self):
            return self.question_text
    
    class Choice(models.Model):
        question = models.ForeignKey(Question, on_delete=models.CASCADE)
        choice_text = models.CharField(max_length=200)
        votes = models.IntegerField(default=0)
    
        def __str__(self):
            return self.choice_text

    这个技巧不但对你打印对象时很有帮助,在你使用Django的admin站点时也同样有帮助。

    重新启动一个新的python shell,再来看看其他的AP

    >>> from polls.models import Question, Choice
    
    # 先看看__str__()的效果,直观多了吧?
    >>> Question.objects.all()
    <QuerySet [<Question: What's up?>]>
    
    # Django提供了大量的关键字参数查询API
    >>> Question.objects.filter(id=1)
    <QuerySet [<Question: What's up?>]>
    >>> Question.objects.filter(question_text__startswith='What')
    <QuerySet [<Question: What's up?>]>
    
    # 获取今年发布的问卷
    >>> from django.utils import timezone
    >>> current_year = timezone.now().year
    >>> Question.objects.get(pub_date__year=current_year)
    <Question: What's up?>
    
    # 查询一个不存在的ID,会弹出异常
    >>> Question.objects.get(id=2)
    Traceback (most recent call last):
    ...
    DoesNotExist: Question matching query does not exist.
    
    # Django为主键查询提供了一个缩写:pk。下面的语句和Question.objects.get(id=1)效果一样.
    >>> Question.objects.get(pk=1)
    <Question: What's up?>
    
    # 看看我们自定义的方法用起来怎么样
    >>> q = Question.objects.get(pk=1)
    >>> q.was_published_recently()
    True
    
    # 让我们试试主键查询
    >>> q = Question.objects.get(pk=1)
    
    # 显示所有与q对象有关系的choice集合,目前是空的,还没有任何关联对象。
    >>> q.choice_set.all()
    <QuerySet []>
    
    # 创建3个choices.
    >>> q.choice_set.create(choice_text='Not much', votes=0)
    <Choice: Not much>
    >>> q.choice_set.create(choice_text='The sky', votes=0)
    <Choice: The sky>
    >>> c = q.choice_set.create(choice_text='Just hacking again', votes=0)
    
    # Choice对象可通过API访问和他们关联的Question对象
    >>> c.question
    <Question: What's up?>
    
    # 同样的,Question对象也可通过API访问关联的Choice对象
    >>> q.choice_set.all()
    <QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
    >>> q.choice_set.count()
    3
    
    # API会自动进行连表操作,通过双下划线分割关系对象。连表操作可以无限多级,一层一层的连接。
    # 下面是查询所有的Choices,它所对应的Question的发布日期是今年。(重用了上面的current_year结果)
    >>> Choice.objects.filter(question__pub_date__year=current_year)
    <QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
    
    # 使用delete方法删除对象
    >>> c = q.choice_set.filter(choice_text__startswith='Just hacking')
    >>> c.delete()

    admin后台管理站点

    Django为你提供了一个基于项目model创建的一个后台管理站点admin。

    这个界面只给站点管理员使用,并不对大众开放。虽然admin的界面可能不是那么美观,功能不是那么强大,内容不一定符合你的要求,

    但是它是免费的、现成的,并且还是可定制的,有完善的帮助文档。

    1. 创建管理员用户

    首先,我们需要通过下面的命令,创建一个可以登录admin站点的用户:

    $ python manage.py createsuperuser
    Email address: qianyi@123.com
    Password:
    Password (again):
    The password is too similar to the email address.
    Bypass password validation and create user anyway? [y/N]: n
    Password:
    Password (again):
    (0.000) INSERT INTO `auth_user` (`password`, `last_login`, `is_superuser`, `username`, `first_name`, `last_name`, `email`, `is_staff`, `is_active`, `date_joined`) VALUES ('pbkdf2_sha256$120000$hxqaIpS92d
    rd$eAOzMV+PAlgAmpWe32pUCCbnor4W1qw/Y7ygVwxdsrg=', NULL, 1, 'qianyi', '', '', 'qianyi@123.com', 1, 1, '2019-08-06 14:39:18.192940'); args=['pbkdf2_sha256$120000$hxqaIpS92drd$eAOzMV+PAlgAmpWe32pUCCbnor4W1q
    w/Y7ygVwxdsrg=', None, True, 'qianyi', '', '', 'qianyi@123.com', True, True, '2019-08-06 14:39:18.192940']
    Superuser created successfully.

    2. 启动开发服务器

    服务器启动后,在浏览器访问http://127.0.0.1:8000/admin/。你就能看到admin的登陆界面了:

    3.进入admin站点

    利用刚才建立的账户,登陆admin,你将看到如下的界面:

     

    当前只有两个可编辑的内容:groups和users。它们是django.contrib.auth模块提供的身份认证框架。

    4. 在admin中注册投票应用

    现在还无法看到投票应用,必须先在admin中进行注册,告诉admin站点,请将polls的模型加入站点内,接受站点的管理。

    打开polls/admin.py文件,加入下面的内容:

    from django.contrib import admin
    from polls import models admin.site.register(models.Question) admin.site.register(models.Choice) # Register your models here.

    点击“Questions”,进入questions的修改列表页面。这个页面会显示所有的数据库内的questions对象,你可以在这里对它们进行修改。

    看到下面的What's new?了么?它就是我们先前创建的一个question对象,并且通过__str__方法的帮助

    这里需要注意的是:

    • 页面中的表单是由Question模型自动生成的。
    • 不同的模型字段类型(DateTimeField, CharField)会表现为不同的HTML input框类型。
    • 每一个DateTimeField都会自动生成一个可点击链接。日期是Today,并有一个日历弹出框;时间是Now,并有一个通用的时间输入列表框。

    在页面的底部,则是一些可选项按钮:

    • delete:弹出一个删除确认页面
    • save and add another:保存当前修改,并加载一个新的空白的当前类型对象的表单。
    • save and continue editing:保存当前修改,并重新加载该对象的编辑页面。
    • save:保存修改,返回当前对象类型的列表页面。

    在页面的右上角,点击History按钮,你会看到你对当前对象的所有修改操作都在这里有记录,包括修改时间和操作人员,如下图所示:

    视图和模板

    一个视图就是一个页面,通常提供特定的功能,使用特定的模板。

    编写视图

    打开polls/views.py文件,输入下列代码:

    def index(request):
        latest_question_list = Question.objects.order_by('-pub_date')[:5]
        context = {'latest_question_list': latest_question_list}
        # render()函数的第一个位置参数是请求对象(就是view函数的第一个参数),第二个位置参数是模板。还可以有一个可选的第三参数,
        # 一个字典,包含需要传递给模板的数据。最后render函数返回一个经过字典数据渲染过的模板封装而成的HttpResponse对象。
        return render(request, 'polls/index.html', context)
    
    def detail(request, question_id):
        question = get_object_or_404(Question, pk=question_id)
        return render(request, 'polls/detail.html', {'question': question})
    
    def results(request, question_id):
        response = "You're looking at the results of question %s."
        return HttpResponse(response % question_id)
    
    def vote(request, question_id):
        return HttpResponse("You're voting on question %s." % question_id)

    polls/urls.py文件中加入下面的url模式,将其映射到我们上面新增的视图

    urlpatterns = [
        path('', views.index, name='index'),
    # ex: /polls/5/
        path('<int:question_id>/', views.detail, name='detail'),
        # ex: /polls/5/results/
        path('<int:question_id>/results/', views.results, name='results'),
        # ex: /polls/5/vote/
        path('<int:question_id>/vote/', views.vote, name='vote'),
    ]

    快捷方式:get_object_or_404()

    get_object_or_404()方法将一个Django模型作为第一个位置参数,后面可以跟上任意个数的关键字参数,如果对象不存在则弹出Http404错误。

    同样,还有一个get_list_or_404()方法,和上面的get_object_or_404()类似,只不过是用来替代filter()函数,当查询列表为空时弹出404错误。

    (filter是模型API中用来过滤查询结果的函数,它的结果是一个列表集。而get则是查询一个结果的方法,和filter是一个和多个的区别!)

    编写模板

    polls/templates/polls/index.html:

    {% if latest_question_list %}
        <ul>
        {% for question in latest_question_list %}
            <li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
        {% endfor %}
        </ul>
    {% else %}
        <p>No polls are available.</p>
    {% endif %}

     polls/detail.html

    <h1>{{ question.question_text }}</h1>
    <ul>
    {% for choice in question.choice_set.all %}
        <li>{{ choice.choice_text }}</li>
    {% endfor %}
    </ul>

    删除模板中硬编码的URLs

    polls/index.html文件中,还有一部分硬编码存在,也就是href里的“/polls/”部分:

    <li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
    

    设想如果你在urls.py文件里修改了路由表达式,那么你所有的模板中对这个url的引用都需要修改,这是无法接受的!

    使用前面给urls定义了一个name别名,可以用它来解决这个问题。具体代码如下

    <li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>

    Django会在polls.urls文件中查找name='detail'的url,具体的就是下面这行:

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

      举个栗子,如果你想将polls的detail视图的URL更换为polls/specifics/12/,那么你不需要在模板中重新修改url地址了,

    仅仅只需要在polls/urls.py文件中,将对应的正则表达式改成下面这样的就行了,所有模板中对它的引用都会自动修改成新的链接:

    # 添加新的单词'specifics'
    path('specifics/<int:question_id>/', views.detail, name='detail'),
    

      

    URL names的命名空间

    本教程例子中,只有一个app也就是polls,但是在现实中很显然会有5个、10个、更多的app同时存在一个项目中。Django是如何区分这些app之间的URL name呢?

    答案是使用URLconf的命名空间。在polls/urls.py文件的开头部分,添加一个app_name的变量来指定该应用的命名空间:

    from django.urls import path
    
    from . import views
    
    app_name = 'polls'
    urlpatterns = [
        path('', views.index, name='index'),
    # ex: /polls/5/
        path('<int:question_id>/', views.detail, name='detail'),
        # ex: /polls/5/results/
        path('<int:question_id>/results/', views.results, name='results'),
        # ex: /polls/5/vote/
        path('<int:question_id>/vote/', views.vote, name='vote'),
    ]

    现在,让我们将代码修改得更严谨一点,将polls/templates/polls/index.html中的

    <li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
    

     修改为

    <li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
  • 相关阅读:
    JQuery
    如何垂直居中一个浮动元素
    Bootstrap概述
    浮动元素的水平居中
    图(Prime算法、 Kruskal算法、Dijkstra算法、Floyd算法、AOV网)
    排序(插入排序、选择排序、交换排序、二路归并排序、基数排序、外部排序)
    实验二 Scala编程初级实践
    数据类型、运算符
    用栈求前缀表达式值
    用栈求后缀表达式地的值
  • 原文地址:https://www.cnblogs.com/xiao-apple36/p/11299700.html
Copyright © 2020-2023  润新知