I am developing an E-commerce website using Python 3.6. I made a fresh installation of Django 2.0.6 and connected it to a MySQL database (on the localhost) by defining the Database variables in settings.py as below:
DATABASES = {
'default': {
'ENGINE' : 'django.db.backends.mysql',
'NAME' : 'moda',
'OPTIONS' : {
'init_command' : "SET sql_mode='STRICT_TRANS_TABLES'",
'init_command' : 'SET innodb_strict_mode=1',
'charset' : 'utf8mb4',
},
'USER' : 'root',
'PASSWORD' : '',
'SERVER' : 'localhost',
'PORT' : '3306'
}
}
and after running the python manage.py check command using cmd, I am getting the following warning:
(django_mysql.W001) MySQL Strict Mode is not set for database connection 'default'
HINT: MySQL's Strict Mode fixes many data integrity problems in MySQL, such as data truncation upon insertion, by escalating warnings into errors. It is strongly recommended you activate it. See: https://django-mysql.readthedocs.io/en/latest/checks.html#django-mysql-w001-strict-mode
I even used ' init_command': "SET sql_mode='STRICT_TRANS_TABLES'", and I'm still getting the warning!
I would be so grateful if some expert could show me the right way to fix this!
Thanks Guys.
Author of django-mysql here.
You have two 'init_command' keys in the dictionary, so only the second one will be in there after parsing - Python just silently handles duplicates like this. Hint: use flake8 to lint your source code, as it detects this and warns you.
Additionally, the two SET commands can be combined, giving:
...
'OPTIONS': {
'init_command': "SET sql_mode='STRICT_TRANS_TABLES', innodb_strict_mode=1",
'charset': 'utf8mb4',
},
...
HTH!
Related
I have two databases configured in my app:
DATABASES = {
'default': { ... }
'legacy': { ... }
}
The legacy database is only used in a particular part of the app (I've added it as a second database for convenience).
This works fine, except that when I try to run tests, Django tried to create a test database for the legacy database, causing an error:
Got an error creating the test database: (1044, "Access denied for user ... to to database 'test_...'")
How can I tell Django not to create a test database for the second legacy database?
I thought setting the following would work:
DATABASES['legacy']['TEST'] = {
'NAME': None,
'CREATE_DB': False
}
but that doesn't seem to help
Seems looks like a common issue with multiples databases and testing in Django. Here is the way I generally deal with it.
DATABASES = {
'default': { ... }
'legacy': { ... }
}
# You can add here any other type of control (not prod, debug == True, etc.)
if "test" in sys.argv:
del DATABASES["legacy"]
# Or
DATABASES = { "default": DATABASES["default"] }
This works great in the case you have only one setting file, you can easily adapt for other cases.
If you are handling many databases another option could be to start from the ground up inside your tests settings:
DATABASES = {
'default': { ... }
'legacy': { ... }
}
# You can add here any other type of control (not prod, debug == True, etc.)
if "test" in sys.argv:
DATABASES = {"default": {}}
DATABASES["default"]["ENGINE"] = "django.db.backends.sqlite3"
# Etc... Add want you need here.
In flask the configuration module is pretty-straight forward and there are ample best practices on the same topic from internet.
If I had to develop an Application which supports multiple instances, for example lets say there is a database for every city supported by application and every city db is independent MongoDB instance hosted on different physical machines.
A sample API code to support my example:
from flask import Flask, request
from flask_restful import Resource, Api
app = Flask(__name__)
api = Api(app)
class CityPopulation(Resource):
def get(self, city_name):
'''
CODE TO GET CITY BASED DB Config
Currently in JSON format
'''
total_population = helper_city(city_name)
return { population : total_population }
api.add_resource(CityPopulation, '/<string:city_name>/population')
if __name__ == '__main__':
app.run(debug=True)
Currently what I've thought about is a json file with section for DB's as below
{
db:[{
'bengaluru' :{
'host' : 'bengaluru.host.db'
'port' : 27017,
'user_name' : 'some_user',
'password' : 'royalchallengers'
},
'hyderabad' :{
'host' : 'hyderabad.host.db'
'port' : 27017,
'user_name' : 'some_user',
'password' : 'sunrisers'
}
}]
}
and the class to read the configuration from JSON as
class project_config:
def __init__(self):
with open(config_full_path, 'r') as myfile:
configuration_raw = json.load(myfile)
In Flask, the config module best practices was suggested as below
class BaseConfig(object):
DEBUG = False
TESTING = False
class DevelopmentConfig(BaseConfig):
DEBUG = True
TESTING = True
class TestingConfig(BaseConfig):
DEBUG = False
TESTING = True
Is there a way for my scenario to be included the flask configuration and not to maintain a separate project configuration? In terms of best practices.
The object based config in the flask docs is described an "an interesting pattern" but it's just one approach, not necessarily best practice.
You can update the contents of app.config in any way that makes sense for your use case. You could fetch values at run time from a service like etcd, zookeeper, or consul, or set them all via environment variables (a useful pattern with containerized apps), or load them from a config file like this.
import os
import json
from flask import Flask
from ConfigParser import ConfigParser
app = Flask(__name__)
def load_config():
config = ConfigParser()
config.read(os.environ.get('MY_APP_CONFIG_FILE'))
for k, v in config.items('my_app'):
app.config[k] = v
#app.route('/')
def get_config():
return json.dumps(dict(app.config), default=str)
load_config()
And then run it like:
$ cat test.ini
[my_app]
thing = stuff
other_thing = junk
$ MY_APP_CONFIG_FILE=test.ini FLASK_APP=test.py flask run
$ curl -s localhost:5000 | jq '.'
{
"JSON_AS_ASCII": true,
"USE_X_SENDFILE": false,
"SESSION_COOKIE_SECURE": false,
"SESSION_COOKIE_PATH": null,
"SESSION_COOKIE_DOMAIN": null,
"SESSION_COOKIE_NAME": "session",
"LOGGER_HANDLER_POLICY": "always",
"LOGGER_NAME": "test",
"DEBUG": false,
"SECRET_KEY": null,
"EXPLAIN_TEMPLATE_LOADING": false,
"MAX_CONTENT_LENGTH": null,
"APPLICATION_ROOT": null,
"SERVER_NAME": null,
"PREFERRED_URL_SCHEME": "http",
"JSONIFY_PRETTYPRINT_REGULAR": true,
"TESTING": false,
"PERMANENT_SESSION_LIFETIME": "31 days, 0:00:00",
"PROPAGATE_EXCEPTIONS": null,
"TEMPLATES_AUTO_RELOAD": null,
"TRAP_BAD_REQUEST_ERRORS": false,
"thing": "stuff", <---
"JSON_SORT_KEYS": true,
"JSONIFY_MIMETYPE": "application/json",
"SESSION_COOKIE_HTTPONLY": true,
"SEND_FILE_MAX_AGE_DEFAULT": "12:00:00",
"PRESERVE_CONTEXT_ON_EXCEPTION": null,
"other_thing": "junk", <---
"SESSION_REFRESH_EACH_REQUEST": true,
"TRAP_HTTP_EXCEPTIONS": false
}
db_conn.j2:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'db_name',
'USER': 'db_user',
'PASSWORD': 'db_pass',
'HOST': 'localhost',
'PORT': '5432',
}
}
main.yml:
tasks:
- name: Set DB settings
template: src="/vagrant/ansible/templates/db_settings.j2" dest="{{ proj_dev }}/proj/settings.py"
tags:
- template
In my task file settings.py will be replaced on db_conn.j2.
But i need to change only DATABASES option in destination file (settings.py).
Can i do this via template? Or better use replace?
Is there other way in ansible for set django-settings?
The template module will override the complete file. There is no option to only replace a specific section. That's the idea of a template.
You could move the DATABASES section out to another file, and then from database.py import *, but then of course you'd have the same problem: You need to replace the DATABASES section with the import rule.
So yes, the replace module or the lineinfile module are generally better suited to replace a section of a file.
But you're lucky, Stouts has created a django role:
You can install it in your project with:
ansible-galaxy install Stouts.django
The blockinfile module introduced in Ansible 2.0 does exactly what you want. It will create and manage a block with special starting and ending marks ("BEGIN/END ANSIBLE MANAGED BLOCK" by default) in your file.
I'm running into an issue that South creates the DB table for a new model as INNODB when I migrate but creates the table as MYISAM when another developer runs their own migration.
The problem with this is that all my other tables are MYISAM so using the new tables leads to many foreign key constraint errors.
How can I explicitly make sure the table is created using MYISAM?
What could be causing the table to be created using a different storage engine in different environments?
To be sure that all migrations are always done using INNODB, you should set the storage engine as INNODB in the database definition directly, like thisĀ :
DATABASES = {
'default': {
...
'OPTIONS' : { 'init_command' : 'SET storage_engine=INNODB', },
}
If you are using MySQL 5.7.x and above,
DATABASES = {
'default': {
...
'OPTIONS' : { 'init_command' : 'SET default_storage_engine=INNODB', },
}
But you should know that it can have a performance hit. So you may want to set this option only when running migrations.
If you use South, you can set the STORAGE_ENGINE.
django < 1.2
# add to your settings file
DATABASE_STORAGE_ENGINE = 'INNODB' # django < 1.2
django >= 1.2
# add to your settings file
DATABASES = {
'default': {
...
'STORAGE_ENGINE': 'INNODB'
}
}
I'm specifying the databases using a python object:
DATABASES = {
'default':{
'ENGINE':'mysql',
'NAME':'testsqldb',
'USER':'<username>',
'PASSWORD':'<password>',
},
'dynamic_data':{
'ENGINE': 'sqlite3',
'NAME':'',
'USER':'',
'PASSWORD':''
},
}
How can I specify the name of my test database? I've been trying to use TEST_NAME = 'auto_tests' in the settings.py file. However, when I run python manage.py tests <app_name> I get the following message:
Creating test database 'default'...
Got an error creating the test database: (1007, "Can't create database 'test_testsqldb'; database exists")
Type 'yes' if you would like to try deleting the test database 'test_testsqldb', or 'no' to cancel:
I'm expecting the system to create a separate database when running my tests, presumably called 'auto_tests_testsqldb'; however, it's still asking me about test_testsqldb.
Any advice is appreciated!
In Django 1.6 and below, TEST_NAME should be a key of one of your database dictionaries. But in Django 1.7 and above, you use a TEST key which is a dictionary of settings for test databases.
You probably want:
DATABASES = {
'default':{
'ENGINE':'mysql',
'NAME':'testsqldb',
'USER':'<username>',
'PASSWORD':'<password>',
'TEST': {
'NAME': 'auto_tests',
}
},
'dynamic_data':{
'ENGINE': 'sqlite3',
'NAME':'',
'USER':'',
'PASSWORD':''
},
}
Alternatively, perhaps you are wanting to use a different engine for your tests? In that case, I think you'll just have to create a separate settings file for testing. It can import from your standard settings module and override DATABASES.