Commit 7deb25b8 authored by Alex Gaynor's avatar Alex Gaynor
Browse files

Fixed #7596. Added Model.objects.bulk_create, and make use of it in several...

Fixed #7596.  Added Model.objects.bulk_create, and make use of it in several places.  This provides a performance benefit when inserting multiple objects.  THanks to Russ for the review, and Simon Meers for the MySQl implementation.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@16739 bcc190cf-cafb-0310-a4f2-bffc1f526a37
parent e55bbf4c
Loading
Loading
Loading
Loading
+9 −11
Original line number Diff line number Diff line
@@ -46,17 +46,15 @@ def create_permissions(app, created_models, verbosity, **kwargs):
        "content_type", "codename"
    ))

    for ctype, (codename, name) in searched_perms:
        # If the permissions exists, move on.
        if (ctype.pk, codename) in all_perms:
            continue
        p = auth_app.Permission.objects.create(
            codename=codename,
            name=name,
            content_type=ctype
        )
    objs = [
        auth_app.Permission(codename=codename, name=name, content_type=ctype)
        for ctype, (codename, name) in searched_perms
        if (ctype.pk, codename) not in all_perms
    ]
    auth_app.Permission.objects.bulk_create(objs)
    if verbosity >= 2:
            print "Adding permission '%s'" % p
        for obj in objs:
            print "Adding permission '%s'" % obj


def create_superuser(app, created_models, verbosity, **kwargs):
+33 −17
Original line number Diff line number Diff line
@@ -8,25 +8,41 @@ def update_contenttypes(app, created_models, verbosity=2, **kwargs):
    entries that no longer have a matching model class.
    """
    ContentType.objects.clear_cache()
    content_types = list(ContentType.objects.filter(app_label=app.__name__.split('.')[-2]))
    app_models = get_models(app)
    if not app_models:
        return
    for klass in app_models:
        opts = klass._meta
        try:
            ct = ContentType.objects.get(app_label=opts.app_label,
                                         model=opts.object_name.lower())
            content_types.remove(ct)
        except ContentType.DoesNotExist:
            ct = ContentType(name=smart_unicode(opts.verbose_name_raw),
                app_label=opts.app_label, model=opts.object_name.lower())
            ct.save()
    # They all have the same app_label, get the first one.
    app_label = app_models[0]._meta.app_label
    app_models = dict(
        (model._meta.object_name.lower(), model)
        for model in app_models
    )
    # Get all the content types
    content_types = dict(
        (ct.model, ct)
        for ct in ContentType.objects.filter(app_label=app_label)
    )
    to_remove = [
        ct
        for (model_name, ct) in content_types.iteritems()
        if model_name not in app_models
    ]

    cts = ContentType.objects.bulk_create([
        ContentType(
            name=smart_unicode(model._meta.verbose_name_raw),
            app_label=app_label,
            model=model_name,
        )
        for (model_name, model) in app_models.iteritems()
        if model_name not in content_types
    ])
    if verbosity >= 2:
        for ct in cts:
            print "Adding content type '%s | %s'" % (ct.app_label, ct.model)
    # The presence of any remaining content types means the supplied app has an
    # undefined model. Confirm that the content type is stale before deletion.
    if content_types:

    # Confirm that the content type is stale before deletion.
    if to_remove:
        if kwargs.get('interactive', False):
            content_type_display = '\n'.join(['    %s | %s' % (ct.app_label, ct.model) for ct in content_types])
            ok_to_delete = raw_input("""The following content types are stale and need to be deleted:
@@ -42,7 +58,7 @@ If you're unsure, answer 'no'.
            ok_to_delete = False

        if ok_to_delete == 'yes':
            for ct in content_types:
            for ct in to_remove:
                if verbosity >= 2:
                    print "Deleting stale content type '%s | %s'" % (ct.app_label, ct.model)
                ct.delete()
+2 −0
Original line number Diff line number Diff line
@@ -301,8 +301,10 @@ class BaseDatabaseFeatures(object):

    can_use_chunked_reads = True
    can_return_id_from_insert = False
    has_bulk_insert = False
    uses_autocommit = False
    uses_savepoints = False
    can_combine_inserts_with_and_without_auto_increment_pk = False

    # If True, don't use integer foreign keys referring to, e.g., positive
    # integer primary keys.
+5 −0
Original line number Diff line number Diff line
@@ -124,6 +124,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
    allows_group_by_pk = True
    related_fields_match_type = True
    allow_sliced_subqueries = False
    has_bulk_insert = True
    has_select_for_update = True
    has_select_for_update_nowait = False
    supports_forward_references = False
@@ -263,6 +264,10 @@ class DatabaseOperations(BaseDatabaseOperations):
    def max_name_length(self):
        return 64

    def bulk_insert_sql(self, fields, num_values):
        items_sql = "(%s)" % ", ".join(["%s"] * len(fields))
        return "VALUES " + ", ".join([items_sql] * num_values)

class DatabaseWrapper(BaseDatabaseWrapper):
    vendor = 'mysql'
    operators = {
+1 −0
Original line number Diff line number Diff line
@@ -74,6 +74,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
    can_defer_constraint_checks = True
    has_select_for_update = True
    has_select_for_update_nowait = True
    has_bulk_insert = True


class DatabaseWrapper(BaseDatabaseWrapper):
Loading