LiveServerTestCase - settings.Database is improperly configured - python

I'm trying to set up a LiveServerTestCase.
For this I'm creating a User within my Testclass with
class ExampleTest(LiveServerTestCase):
user = User.objects.create_superuser('Testuser','test#user.com','1234')
user.save()
.
.
.(rest of the test)
without this line the server and test starts but obviously it can't login because there is no User created before.
But with this line I'm getting a
django.core.exceptions.ImproperlyConfigured: settings.DATABASES
is improperly configured. Please supply the NAME value.
error.
Do I need to set up the Server in settings.py for LiveServerTestCase, and in case yes, with which values or where do I find them?
UPDATE:
I'm running this test with
python manage.py test
so it sets up a database itself which I don't have to define in the settings.py, or am I wrong.
UPDATE2:
I already defined a 'production' database (before I even asked the question), it looks like this:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'HOST': 'localhost', # 10.1.2.41
'NAME': 'pim_testdatabase',
'USER': 'postgres',
'PASSWORD': '1234',
'PORT': '5432',
'HAS_HSTORE': True,
'TEST':{
'NAME': 'test_pim_testdatabase'
},
},
}
Still the exception appears.

You need to set up the database in your DATABASES settings.
Django sets up a test database corresponding to every database that is
defined in the DATABASES definition in your settings file.
By default the test databases get their names by prepending test_ to
the value of the NAME settings for the databases defined in DATABASES.
If you want to use a different database name, specify NAME in the TEST dictionary for any given database in DATABASES.
An example test database configuration:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'USER': 'mydatabaseuser',
'NAME': 'mydatabase',
'TEST': { # test database settings
'NAME': 'mytestdatabase', # test database name
},
},
}

The problem is that you are creating the user in the class definition. This runs when the test class is loaded, before the database has been created.
class ExampleTest(LiveServerTestCase):
user = User.objects.create_superuser('Testuser','test#user.com','1234')
user.save() # This save isn't required -- it has been saved already
You can fix the problem by moving the user creation into an individual test. Then the user will be created when the test method runs, after the database has been created.
class ExampleTest(LiveServerTestCase):
def test_user(self):
self.user = User.objects.create_superuser('Testuser','test#user.com','1234')
...
Django 1.8 has a setUpTestData method where you can set up initial data once for the entire test case. This is quicker, and less repetitive.
class ExampleTest(LiveServerTestCase):
#classmethod
def setUpTestData(cls):
# Set up data for the whole TestCase
self.user = User.objects.create_superuser('Testuser','test#user.com','1234')
def test_user(self):
# access the user with self.user
...
In earlier versions of Django which don't have setUpTestData, you can create the user in the setUp method.
class ExampleTest(LiveServerTestCase):
def setUp(self):
self.user = User.objects.create_superuser('Testuser','test#user.com','1234')

Related

I can connect an application to 2 databases in Django?

I have a web application in Python django. I need to import users and display data about them from another database, from another existing application. All I need is the user to be able to login and display information about them. What solutions are?
You can set 2 DATABASES in settings.py.
DATABASES = {
'default': {
...
},
'user_data': {
...
}
}
Then in one database store User models with authentication and stuff, in another rest information. You can connect information about specific User with a field that is storing id of User from another database.
If you have multiple databases and create a model, you should declare on which db it is going to be stored. If you didn't, it will be in default one (if you have it declared).
class UserModel(models.Model):
class Meta:
db_table = 'default'
class UserDataModel(models.Model):
class Meta:
db_table = 'user_data'
the answer from #NixonSparrow was wrong.
_meta.db_table defined only table_name in database and not the database self.
for switch database you can use manager.using('database_name'), for every model, it is good declared here: https://docs.djangoproject.com/en/4.0/topics/db/multi-db/#topics-db-multi-db-routing
in my project i use multiple router.
https://docs.djangoproject.com/en/4.0/topics/db/multi-db/#topics-db-multi-db-routing
it help don't override every manager with using. But in your case:
DATABASES = {
'default': {
...
},
'other_users_data': {
...
}
}
and somethere in views:
other_users = otherUserModel.objects.using('other_users_data')
Probably, otherUserModel should define in meta, which table you want to use db_table = 'other_users_table_name' and also probably it should have managed=False, to hide this model from migration manager.

Django ORM: How to query secondary database which is in read-only mode and no reference in model.py file

I want to query secondary database which is basically a production database. Currently I am using direct query but want to use ORM.
My current models.py file looks like below. Here user is providing TABLE name. For simplicity consider TABLE is "SERVER_LIST".
from django.db import connections
# Create your models here.
def my_custom_sql(TABLE):
with connections["my_oracle"].cursor() as cursor:
cursor.execute("select * from {0} where server = 'XYZ';".format(TABLE))
row = cursor.fetchall()
return row
Database entry:setttings.py:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': 'mydatabase',
},
'my_oracle': {
'ENGINE': 'django.db.backends.oracle',
'NAME': 'xyz:1234/ABCDB',
'USER': 'ABC',
'PASSWORD': '1234'
},
}
I want to run same query using Django ORM. Can someone help how to connect to secondary database and create models.py file for this database. I refer to this link but it imports model.py file which i dont think is possible in my case as database is already existing and in read-only mode.
Your DATABASES variable in your settings.py file should look something like this:
DATABASES = {
'default': DEFAULT_DB_CONFIG,
'slave': SLAVE_DB_CONFIG,
}
and when you are using ORM and want to query a table, you can use using interface like below:
SampleModel.objects.using('slave').all()
Check documentation: https://docs.djangoproject.com/en/3.0/topics/db/multi-db/

How to Change Django Database schema in a View?

How can I change the database schema from a Django view?
I want the user to select a database field type.
First, settings.py should look something like this:
DATABASES = {
'default': {
'NAME': 'schema_name',
'ENGINE': 'django.db.backends.postgresql',
'USER': 'postgres',
'PASSWORD': 'password'
},
'foo': {
'NAME': 'schema_name',
'ENGINE': 'django.db.backends.mysql',
'USER': 'root',
'PASSWORD': 'password'
},
...
}
Now, in your code, you can manually decide which schema/database to use with the .using method:
SomeModel.objects.using('foo').all() #this uses "foo"
SomeModel.objects.all() #this uses "default"
For more complex logic, you can create a database router do decide which schema to use in a given scenario.
Update
You can execute raw queries by importing connection.
Here is an example create statement:
from django.db import connection
with connection.cursor() as cursor:
sql = '''
CREATE TABLE foo (
col1 INT,
col2 VARCHAR(45)
)'''
cursor.execute(sql)
You should be extremely careful when creating tables using user input. Doing so in an unsafe way can lead to SQL injection and potentially other vulnerabilities like stored xss.

Django: Automatic assignment of primary key in MySql failing

I am following the Effective Django tutorial with the change of using MySql instead of sqlite3.
Following the official recommendation of Django and given that I am working with Python3.4 I am using mysqlclient driver.
I have created the following model as indicated in the tutorial:
class Contact(models.Model):
fName = models.CharField(max_length = 30)
lName = models.CharField(max_length = 100)
eMail = models.EmailField()
def str(self):
return ' '.join([self.fName, self.lName])
db has sync'ed (migrated) ok.Nonetheless, when creating through the shell a contact
a = Contact('John', 'Doe')
and then saving it
a.save()
I get the following error:
ValueError: invalid literal for int() with base 10: 'John'
which does not appear when I provide an explicit integer (taken as primary key???) as first argument
a = Contact(1, 'John', 'Doe')
Why isn't automatic pk assignment working as it should?
I am using Django 1.7.7 / Python 3.4 on virtualenv
Here are the settings:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'addressbook',
'USER': 'abuser',
'PASSWORD': '1234',
'HOST': 'localhost',
'PORT': '3306',
}
}
abuser has been granted all privileges with grant option on the addressbook (as also on the test_addressbook) db
To create a model instance you should use keyword arguments instead of positional:
a = Contact(fName='John', lName='Doe')
a.save()

Running Django unittests causes South migrations to duplicate tables

How do you prevent Django unittests from running South migrations?
I have a custom Django app, myapp, that I'm trying to test with manage.py test myapp but when I run it I get the error:
django.db.utils.OperationalError: table "myapp_mymodel" already exists
and sure enough, the traceback shows that South is being executed:
File "/usr/local/myproject/.env/local/lib/python2.7/site-packages/south/management/commands/test.py", line 8, in handle
super(Command, self).handle(*args, **kwargs)
However, in my settings, I've specified:
SOUTH_TESTS_MIGRATE = 0
SKIP_SOUTH_TESTS = 1
which I believe should prevent Django's test framework from executing any South components.
What am I doing wrong?
Edit: I worked around this by simply removing south with:
if 'test' in sys.argv:
INSTALLED_APPS.remove('south')
However, then I got:
ImproperlyConfigured: settings.DATABASES is improperly configured. Please supply the NAME value.
For my test database settings, I was using:
DATABASES = {
'default':{
'ENGINE': 'django.db.backends.sqlite3'
}
}
which worked fine in Django 1.4. Now I'm using Django 1.5, and I guess that's not kosher. However, no NAME value I see it to fixes it. They all report none of my tables exist. I've tried:
DATABASES = {
'default':{
'ENGINE': 'django.db.backends.sqlite3',
'NAME': '/dev/shm/test.db',
'TEST_NAME': '/dev/shm/test.db',
}
}
DATABASES = {
'default':{
'ENGINE': 'django.db.backends.sqlite3',
'NAME': ':memory:',
'TEST_NAME': ':memory:',
}
}
DATABASES = {
'default':{
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(os.path.dirname(__file__), 'test.db'),
'TEST_NAME': os.path.join(os.path.dirname(__file__), 'test.db'),
}
}
each seems to create a physical test.db file, which I don't understand, because unittests should be run in-memory. It should never save anything to disk. Presumably, it's failing to run syncdb after creating the file but before it executes the actual unittest. How do I fix this?
Edit: I discovered that, in one of my forms, I was populating field choices by directly querying a model (whereas I should have been doing that inside the form's init), so when Django's test framework imported my model, it was trying to read the table before the sqlite3 database had been created. I fixed that, but now I'm getting the error:
DatabaseError: table "myapp_mythroughmodel" already exists
so I'm back to square one, even though it's throwing a different exception type than initially.
Edit: I had a duplicate through model defined, causing Django to attempt to create it twice, resulting in the error.
This also happened to me with a legacy code but for another reason.
I had two models with db_table referencing the same db table.
I know that is stupid, but it's not my fault )
And I never found anything on the internet that could help me.
I was saved by verbosity set to 3 (manage.py test -v 3)
Hope this helps anyone.
class Bla1(Model):
some_column = ...
class Meta:
db_table = 'some_table'
class Bla2(Model):
some_column = ...
class Meta:
db_table = 'some_table'
This error was the result of several problems. I'll summarize them here to help others who may have stumbled across this.
Ensure your settings.DATABASES is set correctly. Django's docs mention using TEST_NAME, but for clarity, I find it easier to check for the test command and override everything. e.g. at the bottom of my settings.py, I have:
if 'test' in sys.argv:
DATABASES = {
'default':{
'ENGINE': 'django.db.backends.sqlite3',
'NAME': ':memory:',
},
}
Unless you have a good reason, always use :memory: to ensure it runs in memory and doesn't create a physical file that will be bogged down on disk. For some odd reason, a lot of other answers on SO recommend specifying a literal path to a test.db file for testing. This is horrible advice.
Unless you want to test South and/or your South migrations, disable South, because it'll only complicate things:
SOUTH_TESTS_MIGRATE = False
SKIP_SOUTH_TESTS = True
Don't be dumb like me and try to access your models before they're created. This mostly means don't directly refer to models from the fields of other models or forms. e.g.
class MyForm(forms.Form):
somefield = forms.ChoiceField(
required=True,
choices=[(_.id, _.name) for _ in OtherModel.objects.filter(criteria=blah)],
)
This might work in code where your database already exists, but it'll break Django's unittest framework when it tries to load your tests, which load your models.py and forms.py, causing it to read a table that doesn't exist. Instead, set the choices value in the form's __init__().

Categories