How to load sql fixture in Django for User model?

2019-01-22 00:23发布

问题:

Does anyone knows how to load initial data for auth.User using sql fixtures? For my models, I just got have a < modelname >.sql file in a folder named sql that syncdb does it's job beautifully. But I have no clue how to do it for the auth.User model. I've googled it, but with no success.

Thanks in advance,

Aldo

回答1:

For SQL fixtures, you'd have to specifically have insert statements for the auth tables. You can find the schema of the auth tables with the command python manage.py sql auth.

The much easier and database-independent way (unless you have some additional SQL magic you want to run), is to just make a JSON or YAML fixture file in the fixtures directory of your app with data like this:

- model: auth.user
  pk: 100000
  fields:
    first_name: Admin
    last_name: User
    username: admin
    password: "<a hashed password>"

You can generate a hashed password quickly in a django shell

>>> from django.contrib.auth.models import User
>>> u = User()
>>> u.set_password('newpass')
>>> u.password
'sha1$e2fd5$96edae9adc8870fd87a65c051e7fdace6226b5a8'

This will get loaded whenever you run syncdb.



回答2:

You are looking for loaddata:

manage.py loadata path/to/your/fixtureFile

But I think the command can only deal with files in XML, YAML, Python or JSON format (see here). To create such appropriate files, have a look at the dumpdata method.



回答3:

Thanks for your answers. I've found the solution that works for me, and for coincidence was one of Brian's suggestion. Here it is:

Firs I disconnected the signal that created the Super User after syncdb, for I have my super user in my auth_user fixture:

models.py:

from django.db.models import signals
from django.contrib.auth.management import create_superuser
from django.contrib.auth import models as auth_app


signals.post_syncdb.disconnect(
    create_superuser,
    sender=auth_app,
    dispatch_uid = "django.contrib.auth.management.create_superuser")

Then I created a signal to be called after syncdb:

< myproject >/< myapp >/management/__init__.py

"""
Loads fixtures for files in sql/<modelname>.sql
"""
from django.db.models import get_models, signals
from django.conf import settings 
import <myproject>.<myapp>.models as auth_app

def load_fixtures(app, **kwargs):
    import MySQLdb
    db=MySQLdb.connect(host=settings.DATABASE_HOST or "localhost", \
       user=settings.DATABASE_USER,
    passwd=settings.DATABASE_PASSWORD, port=int(settings.DATABASE_PORT or 3306))

    cursor = db.cursor()

    try:
        print "Loading fixtures to %s from file %s." % (settings.DATABASE_NAME, \
            settings.FIXTURES_FILE)
        f = open(settings.FIXTURES_FILE, 'r')
        cursor.execute("use %s;" % settings.DATABASE_NAME)
        for line in f:
            if line.startswith("INSERT"):
                try:
                    cursor.execute(line)
                except Exception, strerror:
                    print "Error on loading fixture:"
                    print "-- ", strerror
                    print "-- ", line

        print "Fixtures loaded"

    except AttributeError:
        print "FIXTURES_FILE not found in settings. Please set the FIXTURES_FILE in \
            your settings.py" 

    cursor.close()
    db.commit()
    db.close()

signals.post_syncdb.connect(load_fixtures, sender=auth_app, \
    dispatch_uid = "<myproject>.<myapp>.management.load_fixtures")

And in my settings.py I added FIXTURES_FILE with the path to my .sql file with the sql dump.

One thing that I still haven't found is how to fire this signal only after the tables are created, and not everytime syncdb is fired. A temporary work around for this is use INSERT IGNORE INTO in my sql command.

I know this solution is far from perfect, and critics/improvements/opinions are very welcome!

Regards,

Aldo



回答4:

There is a trick for this: (tested on Django 1.3.1)

Solution:

  1. python manage.py startapp auth_fix
  2. mkdir auth_fix/fixtures
  3. python manage.py dumpdata auth > auth_fixtures/fixtures/initial_data.json
  4. Include auth_fix in INSTALLED_APPS inside settings.py

Next time you run python manage.py syncdb, Django will load the auth fixture automatically.

Explanation:

  1. Just make an empty app to hold the fixtures folder. Leave __init__py, models.py and views.py in it so that Django recognizes it as an app and not just a folder.
  2. Make the fixtures folder in the app.
  3. python manage.py dumpdata auth will dump the "auth" data in the DB with all the Groups and Users information. The rest of the command simply redirects the output into a file called "initial_data.json" which is the one that Django looks for when you run "syncdb".
  4. Just include auth_fix in INSTALLED_APPS inside settings.py.

This example shows how to do it in JSON but you can basically use the format of your choice.



回答5:

An option is to import your auth.User SQL manually and subsequently dump it out to a standard Django fixture (name it initial_data if you want syncdb to find it). You can generally put this file into any app's fixtures dir since the fixtured data will all be keyed with the proper app_label. Or you can create an empty/dummy app and place it there.

Another option is to override the syncdb command and apply the fixture in a manner as you see fit.

I concur with Felix that there is no non-trivial natural hook in Django for populating contrib apps with SQL.



回答6:

If you happen to be doing database migrations with south, creating users is very simple.

First, create a bare data migration. It needs to be included in some application. If you have a common app where you place shared code, that would be a good choice. If you have an app where you concentrate user-related code, that would be even better.

$ python manage.py datamigration <some app name> add_users

The pertinent migration code might look something like this:

# encoding: utf-8
import datetime
from south.db import db
from south.v2 import DataMigration
from django.db import models
from django.contrib.auth.models import User

class Migration(DataMigration):

    users = [
        {
            'username': 'nancy',
            'email': 'nancy@example.com',
            'password': 'nancypassword',
            'staff': True,
            'superuser': True
        },
        {
            'username': 'joe',
            'email': '',
            'password': 'joepassword',
            'staff': True,
            'superuser': False
        },
        {
            'username': 'susan',
            'email': 'susan@example.com',
            'password': 'susanpassword',
            'staff': False,
            'superuser': False
        }
    ]

    def forwards(self, orm):
        """
        Insert User objects
        """
        for i in Migration.users:
            u = User.objects.create_user(i['username'],  i['email'], i['password'])
            u.is_staff = i['staff']
            u.is_superuser = i['superuser']
            u.save()

    def backwards(self, orm):
        """
        Delete only these users
        """
        for i in Migration.users:
            User.objects.filter(username=i['username']).delete()

Then simply run the migration and the auth users should be inserted.

$ python manage.py migrate <some app name>


回答7:

I simply added SQL statements into the custom sql file for another model. I chose my Employee model because it depends on auth_user. The custom SQL I wrote actually reads from my legacy application and pulls user info from it, and uses REPLACE rather than INSERT (I'm using MySQL) so I can run it whenever I want. And I put that REPLACE...SELECT statement in a procedure so that it's easy to run manually or scheduled with cron.