Django

Code

Changeset 4476

Show
Ignore:
Timestamp:
02/09/07 23:48:20 (2 years ago)
Author:
ubernostrum
Message:

Backport generic-relations data loss fix from [4428]. Thanks to Malcolm for pointing out my stupid error the first time I tried this.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/branches/0.95-bugfixes/django/db/models/query.py

    r3400 r4476  
    11from django.db import backend, connection, transaction 
    22from django.db.models.fields import DateField, FieldDoesNotExist 
     3from django.db.models.fields.generic import GenericRelation 
    34from django.db.models import signals 
    45from django.dispatch import dispatcher 
     
    926927        pk_list = [pk for pk,instance in seen_objs[cls]] 
    927928        for related in cls._meta.get_all_related_many_to_many_objects(): 
     929            if not isinstance(related.field, GenericRelation): 
     930                for offset in range(0, len(pk_list), GET_ITERATOR_CHUNK_SIZE): 
     931                    cursor.execute("DELETE FROM %s WHERE %s IN (%s)" % \ 
     932                                   (qn(related.field.m2m_db_table()), 
     933                                    qn(related.field.m2m_reverse_name()), 
     934                                    ','.join(['%s' for pk in pk_list[offset:offset+GET_ITERATOR_CHUNK_SIZE]])), 
     935                                   pk_list[offset:offset+GET_ITERATOR_CHUNK_SIZE]) 
     936        for f in cls._meta.many_to_many: 
     937            if isinstance(f, GenericRelation): 
     938                from django.contrib.contenttypes.models import ContentType 
     939                query_extra = 'AND %s=%%s' % f.rel.to._meta.get_field(f.content_type_field_name).column 
     940                args_extra = [ContentType.objects.get_for_model(cls).id] 
     941            else: 
     942                query_extra = '' 
     943                args_extra = [] 
    928944            for offset in range(0, len(pk_list), GET_ITERATOR_CHUNK_SIZE): 
    929945                cursor.execute("DELETE FROM %s WHERE %s IN (%s)" % \ 
    930                     (qn(related.field.m2m_db_table()), 
    931                         qn(related.field.m2m_reverse_name()), 
    932                         ','.join(['%s' for pk in pk_list[offset:offset+GET_ITERATOR_CHUNK_SIZE]])), 
    933                     pk_list[offset:offset+GET_ITERATOR_CHUNK_SIZE]) 
    934         for f in cls._meta.many_to_many: 
    935             for offset in range(0, len(pk_list), GET_ITERATOR_CHUNK_SIZE): 
    936                 cursor.execute("DELETE FROM %s WHERE %s IN (%s)" % \ 
    937                     (qn(f.m2m_db_table()), qn(f.m2m_column_name()), 
    938                     ','.join(['%s' for pk in pk_list[offset:offset+GET_ITERATOR_CHUNK_SIZE]])), 
    939                     pk_list[offset:offset+GET_ITERATOR_CHUNK_SIZE]) 
     946                               (qn(f.m2m_db_table()), qn(f.m2m_column_name()), 
     947                                ','.join(['%s' for pk in pk_list[offset:offset+GET_ITERATOR_CHUNK_SIZE]])) + query_extra, 
     948                               pk_list[offset:offset+GET_ITERATOR_CHUNK_SIZE] + args_extra) 
    940949        for field in cls._meta.fields: 
    941950            if field.rel and field.null and field.rel.to in seen_objs: 
  • django/branches/0.95-bugfixes/tests/modeltests/generic_relations/models.py

    r3160 r4476  
    6666# Objects with declared GenericRelations can be tagged directly -- the API 
    6767# mimics the many-to-many API. 
     68>>> bacon.tags.create(tag="fatty") 
     69<TaggedItem: fatty> 
     70>>> bacon.tags.create(tag="salty") 
     71<TaggedItem: salty> 
    6872>>> lion.tags.create(tag="yellow") 
    6973<TaggedItem: yellow> 
    7074>>> lion.tags.create(tag="hairy") 
    7175<TaggedItem: hairy> 
    72 >>> bacon.tags.create(tag="fatty") 
    73 <TaggedItem: fatty> 
    74 >>> bacon.tags.create(tag="salty") 
    75 <TaggedItem: salty> 
    7676 
    7777>>> lion.tags.all() 
     
    106106>>> TaggedItem.objects.filter(content_type__pk=ctype.id, object_id=quartz.id) 
    107107[<TaggedItem: clearish>] 
     108 
     109 
     110# If you delete an object with an explicit Generic relation, the related  
     111# objects are deleted when the source object is deleted.  
     112# Original list of tags:  
     113>>> [(t.tag, t.content_type, t.object_id) for t in TaggedItem.objects.all()]  
     114[('clearish', <ContentType: mineral>, 1), ('fatty', <ContentType: vegetable>, 2), ('hairy', <ContentType: animal>, 1), ('salty', <ContentType: vegetable>, 2), ('shiny', <ContentType: animal>, 2), ('yellow', <ContentType: animal>, 1)] 
     115  
     116>>> lion.delete()  
     117>>> [(t.tag, t.content_type, t.object_id) for t in TaggedItem.objects.all()]  
     118[('clearish', <ContentType: mineral>, 1), ('fatty', <ContentType: vegetable>, 2), ('salty', <ContentType: vegetable>, 2), ('shiny', <ContentType: animal>, 2)] 
     119  
     120# If Generic Relation is not explicitly defined, any related objects   
     121# remain after deletion of the source object.  
     122>>> quartz.delete()  
     123>>> [(t.tag, t.content_type, t.object_id) for t in TaggedItem.objects.all()]  
     124[('clearish', <ContentType: mineral>, 1), ('fatty', <ContentType: vegetable>, 2), ('salty', <ContentType: vegetable>, 2), ('shiny', <ContentType: animal>, 2)] 
     125  
     126# If you delete a tag, the objects using the tag are unaffected   
     127# (other than losing a tag)  
     128>>> tag = TaggedItem.objects.get(id=1)  
     129>>> tag.delete()  
     130>>> bacon.tags.all()  
     131[<TaggedItem: salty>] 
     132>>> [(t.tag, t.content_type, t.object_id) for t in TaggedItem.objects.all()]  
     133[('clearish', <ContentType: mineral>, 1), ('salty', <ContentType: vegetable>, 2), ('shiny', <ContentType: animal>, 2)] 
     134 
    108135"""