Django fixtures. JSONDecodeError - django

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.

Related

Why is django TestCase not creating a test database?

I am writing a Django test inheriting from django.test.TestCase. Everywhere, in the docs, this tutorial and even in this accepted SO accepted answer is stated that when using Django TestCase, a test db will be automatically created.
Previously I have worked with DRF APITestCases and all worked well. Here I am using the very standard approach but the setUpTestData class method is using my production db.
What do I do wrong and what has to be done so a test db is spawned and used for the test?
Please see my code bellow.
from django.test import TestCase
from agregator.models import AgregatorProduct
from django.db.models import signals
def sample_product_one():
sample_product_one = {
# "id": 1,
"name": "testProdOne",
"dph": 21,
"updated": datetime.now(),
"active": True,
"updatedinstore": False,
"imagechanged": False,
"isVirtualProduct": False,
}
return sample_product_one
class TestCreateProdToCategory(TestCase):
"""
Test for correct creation of records
"""
#classmethod
#factory.django.mute_signals(signals.pre_save, signals.post_save)
def setUpTestData(cls):
AgregatorProduct.objects.create(
**sample_product_one()
)
def test_create_prod_to_cat(self):
product = AgregatorProduct.objects.get(id=1)
self.assertEqual(product.id, 1)
DB set up:
DATABASES = {
'agregator': {
'NAME': 'name',
'ENGINE': 'sql_server.pyodbc',
'HOST': 'my_ip',
'USER': 'my_user',
'PASSWORD': 'my_pwd',
'OPTIONS': {
'driver': 'ODBC Driver 17 for SQL Server',
'isolation_level': 'READ UNCOMMITTED',
},
}
}
The test results in
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\xevos\xevosadmin\agregator\tests\test_admin_actions\test_products_to_categories_admin_action.py", line 64, in test_create_prod_to_cat
product = AgregatorProduct.objects.get(id=1)
File "C:\xevos\xevosadmin\.venv\lib\site-packages\django\db\models\manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "C:\xevos\xevosadmin\.venv\lib\site-packages\django\db\models\query.py", line 397, in get
raise self.model.DoesNotExist(
agregator.models.AgregatorProduct.DoesNotExist: AgregatorProduct matching query does not exist.
----------------------------------------------------------------------
which is a result of id being autoincrementing and given there are products in the production db already, it gets id of eg 151545
(AgregatorProduct matching query does not exist. is a result of the fact that the product which used to have id=1 was deleted a long time ago in the production db.)
So the test writes to the existing database and the data persist there even after the test is finished.
To create a test database, use the setUp method inside TestCase and run it using python manage.py test
from django.test import TestCase
from myapp.models import Animal
class AnimalTestCase(TestCase):
def setUp(self):
Animal.objects.create(name="lion", sound="roar")
Animal.objects.create(name="cat", sound="meow")
def test_animals_can_speak(self):
"""Animals that can speak are correctly identified"""
lion = Animal.objects.get(name="lion")
cat = Animal.objects.get(name="cat")
self.assertEqual(lion.speak(), 'The lion says "roar"')
self.assertEqual(cat.speak(), 'The cat says "meow"')
The database will be created and deleted automatically after tests are done
https://docs.djangoproject.com/en/3.1/topics/testing/overview/#writing-tests

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 - populate table on startup with known values

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!

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.

Querying with mongoengine and django

I have a database "tumblelog" (using mongoengine) in which I added some data in the "user" collection with a "User" model:
db.user.find()
...
{ "_id" : ObjectId("4fb0c9494ca88402dd000000"), "_types" : [ "User" ], "first_name" : "John", "last_name" : "Doe", "_cls" : "User", "email" : "jdoe#example.com" }
{ "_id" : ObjectId("4fb0cb9d4ca88402ec000000"), "_types" : [ "User" ], "first_name" : "Joe30", "last_name" : "Foe", "_cls" : "User", "email" : "hu#huu.com" }
When I try User.objects in a django shell, I get the following error:
Traceback (most recent call last):
File "<console>", line 1, in <module>
File ".../mongoengine/queryset.py", line 1127, in __getitem__
return self._document._from_son(self._cursor[key])
File ".../mongoengine/base.py", line 1018, in _from_son
obj = cls(**data)
TypeError: __init__() keywords must be strings
Same thing when I try
for user in User.objects:
print user.first_name
---- Edit ----
I tried this
>>> users = User.objects
>>> users.count()
7
>>> users.first()
...
TypeError: __init__() keywords must be strings
---- Edit 2 ----
I installed my project this way :
> virtualenv Test
> source Test/bin/activate
> pip install Django
> pip install mongoengine
> cd Test/
> django-admin.py startproject db
Then I added the lines
from mongoengine import *
connect('tumblelog')
in settings.py
then I created this simple model
from mongoengine import *
class User(Document):
email = StringField(required=True)
name = StringField(max_length=50)
then I run the server
> python manage.py runserver
And in the shell (python manage.py shell) I can save data if I import my model class but I can't read it, I always have the same TypeError: init() keywords must be strings !
-----Switching to django-mongodb engine----
I didn't find any solution so I will use django-mongodb-engine. I did not find any comparison, but I tried both and it's very similar.
I just regret django-mongodb-engine doesn't handle inheritance principle.
What am I doing wrong ?
Thanks in advance!
we had the exact same issue using mongoengine 0.6.9. I am not suggesting this as an ideal solution but downgrading to 0.6.5 resolved this issue for us.
use the all() method
for user in User.objects.all():
print user.first_name