Commits

Mikhail Korobov committed e151c36

Support for FK lookups in unique_with

Comments (0)

Files changed (2)

autoslug/fields.py

         names) was specified for the field, all these fields are included together
         in the query when looking for a "rival" model instance.
         """
-        def _get_lookups(instance):
+        base_instance = instance
+        
+        def _get_lookups(instance, unique_with):
             "Returns a dict'able tuple of lookups to ensure slug uniqueness"
-            for _field_name in self.unique_with:
-                # `inner` is the 'month' part in 'pub_date__month'.
-                # it *only* applies to dates, otherwise it's just ignored.
+            for _field_name in unique_with:
                 if '__' in _field_name:
-                    if _field_name.count('__') > 1:
-                        raise ValueError('The `unique_with` constraint in %s.%s'
-                                         ' is set to "%s", but AutoSlugField only'
-                                         ' accepts one level of nesting for dates'
-                                         ' (e.g. "date__month").'
-                                         % (instance._meta.object_name, self.name,
-                                            _field_name))
-                    field_name, inner = _field_name.split('__')
+                    field_name, inner = _field_name.split('__', 1)
                 else:
                     field_name, inner = _field_name, None
 
                     raise ValueError('Could not find attribute %s.%s referenced'
                                      ' by %s.%s (see constraint `unique_with`)'
                                      % (instance._meta.object_name, field_name,
-                                        instance._meta.object_name, self.name))
+                                        base_instance._meta.object_name, self.name))
 
                 value = getattr(instance, field_name)
                 if not value:
                                      ' Please ensure that "%s" is declared *after*'
                                      ' all fields it depends on (i.e. "%s"), and'
                                      ' that they are not blank.'
-                                     % (instance._meta.object_name, self.name,
+                                     % (base_instance._meta.object_name, self.name,
                                         instance._meta.object_name, field_name,
                                         self.name, '", "'.join(self.unique_with)))
-                if isinstance(field, DateField):    # DateTimeField is a DateField subclass
+                if isinstance(field, DateField):    # DateTimeField is a DateField subclass                    
                     inner = inner or 'day'
+                    
+                    if '__' in inner:
+                        raise ValueError('The `unique_with` constraint in %s.%s'
+                                         ' is set to "%s", but AutoSlugField only'
+                                         ' accepts one level of nesting for dates'
+                                         ' (e.g. "date__month").'
+                                         % (base_instance._meta.object_name, self.name,
+                                            _field_name))                    
+                        
                     parts = ['year', 'month', 'day']
                     try:
                         granularity = parts.index(inner) + 1
                             yield (lookup, getattr(value, part))
                 else:
                     if inner:
-                        raise ValueError('Wrong value "%s__%s" for constraint'
-                                         ' `unique_with` in %s.%s. Compound field'
-                                         ' names are only accepted for DateField'
-                                         ' attributes (such as "date__month").'
-                                         % (field_name, inner,
-                                            instance._meta.object_name, self.name))
-                    yield (field_name, value)
-        lookups = tuple(_get_lookups(instance))
+                        for res in _get_lookups(value, [inner]):
+                            yield (_field_name, res[1],)
+                    else:
+                        yield (field_name, value)
+                    
+        lookups = tuple(_get_lookups(instance, self.unique_with))
         model = instance.__class__
         field_name = self.name
         index = 1

autoslug/tests.py

 
 # TODO: test cases for dates and unique_with
 
+from django.test import TestCase
 
-from django.db.models import Model, CharField
+from django.db.models import Model, CharField, ForeignKey
 from autoslug.fields import AutoSlugField
 
 
     """
     name = CharField(max_length=200)
     slug = AutoSlugField(populate_from='name', unique=True)
+    
+
+class ModelWithUniqueSlugFK(Model):    
+    """
+    >>> sm1 = SimpleModel.objects.create(name='test')
+    >>> sm2 = SimpleModel.objects.create(name='test')
+    >>> sm3 = SimpleModel.objects.create(name='test2')    
+    >>> greeting = 'Hello world!'
+    >>> a = ModelWithUniqueSlugFK.objects.create(name=greeting, simple_model=sm1)
+    >>> a.slug
+    'hello-world'
+    >>> b = ModelWithUniqueSlugFK.objects.create(name=greeting, simple_model=sm2)
+    >>> b.slug
+    'hello-world-2'
+    >>> c = ModelWithUniqueSlugFK.objects.create(name=greeting, simple_model=sm3)
+    >>> c.slug
+    'hello-world'
+    >>> d = ModelWithUniqueSlugFK.objects.create(name=greeting, simple_model=sm1)
+    >>> d.slug
+    'hello-world-3'
+    """    
+    name = CharField(max_length=200)
+    simple_model = ForeignKey(SimpleModel)
+    slug = AutoSlugField(populate_from='name', unique_with='simple_model__name')
 
 
 class ModelWithLongName(Model):