Django工程搭建

Django工程搭建

1.django依赖module
python -m pip install \
Django==2.0 \
django-cors-headers==2.4.0 \
django-recaptcha==1.5.0 \ \
django-admin-view-permission==1.9 \
django-crontab==0.7.1  \
django-redis==4.11.0 \
-i https://pypi.douban.com/simple
2.创建工程pro1
django-admin startproject pro1
3.创建app应用模块
创建users应用模块
mkdir pro1/apps
cd pro1/apps
python ../manage.py startapp user
配置app模块

在pro1/settings.py中,将对应的app模块添加进去

# Application definition

INSTALLED_APPS = [
  'django.contrib.admin',
  'django.contrib.auth',
  'django.contrib.contenttypes',
  'django.contrib.sessions',
  'django.contrib.messages',
  'django.contrib.staticfiles',
  'apps.users', #用户模块
]
命名路由

使用命名空间定义路由

from django.contrib import admin
from django.urls import path
from django.conf.urls import url, include

urlpatterns = [
  path('admin/', admin.site.urls),
  #使用users命名空间定义users路由
  url(r'^api/v1/users/',include(('apps.users.urls','users'),namespace='users')), 
]

命名空间表示,凡是users.urls中定义的路由,均属于namespace指明的users名下。

命名空间的作用:避免不同应用中的路由使用相同的名称发生冲突,使用命名空间区分开

创建users自己的路由
cat >> apps/users/urls.py << EOF

#!/usr/bin/env python

# -*- coding: utf-8 -*-

from django.conf.urls import url

from apps.users import views

urlpatterns = [
  url(r'^hello/$',views.hello,name='hello'),
]
EOF
测试代码

在apps/users/views.py中添加下面内容

from django import http
# Create your views here.
def hello(request):
    
    # 返回相应
    return http.JsonResponse({'name':'hello'})
启动服务
python manage.py runserver 0.0.0.0:8080

0.0.0.0:设置外部可以访问

显示结果

Django工程搭建_第1张图片

4.redis配置
django项目settings.py文件关于redis的配置
# Redis缓存库配置
CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379/0",
        "OPTIONS": {
            "PASSWORD": "123456",#redis密码
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
            "COMPRESSOR": "django_redis.compressors.zlib.ZlibCompressor",
            "CONNECTION_POOL_KWARGS": {"max_connections": 512},
            "IGNORE_EXCEPTIONS": True,
            "SOCKET_CONNECT_TIMEOUT": 5,  # in seconds
            "SOCKET_TIMEOUT": 5,  # in seconds
        }
    },
    "authority": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379/1",
        "OPTIONS": {
            "PASSWORD": "123456",#redis密码
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
            "COMPRESSOR": "django_redis.compressors.zlib.ZlibCompressor",
            "CONNECTION_POOL_KWARGS": {"max_connections": 512},
            "IGNORE_EXCEPTIONS": True,
            "SOCKET_CONNECT_TIMEOUT": 5,  # in seconds
            "SOCKET_TIMEOUT": 5,  # in seconds
        }
    },
    "feedflow": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379/2",
        "OPTIONS": {
            "PASSWORD": "123456",#redis密码
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
            "COMPRESSOR": "django_redis.compressors.zlib.ZlibCompressor",
            "CONNECTION_POOL_KWARGS": {"max_connections": 512},
            "IGNORE_EXCEPTIONS": True,
            "SOCKET_CONNECT_TIMEOUT": 5,  # in seconds
            "SOCKET_TIMEOUT": 5,  # in seconds
        }
    },
}
封装redis工具类
"""
全局管理缓存的调用,封装django自带的cache
主要用于小数据量的调用
"""
import json
import re
import redis
from contextlib import contextmanager
from functools import reduce
from django.core import signals
from django.core.cache import _create_cache
from django_redis import get_redis_connection


def query_cache(dbname):
    """
    redis 扩展redis 原生 功能用此连接方式
    """
    conn_redis = get_redis_connection(dbname)
    return conn_redis


def get_cache(backend, **kwargs):
    """django-redis 自带方法请用这个"""
    cache = _create_cache(backend, **kwargs)
    signals.request_finished.connect(cache.close)
    return cache


class CacheAdpter():
    @classmethod
    def hset(cls, cache_name, mainkey, subkey, values, second=None):
        """
        单个添加 redis hash 值
        :param cache_name: db
        :param mainkey: 主key
        :param subkey: 子key
        :param second: 不建议设置过期时间,此过期时间针对mainkey设置,对subkey无效
        :return
        CacheAdpter.hmset('authority', CacheKey.AUTHY_CUSTOMER_ROLE, 20, key_1='values_11', key_2='values_662')
        """
        use_cache = query_cache(cache_name)
        use_cache.hset(mainkey, subkey, values)
        if second:
            use_cache.expire(mainkey, second)

    @classmethod
    def hmset(cls, cache_name, mainkey, second=None, **kwargs):
        """
        批量添加 redis hash 值
        :param cache_name: db
        :param mainkey: 主key
        :param **kwargs: 批量subkey
        :param second: 不建议设置过期时间,此过期时间针对mainkey设置,对subkey无效
        :return
        CacheAdpter.hmset('authority', CacheKey.AUTHY_CUSTOMER_ROLE, 20, key_1='values_11', key_2='values_662')
        """
        use_cache = query_cache(cache_name)
        use_cache.hmset(mainkey, kwargs)
        if second:
            use_cache.expire(mainkey, second)
    
    @classmethod
    def hdel(cls, cache_name, mainkey, key):
        """
        删除 redis hash 数据
        :param cache_name: db
        :param mainkey: 主key
        :param subkey: 子key
        :return:
        """
        use_cache = query_cache(cache_name)
        use_cache.hdel(mainkey, key)
    
    @classmethod
    def hget(cls, cache_name, mainkey, subkey, type=False):
        """
        获取 redis hash 数据 扩展redis hash hget 调用
        :param cache_name: db
        :param mainkey: 主key
        :param subkey: 子key
        :return:
        """
        use_cache = query_cache(cache_name)
        result = use_cache.hget(mainkey, subkey)
        # bytes 转 str
        if type:
            return None if result is None else str(result, encoding='utf-8')
        else:
            result = json.loads(result) if result else None
            return result
    
    @classmethod
    def hkeys(cls, cache_name, mainkey, default=None):
        """
        获取主key中所有子key的列表
        :param cache_name: 缓存库
        :param mainkey: 主key
        :return: 返回列表
        """
        default = default if default else []
        use_cache = query_cache(cache_name)
        keys_list = use_cache.hkeys(mainkey)
        if not keys_list:
            return default
        return keys_list
    
    @classmethod
    def get_time_out(cls, cache, timeout):
        """
        设置db 过期时间
        :param cache: db
        :param timeout: 过期时间
        :return:
        """
        if not timeout:
            timeout = cache.default_timeout
        return timeout
    
    @classmethod
    def get(cls, cache_name, key, default=None):
        """
        获取 redis 数据
        :param cache_name: db
        :param key: 主key
        :return:
        """
        use_cache = get_cache(cache_name)
        value = use_cache.get(key)
        if value is None:
            return default
        return value
    
    @classmethod
    def set(cls, cache_name, key, value, timeout=0):
        """
        存储 redis 数据
        :param cache_name :db
        :param key: key
        :param value: values
        :param timeout:设置过期时间 单位秒
        :return:
        """
        use_cache = get_cache(cache_name)
        use_cache.set(key, value, cls.get_time_out(use_cache, timeout))
    
    @classmethod
    def get_many(cls, cache_name, keys, default=None):
        """
        批量获取 redis 数据
        :param cache_name :db
        :param keys: key list []
        :return:
        """
        default = default if default else {}
        use_cache = get_cache(cache_name)
        value_dict = use_cache.get_many(keys)
        if value_dict is None:
            return default
        return value_dict
    
    @classmethod
    def set_many(cls, cache_name, keys, timeout=0):
        """
        批量设置 redis 过期数据
        :param cache_name :db
        :param keys: key list []
        :param timeout 60*24
        :return:
        """
        use_cache = get_cache(cache_name)
        use_cache.set_many(keys, cls.get_time_out(use_cache, timeout))
    
    @classmethod
    def delete(cls, cache_name, key):
        """
        删除  redis set 数据
        :param cache_name :db
        :param key: key
        :return:
        """
        use_cache = get_cache(cache_name)
        use_cache.delete(key)
    
    @classmethod
    def delete_many(cls, cache_name, keys):
        use_cache = get_cache(cache_name)
        for key in keys:
            use_cache.delete(key)
    
    @classmethod
    def get_large_list(cls, cache_name, key):
        use_cache = get_cache(cache_name)
    
        value_list = []
        grp_num = use_cache.get(key)
        if grp_num is None:
            return value_list
    
        keys = [key + '_' + str(i) for i in range(grp_num)]
        value_dict = use_cache.get_many(keys)
        if not value_dict:
            return value_list
        else:
            return reduce(list.__add__, value_dict.values())
    
    @classmethod
    def sadd(cls, cache_name, key, values):
        """
        添加元素到redis集合中,添加多个元素需要封装为可迭代类型
        :param key: 键
        :param values: 值
        :param cache_name: 缓存库
        :return:
        """
        use_cache = query_cache(cache_name)
        if isinstance(values, str or int):
            return use_cache.sadd(key, values)
        return use_cache.sadd(key, *values)
    
    @classmethod
    def smembers(cls, cache_name, key):
        """
        获取缓存中集合的所有元素
        :param key: 键
        :param cache_name: 缓存库
        :return: 以列表返回所有结果
        """
        use_cache = query_cache(cache_name)
        value = use_cache.smembers(key)
        if value:
            return sorted([i.decode() for i in value])
        return None
    
    @classmethod
    def delete_set_key(cls, cache_name, key):
        """
        由于django自带的redis无法删除set(集合)中的键,所以调用此方法
        :param key: 键
        :param cache_name: 缓存库
        :return:
        """
        use_cache = query_cache(cache_name)
        return use_cache.delete(key)
    
    @classmethod
    def incr(cls, cache_name, key, count, timeout=0):
        use_cache = query_cache(cache_name)
        use_cache.incr(key, count)
        if timeout:
            use_cache.expire(key, timeout)
    
    @classmethod
    def get_8origin(cls, cache_name, key, default=None):
        """
        获取 redis 数据, 通过get_redis_connection原生连接获取数据
        :param cache_name: db
        :param key: 主key
        :return:
        """
        use_cache = query_cache(cache_name)
        value = use_cache.get(key)
        result = json.loads(value) if value else default
        return result
    
    @classmethod
    def add(cls, cache_name, key, value, timeout=None):
        """
        当缓存中键不存在时向缓存中写入键值,可以设置有效期
        :param key: 键
        :param value: 值
        :param cache_name: 缓存库
        :param timeout: 有效期时间
        :return:
        """
        use_cache = get_cache(cache_name)
        if isinstance(timeout, int):
            return use_cache.add(key, value, timeout)
        else:
            return use_cache.add(key, value, timeout=cls.get_time_out(use_cache, None))

测试调用
python manage.py shell

开启shell模式,接下来就可以直接对表模型直接进行操作

执行代码

from django_redis import get_redis_connection
conn_redis = get_redis_connection("default")
conn_redis.set("test","test")

显示结果

Django工程搭建_第2张图片

5.mysql配置
在配置文件中增加slave数据库的配置
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql', # 数据库引擎
        'HOST': '127.0.0.1', # 数据库主机
        'PORT': 3306, # 数据库端口
        'USER': 'root', # 数据库用户名
        'PASSWORD': '123456', # 数据库用户密码
        'NAME': 'test' # 数据库名字
    },
    'slave': {
        'ENGINE': 'django.db.backends.mysql', # 数据库引擎
        'HOST': '127.0.0.1', # 数据库主机
        'PORT': 3306, # 数据库端口
        'USER': 'root', # 数据库用户名
        'PASSWORD': '123456', # 数据库用户密码
        'NAME': 'test' # 数据库名字
    }
}
创建数据库操作的路由分发类

在utils中创建db_router.py

class MasterSlaveDBRouter(object):
    """数据库主从读写分离路由"""

    def db_for_read(self, model, **hints):
        """读数据库"""
        return "slave"

    def db_for_write(self, model, **hints):
        """写数据库"""
        return "default"

    def allow_relation(self, obj1, obj2, **hints):
        """是否运行关联操作"""
        return True
配置读写分离路由

在settings.py文件中增加

# 配置读写分离
DATABASE_ROUTERS = ['utils.db_router.MasterSlaveDBRouter']
使用pymysql代替mysqldb连接数据库

在pro1/init.py文件中增加

import pymysql
pymysql.install_as_MySQLdb() #使用pymysql代替mysqldb连接数据库
测试调用
python manage.py shell

开启shell模式,接下来就可以直接对表模型直接进行操作

执行代码

from django.db import connection, transaction
cursor = connection.cursor()
cursor.execute("show tables")
print(cursor.fetchone())
  • django.db.connection,代表了默认的数据库连接,
  • django.db.transaction,代表默认的数据库事务。
  • counnection.cursor,代表默认数据库游标。
  • cursor.execute(sql,[params]),执行sql语句。
  • cursor.fetchone()或cursor.fetchall(),返回查询的结果。
  • transaction.commit_unless_managed(),事务提交,确保数据更改(在更改数据库时使用,如果查询操作没必要使用)

显示结果
Django工程搭建_第3张图片

测试mysql配置问题
import pymysql
conn = pymysql.connect(
    host='127.0.0.1',  # ip
    port=3306,  # 端口
    user='root',  # mysql客户端登陆用户名
    passwd='123456',  # mysql客户端登陆用密码
    charset='utf8',  # 千万不要加-
    # 指定要操作哪个库
    database='meiduo_mall_42'
)  # 链接数据库
# 产生一个游标对象(类似在cmd中登陆mysql客户端后的哪个等待你输命令的闪烁的短下划线)
"""
将查询的结果以字典的形式返回
"""
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
cursor.execute("show tables")
print(cursor.fetchone())
6.错误总结
6.1.路由异常

具体的错误提示为:

 File "", line 1030, in _gcd_import
 File "", line 1007, in _find_and_load
 File "", line 986, in _find_and_load_unlocked
 File "", line 680, in _load_unlocked
 File "", line 850, in exec_module
 File "", line 228, in _call_with_frames_removed
 File "/home/test/Desktop/works/demos/django-pro/pro1/pro1/urls.py", line 25, in <module>
  url(r'^',include('apps.users.urls',namespace='users')), 
 File "/home/test/anaconda3/lib/python3.9/site-packages/django/urls/conf.py", line 38, in include
  raise ImproperlyConfigured(
django.core.exceptions.ImproperlyConfigured: Specifying a namespace in include() without providing an app_name is not supported. Set the app_name attribute in the included module, or pass a 2-tuple containing the list of patterns and app_name instead.

错误示例:

url(r'^',include('apps.users.urls',namespace='users')), 

修改为:

url(r'^',include(('apps.users.urls','users'),namespace='users')), 
6.2.跨域异常

具体的错误提示为:

Exception Value:   

Invalid HTTP_HOST header: '192.168.3.171:8080'. You may need to add '192.168.3.171' to ALLOWED_HOSTS.

settings.py中的

ALLOWED_HOSTS = []

改为

ALLOWED_HOSTS = ['192.168.3.171']

ALLOWED_HOSTS的作用 ALLOWED_HOSTS是用来设置允许哪些主机访问我们的django后台站点

6.3.mysql调用异常
    self.db_table = truncate_name(self.db_table, connection.ops.max_name_length())
  File "/home/test/anaconda3/lib/python3.9/site-packages/django/db/__init__.py", line 33, in __getattr__
    return getattr(connections[DEFAULT_DB_ALIAS], item)
  File "/home/test/anaconda3/lib/python3.9/site-packages/django/db/utils.py", line 202, in __getitem__
    backend = load_backend(db['ENGINE'])
  File "/home/test/anaconda3/lib/python3.9/site-packages/django/db/utils.py", line 110, in load_backend
    return import_module('%s.base' % backend_name)
  File "/home/test/anaconda3/lib/python3.9/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "/home/test/anaconda3/lib/python3.9/site-packages/django/db/backends/mysql/base.py", line 17, in <module>
    raise ImproperlyConfigured(
django.core.exceptions.ImproperlyConfigured: Error loading MySQLdb module.
Did you install mysqlclient?

解决方案,使用pymysql代替mysqldb连接数据库

在pro1/init.py文件中增加

import pymysql
pymysql.install_as_MySQLdb() #使用pymysql代替mysqldb连接数据库

你可能感兴趣的:(python,django,python,后端)