Django学习1-环境配置、创建模型、QuerySet

Django

django是一个web框架,是一套用于帮助开发交互式网站的工具。和flask一样,Django采用了MVC的软件设计模式,即模型M,视图V和控制器C。
使用的环境:ubuntu18.04+Django2.1.2+python3.6,pycharm集成开发平台。

虚拟环境配置

使用python的venv模块创建虚拟模块。也可以在pycharm中创建project时选择使用virtualenv虚拟环境。

$ sudo apt install python3-venv

使用venv模块创建虚拟环境。

$ python3 -m venv venv

激活虚拟环境,运行activate脚本。

$ source venv/bin/activate

环境处于活动状态时,环境名包含(venv)标识。执行deactivate命令,停止使用虚拟环境

(venv) ulysses@ulysses:~/PycharmProjects/django_ulysses$ deactivate
ulysses@ulysses:~/PycharmProjects/django_ulysses$

安装Django: pip install django

创建项目

在虚拟环境下运行 django-admin startproject learning_log创建learning_log项目,Django创建了一个名为manage.py的文件。它接受命令并将其交给Django的相关部分去执行。

(venv) ulysses@ulysses:~/PycharmProjects/django_ulysses$ ls
learning_log_django  manage.py  venv

查看django-admin的源码:

#!/usr/bin/env python
from django.core import management

if __name__ == "__main__":
    management.execute_from_command_line()

表明django-admin.py是从命令行接受命令并执行,查看其所有命令:

ulysses@ulysses:~/PycharmProjects/django_ulysses$ django-admin.py

Type 'django-admin.py help <subcommand>' for help on a specific subcommand.

Available subcommands:

[django]
    check
    compilemessages
    createcachetable
    dbshell
    diffsettings
    dumpdata
    flush
    inspectdb
    ...省略...

在创建的manage.py中:

#!/usr/bin/env python
import os
import sys

if __name__ == '__main__':
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'learning_log_django.settings')
    try:
        from django.core.management import execute_from_command_line
    except ImportError as exc:
        raise ImportError(
            "Couldn't import Django. Are you sure it's installed and "
            "available on your PYTHONPATH environment variable? Did you "
            "forget to activate a virtual environment?"
        ) from exc
    execute_from_command_line(sys.argv)

可以看到也是使用execute_from_command_line()来执行命令。
在创建的项目文件中包含四个文件,

  • learning_log_django/ _ init_.py: 一个空文件,告诉 Python 该目录是一个 Python 包。
  • learning_log_django/settings.py: 该 Django 项目的设置/配置。
  • learning_log_django/urls.py: 该 Django 项目的 URL 声明; 一份由 Django 驱动的网站"目录"。
  • learning_log_django/wsgi.py: 一个 WSGI (Web Server Gateway Interface:服务器网关接口)兼容的 Web 服务器的入口,以便运行项目。

创建数据库

使用python3 manage.py migrate命令为项目创建数据库,Django会为我们创建一个名为db.sqlite3的文件,SQLite是一种使用单个文件的数据库。之后数据库发生修改后,运行mkmigrations命令进行迁移数据库。

运行项目

执行runserver命令

ulysses@ulysses:~/PycharmProjects/django_ulysses$ python3 manage.py runserver
Performing system checks...

System check identified no issues (0 silenced).
October 19, 2018 - 06:51:07
Django version 2.1.2, using settings 'learning_log_django.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

可以看到项目使用的配置文件learning_log_django.settings。项目在本机的8000端口上监听请求。

创建应用程序

在项目中运行startapp命令创建名为learning_logs的应用,Django会创建一些基础设施。

(venv) ulysses@ulysses:~/PycharmProjects/django_ulysses$ python3 manage.py startapp learning_logs
(venv) ulysses@ulysses:~/PycharmProjects/django_ulysses$ cd learning_logs
(venv) ulysses@ulysses:~/PycharmProjects/django_ulysses/learning_logs$ ls
admin.py  apps.py  __init__.py  migrations  models.py  tests.py  views.py

创建模型Topic

在model.py创建应用的模型Topic:CharField对应sql中的varchar 类型DateTimeField就对于sql中的datetime类型

from django.db import models

# Create your models here.
class Topic(models.Model):
    text = models.CharField(max_length=20)
    date_added = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.text

在flask中使用flask-sqlalchemy扩展建立模型,而在Django中django.db.models提供了高层的ORM来建立模型。通常一个模型类就映射数据库中的一张数据表。
django.db.models所有映射的数据类型:

__all__ = [
    'AutoField', 'BLANK_CHOICE_DASH', 'BigAutoField', 'BigIntegerField',
    'BinaryField', 'BooleanField', 'CharField', 'CommaSeparatedIntegerField',
    'DateField', 'DateTimeField', 'DecimalField', 'DurationField',
    'EmailField', 'Empty', 'Field', 'FieldDoesNotExist', 'FilePathField',
    'FloatField', 'GenericIPAddressField', 'IPAddressField', 'IntegerField',
    'NOT_PROVIDED', 'NullBooleanField', 'PositiveIntegerField',
    'PositiveSmallIntegerField', 'SlugField', 'SmallIntegerField', 'TextField',
    'TimeField', 'URLField', 'UUIDField',
]

激活模型

要使用创建的模型需要在上文提到的setting.py中添加新创建的应用。
将创建的learning_logs应用添加到INSTALLED_APPS列表中。

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # 创建的应用
    'learning_logs'
]

创建新模型后创建一个数据迁移:

(venv) ulysses@ulysses:~/PycharmProjects/django_ulysses$ python3 manage.py makemigrations learning_logs
Migrations for 'learning_logs':
  learning_logs/migrations/0001_initial.py
    - Create model Topic

在learning_logs/migrations目录下会生成对应的0001_initial.py的迁移文件,
它会在数据库中生成名为Topic的数据表。在模型中没有声名主键(primary_key=True)时,Django自动为这个表添加了一个id字段并声名为主键。

class Migration(migrations.Migration):

    initial = True

    dependencies = [
    ]

    operations = [
        migrations.CreateModel(
            name='Topic',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('text', models.CharField(max_length=20)),
                ('date_added', models.DateTimeField(auto_now_add=True)),
            ],
        ),
    ]

之后应用这个迁移,执行migrate命令Django会修改对应的数据库:

(venv) ulysses@ulysses:~/PycharmProjects/django_ulysses$ python3 manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, learning_logs, sessions
Running migrations:
  Applying learning_logs.0001_initial... OK

修改数据库的过程:

  1. 修改应用下的models;
  2. 对应用执行makemigrations: python manage.py makemigrations [appname]
  3. Django迁移数据库:python manage.py migrate

Django 管理网站

Django最为强大的部分就是自带了一个高度自动化的admin site。在setting.py 的INSTALLED_APPS可以看到项目已经包含了admin应用模块:

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',

在urls.py中已经添加了admin的路由:

urlpatterns = [
    path('admin/', admin.site.urls),
]

runserver 启动应用,访问http://127.0.0.1:8000/admin/, 可以看到Django自带的admin site网站管理。
在这里插入图片描述

注册超级用户

权限决定了用户可执行的操作,超级用户具有所有权限。
使用createsuperuser命令创建超级用户

(venv) ulysses@ulysses:~/PycharmProjects/django_ulysses$ python3 manage.py createsuperuser
Username (leave blank to use 'ulysses'): 
Email address: 
Password: 
Password (again): 

可以使用changepassword username修改用户的密码。

向admin site注册模型

Django自动在管理网站添加了User和Group,为了让 admin 界面管理应用创建的数据模型,需要先注册该数据模型到 admin。在应用目录下的admin.py中注册模型Topic:

from django.contrib import admin
from .models import Topic
# Register your models here.

admin.site.register(Topic)

处于development 模式下修改文件后,Django会自动重启应用。在admin界面可以看到新添加的Topic模块:
在这里插入图片描述

点击add添加新的topic,在管理页面上可以修改或删除Topic。
在这里插入图片描述

模型Post

同一Topic下发表生成不同的Post,每篇文章都要与特定的主题相联。

class Post(models.Model):
    """同一Topic下的多篇文章"""
    # many to one relationship
    topic = models.ForeignKey(Topic, on_delete=models.CASCADE, verbose_name='the related topic')
    text = models.TextField('post content')
    date_added = models.DateTimeField(auto_now_add=True)

    class Meta:
        verbose_name_plural = 'posts'
        
    def __str__(self):
        return  self.text[:50] + '...'

每个字段(除ForeignKeyManyToManyFieldOneToOneField外 )的第一个位置都可以添加一条冗余名称verbose_name,没有设置时默认为字段名称。Django提供了3种最常用的数据表关系:

  • 多对一:类似汽车与制造商的关系:一辆汽车只有唯一一个制造商, 一个制造商下有多量汽车。在汽车(的那端)使用models.ForeignKey,指定与之关联的那个表和字段(类);
  • 多对多:课程与学生的关系,:一个学生选修多门课程,一门课程下有多名学生。使用ManyToManyField (, through='Membership')来指定一个intermediary model关系表来连接课程与学生的关系。
  • 一对一:一一对应的关系,使用OneToOneField
    元数据Meta,存储用于管理模型的额外信息,如verbose_name的复数表现形式verbose_name_plural,用于排序的ordering
    模型创建完后,迁移数据库。

Django shell 和QuerySet API

Django提供了交互式终端会话shell,以编程的方式查看数据或运行指令。

(venv) ulysses@ulysses:~/PycharmProjects/django_ulysses$ python3 manage.py shellPython 3.6.6 (default, Sep 12 2018, 18:26:19) 
[GCC 8.0.1 20180414 (experimental) [trunk revision 259383]] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from learning_logs.models import Topic
>>> Topic.objects.all()
<QuerySet [<Topic: 万事无如退步人>]>
>>> Topic.objects.create(text='古典艺术')
<Topic: 古典艺术>
>>> Topic.objects.get(text='古典艺术')
<Topic: 古典艺术>

在admin site界面下可以看到数据被添加了
在这里插入图片描述
QuerySet API

创建对象
1. Person.objects.create(name=name,age=age)
2. p = Person(name="WZ", age=23)
 	p.save()
3. p = Person(name="TWZ")
	p.age = 23
	p.save()
4.	Person.objects.get_or_create(name="WZT", age=23)

这种方法是防止重复很好的方法,但是速度要相对慢些,返回一个元组,第一个为Person对象,第二个为True或False, 新建时返回的是True, 已经存在时返回False.

获取对象
1. Person.objects.all() # 获取所有对象
2. Person.objects.all()[:10] # 切片操作,获取10个人,不支持负索引,切片可以节约内存
3. Person.objects.get(name=name) # 根据指定条件索引对象
筛选
1. Person.objects.filter(name="abc")  # 等于
2. Person.objects.filter(name__exact="abc") #名称严格等于 "abc" 的人
3. Person.objects.filter(name__iexact="abc")  # 名称为 abc 但是不区分大小写,可以找到 ABC, Abc, aBC,这些都符合条件
4. Person.objects.filter(name__contains="abc")  # 名称中包含 "abc"的人
5. Person.objects.filter(name__icontains="abc")  #名称中包含 "abc",且abc不区分大小写
6. Person.objects.filter(name__regex="^abc")  # 正则表达式查询
7. Person.objects.filter(name__iregex="^abc")  # 正则表达式不区分大小写
去重复

  执行select distinct语句

1. >>> Author.objects.distinct()
[...]
2. >>> Entry.objects.order_by('author', 'pub_date').distinct('author')
[...]
排除
1. Person.objects.exclude(name__contains="WZ")  # 排除包含 WZ 的Person对象
2. Person.objects.filter(name__contains="abc").exclude(age=23)  # 找出名称含有abc, 但是排除年龄是23岁的
排序
Author.objects.all().order_by('name')
Author.objects.all().order_by('-name') # 在 column name 前加一个负号,可以实现倒序
负索引

QuerySet不支持负索引

1. 使用 reverse() 解决
    Person.objects.all().reverse()[:2] # 最后两条
    Person.objects.all().reverse()[0] # 最后一条

2. 使用 order_by,在栏目名(column name)前加一个负号

    Author.objects.order_by('-id')[:20] # id最大的20条
删除、更新

删除符合条件的结果:

Person.objects.filter(name__contains="abc").delete() # 删除 名称中包含 "abc"的人
 或
people = Person.objects.filter(name__contains="abc")
people.delete()

更新某个内容:
(1) 批量更新,适用于 .all() .filter() .exclude() 等后面 (危险操作,正式场合操作务必谨慎)

Person.objects.filter(name__contains="abc").update(name='xxx') # 名称中包含 "abc"的人 都改成 xxx
Person.objects.all().delete() # 删除所有 Person 记录

(2) 单个 object 更新,适合于 .get(), get_or_create(), update_or_create() 等得到的 obj,和新建很类似。

twz = Author.objects.get(name="WeizhongTu")
twz.name="WeizhongTu"
twz.email="tuweizhong@163.com"
twz.save() 
values

  获取所有字段的值,执行select *语句:

# This list contains a Blog object.
>>> Blog.objects.filter(name__startswith='Beatles')
<QuerySet [<Blog: Beatles Blog>]>

# This list contains a dictionary.
>>> Blog.objects.filter(name__startswith='Beatles').values()
<QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]>
annotate

  使用提供的查询表达式列表注释QuerySet中的每个对象。annotate()的每个参数都是一个注释,将添加到返回的QuerySet中的每个对象。

>>> from django.db.models import Count
>>> q = Topic.objects.annotate(Count('post'))
# The name of the first topic
>>> q[0].text
'天-剑'
# The number of posts on the first topic
>>> q[0].post__count
1
>>> q[3].post__count
0

使用fake随机生成数据

在应用下创建 fake.py,使用faker模块自动生成数据

"""用于生成虚拟topic 和 post"""
from random import randint
from faker import Faker
from .models import Topic, Post

def topics(count=100):
    print(f"count={count}")
    fake = Faker()
    i = 0
    while i < count:
        t = Topic(id=i, text=fake.text())
        t.save()
        i = i + 1

def posts(count=100):
    fake = Faker()
    i = 0
    topic_count = Topic.objects.count()
    for i in range(count):
        # 在随机Topic下生成Post
        count_1 = randint(0, topic_count-1)
        print(f"topic_id:{count_1}")
        t = Topic.objects.get(id=count_1)
        print(t)
        p = Post(id=i, text=fake.text(), topic=t)
        p.save()

外键获取数据

为通过外键获取数据,可使用相关模型的小写名称,下划线和单词set:

>>> t = Topic.objects.get(id=8)
>>> t.post_set.all()
<QuerySet [<Post: Piece check system kind sister if listen. Among mo...>, <Post: Various sport director area. Up receive real stree...>, <Post: Rise star stay heavy say today rich born.
Board wh...>]>
>>>      

在管理界面可以看到自动生成的数据:
在这里插入图片描述
部分内容参考https://code.ziqiangxuetang.com/django/django-tutorial.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值