Django

Code

Changeset 2383

Show
Ignore:
Timestamp:
02/24/06 04:36:04 (3 years ago)
Author:
russellm
Message:

magic-removal: Fixes #1346 -- Added ability for m2m relations to self to be optionally non-symmetrical. Added unit tests for non-symmetrical behaviour.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/branches/magic-removal/django/db/models/fields/related.py

    r2382 r2383  
    276276        qn = backend.quote_name 
    277277        this_opts = instance.__class__._meta 
     278        symmetrical = self.field.rel.symmetrical 
    278279        rel_model = self.field.rel.to 
    279280        rel_opts = rel_model._meta 
     
    302303                    target_col_name, instance._get_pk_val(), *objs, **kwargs) 
    303304 
    304                 # If this is an m2m relation to self, add the mirror entry in the m2m table 
    305                 if instance.__class__ == rel_model
     305                # If this is a symmmetrical m2m relation to self, add the mirror entry in the m2m table 
     306                if instance.__class__ == rel_model and symmetrical
    306307                    _add_m2m_items(self, superclass, rel_model, join_table, target_col_name, 
    307308                        source_col_name, instance._get_pk_val(), *objs, **kwargs)                     
     
    313314                    target_col_name, instance._get_pk_val(), *objs) 
    314315                     
    315                 # If this is an m2m relation to self, remove the mirror entry in the m2m table 
    316                 if instance.__class__ == rel_model
     316                # If this is a symmmetrical m2m relation to self, remove the mirror entry in the m2m table 
     317                if instance.__class__ == rel_model and symmetrical
    317318                    _remove_m2m_items(rel_model, join_table, target_col_name, 
    318319                        source_col_name, instance._get_pk_val(), *objs) 
     
    323324                _clear_m2m_items(join_table, source_col_name, instance._get_pk_val()) 
    324325     
    325                 # If this is an m2m relation to self, clear the mirror entry in the m2m table                 
    326                 if instance.__class__ == rel_model
     326                # If this is a symmmetrical m2m relation to self, clear the mirror entry in the m2m table                 
     327                if instance.__class__ == rel_model and symmetrical
    327328                    _clear_m2m_items(join_table, target_col_name, instance._get_pk_val()) 
    328329                 
     
    473474            filter_interface=kwargs.pop('filter_interface', None), 
    474475            limit_choices_to=kwargs.pop('limit_choices_to', None), 
    475             raw_id_admin=kwargs.pop('raw_id_admin', False)) 
     476            raw_id_admin=kwargs.pop('raw_id_admin', False), 
     477            symmetrical=kwargs.pop('symmetrical', True)) 
    476478        if kwargs["rel"].raw_id_admin: 
    477479            kwargs.setdefault("validator_list", []).append(self.isValidIDList) 
     
    560562 
    561563    def contribute_to_related_class(self, cls, related): 
    562         setattr(cls, related.get_accessor_name(), ManyRelatedObjectsDescriptor(related, 'm2m')) 
    563         # Add the descriptor for the m2m relation 
     564        # m2m relations to self do not have a ManyRelatedObjectsDescriptor,  
     565        # as it would be redundant - unless the field is non-symmetrical.  
     566        if related.model != related.parent_model or not self.rel.symmetrical: 
     567            # Add the descriptor for the m2m relation 
     568            setattr(cls, related.get_accessor_name(), ManyRelatedObjectsDescriptor(related, 'm2m')) 
     569             
    564570        self.rel.singular = self.rel.singular or self.rel.to._meta.object_name.lower() 
    565571 
     
    602608class ManyToMany: 
    603609    def __init__(self, to, singular=None, related_name=None, 
    604         filter_interface=None, limit_choices_to=None, raw_id_admin=False): 
     610        filter_interface=None, limit_choices_to=None, raw_id_admin=False, symmetrical=True): 
    605611        self.to = to 
    606612        self.singular = singular or None 
     
    610616        self.edit_inline = False 
    611617        self.raw_id_admin = raw_id_admin 
     618        self.symmetrical = symmetrical 
    612619        assert not (self.raw_id_admin and self.filter_interface), "ManyToMany relationships may not use both raw_id_admin and filter_interface" 
  • django/branches/magic-removal/tests/modeltests/m2m_recursive/models.py

    r2380 r2383  
    44In this example, A Person can have many friends, who are also people. Friendship is a  
    55symmetrical relationshiup - if I am your friend, you are my friend. 
     6 
     7A person can also have many idols - but while I may idolize you, you may not think 
     8the same of me. 'Idols' is an example of a non-symmetrical m2m field. Only recursive  
     9m2m fields may be non-symmetrical, and they are symmetrical by default. 
    610 
    711This test validates that the m2m table will create a mangled name for the m2m table if 
     
    1418    name = models.CharField(maxlength=20) 
    1519    friends = models.ManyToManyField('self') 
     20    idols = models.ManyToManyField('self', symmetrical=False, related_name='stalkers') 
    1621 
    1722    def __repr__(self): 
     
    9095 
    9196 
     97# Add some idols in the direction of field definition 
     98# Anne idolizes Bill and Chuck 
     99>>> a.idols.add(b,c) 
     100 
     101# Bill idolizes Anne right back 
     102>>> b.idols.add(a) 
     103 
     104# David is idolized by Anne and Chuck - add in reverse direction 
     105>>> d.stalkers.add(a,c) 
     106 
     107# Who are Anne's idols? 
     108>>> a.idols.all()  
     109[Bill, Chuck, David] 
     110 
     111# Who is stalking Anne? 
     112>>> a.stalkers.all() 
     113[Bill] 
     114 
     115# Who are Bill's idols? 
     116>>> b.idols.all() 
     117[Anne] 
     118 
     119# Who is stalking Bill? 
     120>>> b.stalkers.all() 
     121[Anne] 
     122 
     123# Who are Chuck's idols? 
     124>>> c.idols.all() 
     125[David] 
     126 
     127# Who is stalking Chuck? 
     128>>> c.stalkers.all() 
     129[Anne] 
     130 
     131# Who are David's idols? 
     132>>> d.idols.all() 
     133[] 
     134 
     135# Who is stalking David 
     136>>> d.stalkers.all() 
     137[Anne, Chuck] 
     138 
     139# Bill is already being stalked by Anne - add Anne again, but in the reverse direction 
     140>>> b.stalkers.add(a) 
     141 
     142# Who are Anne's idols? 
     143>>> a.idols.all()  
     144[Bill, Chuck, David] 
     145 
     146# Who is stalking Anne? 
     147[Bill] 
     148 
     149# Who are Bill's idols 
     150>>> b.idols.all() 
     151[Anne] 
     152 
     153# Who is stalking Bill? 
     154>>> b.stalkers.all() 
     155[Anne] 
     156 
     157# Remove Anne from Bill's list of stalkers 
     158>>> b.stalkers.remove(a) 
     159 
     160# Who are Anne's idols? 
     161>>> a.idols.all()  
     162[Chuck, David] 
     163 
     164# Who is stalking Anne? 
     165>>> a.stalkers.all() 
     166[Bill] 
     167 
     168# Who are Bill's idols? 
     169>>> b.idols.all() 
     170[Anne] 
     171 
     172# Who is stalking Bill? 
     173>>> b.stalkers.all() 
     174[] 
     175 
     176# Clear Anne's group of idols 
     177>>> a.idols.clear() 
     178 
     179# Who are Anne's idols 
     180>>> a.idols.all()  
     181[] 
     182 
     183# Reverse relationships should also be gone 
     184# Who is stalking Chuck? 
     185>>> c.stalkers.all() 
     186[] 
     187 
     188# Who is friends with David? 
     189>>> d.stalkers.all()  
     190[Chuck] 
     191 
    92192"""