Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does django grok YML ? django not loading fixtures YML file (yml is not a known serialization)

I have successfully created my first django project.

I have two apps in my project foo and foobar.

I have created a folder named 'fixtures' in each of the app folders. I have NOT specified a fixtures directory in my settings.yml, so (according to the docs), django should be looking in my {app}/fixtures folder.

In the {app}/fixtures folder, I have several YML files. I have split the initial data for the various modules into separate YML files, making sure there are no cross file dependencies (i.e. all related models are in the same YML file and ancestors occur in the file before models that use them).

However, when I run./manage.py syncdb after the db objects were successfully created, there was the following message:

No fixtures found

I then tried to manually load the fixtures by using the loaddata command:

./manage.py loaddata 0100_foobar.yml
Problem installing fixture '0100_foobar': yml is not a known serialization 

Is the documentation given in the link above wrong?, or do I need to install a module in order for django to grok YML?

BTW, the YML files parse correctly and have been checked for correctness (i used them successfully in another project) - so that is not the problem

[Edit]

I have installed PyYaml and renamed my fixtures files as per Manoj's instructions. I am able to get a little further down the line, but I am still encountering problems (BTW, I am using PyYaml 3.0.9).

Here is the Model in my project ORM (i.e. {app}/model.py):

class Currency(models.Model):
    short_name = models.CharField(max_length=3, db_index=True, unique=True, null=False) # ISO Code
    long_name = models.CharField(max_length=64, db_index=True, unique=True, null=False)
    spot_settle = models.IntegerField(null=False, default=0)
    rounding = models.IntegerField(null=False, default=2)

Here is the YAML file I am importing:

Currency:    
  currency_aud : { short_name: AUD , long_name: Australia - Dollars , spot_settle: 0, rounding: 2 }    
  currency_cad : { short_name: CAD , long_name: Canada - Dollars , spot_settle: 0, rounding: 2 }    
  currency_eur : { short_name: EUR , long_name: Euro Member Countries - Euro , spot_settle: 0, rounding: 2 }    
  currency_gbp : { short_name: GBP , long_name: United Kingdom - Pounds , spot_settle: 0, rounding: 2 }    
  currency_jpy : { short_name: JPY , long_name: Japan - Yen , spot_settle: 0, rounding: 2 }    
  currency_usd : { short_name: USD , long_name: United States Of America - Dollars , spot_settle: 0, rounding: 2 }    
  currency_zar : { short_name: ZAR , long_name: South Africa - Rand, spot_settle: 0, rounding: 2 }    
  currency_hkd : { short_name: HKD , long_name: Hong Kong Dollar, spot_settle: 0, rounding: 2 }    
  currency_nzd : { short_name: NZD , long_name: New Zealand Dollar, spot_settle: 0, rounding: 2 }    
  currency_sgd : { short_name: SGD , long_name: Singapore Dollar, spot_settle: 0, rounding: 2 }    
  currency_dkk : { short_name: DKK , long_name: Danish Krone, spot_settle: 0, rounding: 2 }    
  currency_sek : { short_name: SEK , long_name: Swedish Krona, spot_settle: 0, rounding: 2 }    
  currency_chf : { short_name: CHF , long_name: Swiss Franc, spot_settle: 0, rounding: 2 }

Here is the stack trace when I run ./manage.py loaddata myapp/fixtures/currencies.yaml

me@somebox:~/work/demo/myproj$ ./manage.py loaddata reference/fixtures/0100_currency.yaml 
Installing yaml fixture 'reference/fixtures/0100_currency' from absolute path.
Problem installing fixture 'reference/fixtures/0100_currency.yaml': Traceback (most recent call last):
  File "/usr/local/lib/python2.6/dist-packages/django/core/management/commands/loaddata.py", line 165, in handle
    for obj in objects:
  File "/usr/local/lib/python2.6/dist-packages/django/core/serializers/pyyaml.py", line 57, in Deserializer
    for obj in PythonDeserializer(yaml.load(stream), **options):
  File "/usr/local/lib/python2.6/dist-packages/django/core/serializers/python.py", line 84, in Deserializer
    Model = _get_model(d["model"])
TypeError: string indices must be integers, not str
like image 469
skyeagle Avatar asked Oct 07 '10 10:10

skyeagle


2 Answers

I tried to reproduce your problem in one of my projects. Apparently loaddata expects the extension of the file to match the serialization format. In your case you should rename your file to 0100_foobar.yaml (note the new extension).

Local tests showed my hypothesis was correct.

PS: YAML serialization requires the PyYAML library. If you already haven't, install PyYAML.

Update

I copied the OP's model to one of my projects. When I tried to load the sample YAML given by the OP as-is, I got the same error.

After that I added some data using the admin app and used django.core.serializers.serialize to dump the data in YAML format.

from django.core.serializers import serialize
from app.models import Currency
print serializers.serialize("yaml", Currency.objects.all())

The result I got looked significantly different from what the OP posted. See below. I added three instances for the model and they are showing up.

- fields: {long_name: Australia - Dollars, rounding: 2, short_name: AUD, spot_settle: 0}
  model: app.currency
  pk: 1
- fields: {long_name: Canada - Dollars, rounding: 2, short_name: CAD, spot_settle: 0}
  model: app.currency
  pk: 2
- fields: {long_name: Euro Member Countries - Euro, rounding: 2, short_name: EUR,
    spot_settle: 0}
  model: app.currency
  pk: 3

I was able to load this data back without any trouble.

Given the above, I suspect that there is something wrong with the OP's YAML file. @skyeagle, can you try dumping the existing data and then try loading the dump back?

like image 199
Manoj Govindan Avatar answered Sep 21 '22 00:09

Manoj Govindan


For anyone like me who is just stubborn and really, really, wants to use files with a .yml extension, you can register a serializer at startup to make loaddata recognize the fixture file:

from django.apps import AppConfig
from django.core.serializers import register_serializer


class MyAppConfig(AppConfig):
    name = 'my_app_name'
    label = 'my_app_label'
    verbose_name = 'this is my really cool app'

    def ready(self):
        register_serializer('yml', 'django.core.serializers.pyyaml')

The call to register_serializer will register yml as a recognized extension.

like image 39
2ps Avatar answered Sep 21 '22 00:09

2ps