Django - populate table on startup with known values - django

I have a Dog Model that have a "dog_type" field. i want the dog_type to be chosen from a list of pre-defined dog types, i DO NOT want to use a textfield with choices but a ForeignKey to a "DogType" Model. How could I populate the DogType Model with types on server startup? is this a good practice or a hack?
thanks.
code:
class Dog(Model):
name = CharField(...)
dog_type = ForeignKey(DogType)
class DogType(Model):
type_name = CharField(...)
type_max_hight = IntegerField(...)
etc....

You'll probably want to write a data migration that will add your choices in database.
Advantages of using this approach is that the data will be loaded in all your databases (production, dev, etc.)
(If you're not using migrations yet, you should consider it, it's a clean and well-supported way to manage your database)
In your django project, just run python manage.py shell makemigrations myapp --empty. This will create an empty migration file under myapp/migrations.
You can then edit it:
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
DEFAULT_DOG_TYPES = (
('Labrador', 90),
('Berger Allemand', 66),
('Chihuaha', -2),
)
def add_dog_types(apps, schema_editor):
DogType = apps.get_model('myapp', 'DogType')
for name, max_height in DEFAULT_DOG_TYPES:
dog_type = DogType(name=name, max_height=max_height)
dog_type.save()
def remove_dog_types(apps, schema_editor):
# This is used to migrate backward
# You can remove your dog types, or just pass
# pass
for name, max_height in DEFAULT_DOG_TYPES:
dog_type = DogType.objects.get(name=name, max_height=max_height)
dog_type.delete()
class Migration(migrations.Migration):
dependencies = [
# if you're already using migrations, this line will be different
('myapp', '0001_initial'),
]
operations = [
migrations.RunPython(add_dog_types, remove_dog_types),
]
After that, all you need to do is to run python manage.py syncdb.

not so far after, i found this it's called "fixtures"...
basically what you need to do is to place a "fixture" file in a format of your choice (JSON\YAML...) "myapp/fixtures/" for example, a JSON file would look like this:
[
{
"model": "myapp.person",
"pk": 1,
"fields": {
"first_name": "John",
"last_name": "Lennon"
}
},
{
"model": "myapp.person",
"pk": 2,
"fields": {
"first_name": "Paul",
"last_name": "McCartney"
}
}
]
then simply run from the command line:
python manage.py loaddata <filename> # file with no path!

Related

django dumpdata command throws doesnot exist error

I am trying to add some default/fixed values to postgres database and came across fixtures.
My model is like this
app/models.py
class Category(models.Model):
category = models.CharField(max_length=255)
def __str__(self):
return self.category
app/fixtures/category.json
[
{
"model": "core.category",
"pk": 1,
"fields": {
"category": "foo"
}
]
However, I am getting the following error when I run manage.py dumpdata
[CommandError: Unable to serialize database: cursor "_django_curs_139823939079496_sync_1" does not exist
It looks like you have json file already (serialize, means that your django models data has been translated already to json format) you just need to to migrate your data into a new database(you say postgres), try to run these few lines of codes NOTE: I used python3 because I am using macbook pro:-
python3 manage.py migrate
OR
python3 manage.py migrate --run -syncdb
Then, enter your django shell and delete all contenttypes:
>>> from django.contrib.contenttypes.models import ContentType
>>> c = ContentType.objects.all()
>>> c.delete()
(55, {'auth.Permission': 44, 'contenttypes.ContentType': 11})
>>> exit()
python3 manage.py loaddata datadump.json
After being notified that all contenttypes has been deleted, You need to ensure that those data will be displayed in your templates. Simply by loading them from from your json file as shown above.*

Django test database requires Postgres Extension enabled

I have a Django app which requires Postgres' fuzzystrmatch extension to be enabled on the database.
Django's unittest framework creates and destroys a new database. I need this new database to have the extension turned on for testing.
I can use './manage.py test --keepdb' to keep the database and then manually turn on the extension, but this is an ineloquent solution.
Any idea how I can enable this extension programmatically?
Create an empty migration and use the CreateExtension operation:
from django.contrib.postgres.operations import CreateExtension
class Migration(migrations.Migration):
...
operations = [
CreateExtension(name='fuzzystrmatch'),
...
]
Relevant docs
Edit:
If that doesn't work, reviewing how Django actually handles those classes internally would be my next suggestion.
In case you've disabled the migrations in the test settings, the migrations will not be run, so you can't use django CreateExtension.
Example:
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": "test-database",
"USER": "username",
"PASSWORD": "password",
"HOST": "postgresql-host",
"PORT": "5432",
"TEST": {
"MIGRATE": False,
},
},
}
In this case you can manually call SQL code to create the extension.
If you use unitest, you can for example create a custom TestCase class inherited by all your tests like so:
from django.test import TestCase from django.db import connection
class PostgresExtensionTestCase(TestCase):
#classmethod
def setUpClass(cls):
with connection.cursor() as cursor:
cursor.execute("CREATE EXTENSION IF NOT EXISTS unaccent;")
super().setUpClass()
If you use pytest, you can create a fixture in your conftest.py like so (for unaccent in the example):
from django.db import connection
#pytest.fixture(autouse=True)
def activate_postgresql_unaccent():
with connection.cursor() as cursor:
cursor.execute("CREATE EXTENSION IF NOT EXISTS unaccent;")

How to add superuser in Django from fixture

How to add SUPERuser(not just user) through Django fixtures?
Let's say I wanna have login:admin, password:admin.
solution 1
On empty database:
python manage.py createsuperuser
python manage.py dumpdata auth.User --indent 4 > users.json
and in users.json You have needed fixtures.
solution 2
./manage.py shell
>>> from django.contrib.auth.hashers import make_password
>>> make_password('test')
'pbkdf2_sha256$10000$vkRy7QauoLLj$ry+3xm3YX+YrSXbri8s3EcXDIrx5ceM+xQjtpLdw2oE='
and create fixtures file:
[
{ "model": "auth.user",
"pk": 1,
"fields": {
"username": "admin",
"password": "pbkdf2_sha256$10000$vkRy7QauoLLj$ry+3xm3YX+YrSXbri8s3EcXDIrx5ceM+xQjtpLdw2oE="
"is_superuser": true,
"is_staff": true,
"is_active": true
}
}
]
If you are using pytest-django you can use the existing fixture admin_user.
From RTD:
An instance of a superuser, with username “admin” and password “password” (in case there is no “admin” user yet).

Django - can't run tests while the application works normally

Problem:
The problem is that I have an application which works ok, but when I try to run tests with the command:
coverage run manage.py test --settings=crm.settings.test
there occurs an error in the very beggining:
Creating test database for alias 'default'...
IntegrityError: profiles_usermodel.current_project_id may not be NULL
Previously I ran tests and everything worked nicely. Then I significantly changed the models and the application and tried to run tests -- as a result I got the mentioned above problem. What I did wrong?
My settings:
I have separate settings for tests:
My_application
|___My_application
|___urls.py
|___ __init__.py
|___wsgi.py
|___settings
|___base.py
|___test.py
|___local.py
|___profiles
|___models.py
|___views.py
|___tests
|___ __init__.py
|___models.py
The test settings are as follows:
"""Local test settings and globals which allows us to run our
test suite locally."""
from .base import *
########## TEST SETTINGS
TEST_RUNNER = 'discover_runner.DiscoverRunner'
TEST_DISCOVER_TOP_LEVEL = PROJECT_ROOT
TEST_DISCOVER_ROOT = PROJECT_ROOT
TEST_DISCOVER_PATTERN = "*"
########## IN-MEMORY TEST DATABASE
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": ":memory:",
"USER": "",
"PASSWORD": "",
"HOST": "",
"PORT": "",
},
}
INSTALLED_APPS += ('coverage',)
And there is the models from My_application/profiles/models.py (ommited several fields and methods):
from django.db import models
from django.contrib.auth.models import (
BaseUserManager, AbstractBaseUser, PermissionsMixin )
from django.contrib.auth.models import Group
class Project(models.Model):
name = models.CharField(max_length=255)
class UserModel(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(max_length=255, unique=True, db_index=True,)
current_project = models.ForeignKey(Group, related_name='usermodel_current')
USERNAME_FIELD = 'email'
Also I use South for db migrations and django 1.5c2.
The error is being pretty explicit.
The test runner is attempting to create the database, and insert a record into 'profiles_usermodel'. This insertion is failing because the field 'current_project' cannot be null, but the creation process isn't setting anything into that field.
We'd have to see your tests to narrow down exactly where this is occurring.
If you don't care about getting it working "right" and just want it to work, update your user model, and add null=True to the kwargs of UserModel.current_project.

Django fixtures. JSONDecodeError

I've a Django project and I want to add test data to database. When I make syncdb like this
python ~/django/foo/manage.py syncdb
After tables are installed I've got an error
Problem installing fixture '~/django/foo/shop/fixtures/initial_data.json':
Traceback (most recent call last):
raise JSONDecodeError("No JSON object could be decoded", s, idx)
JSONDecodeError: No JSON object could be decoded: line 1 column 0 (char 0)
My model is here:
# -*- coding: utf-8 -*-
from django.db import models
class Image(models.Model):
file = models.ImageField(upload_to = "img/")
title = models.CharField(
max_length=128,
blank = True
)
slug = models.SlugField(max_length=128, blank = True)
def __unicode__(self):
return unicode(self.title)
My fixture is this:
[
{
"pk": 2,
"model": "shop.image",
"fields": {
"slug": "",
"file": "img/8_m.jpg",
"title": "1"
}
}
]
Where is the problem?
Wild guess... maybe your fixture file is saved as a unicode file??? Try to open it in the simplest text editor you can, or run
hexdump ~/django/foo/shop/fixtures/initial_data.json
and make sure the first character in the dump is 5b not fe or something.