Merge branch 'master' into penfield
authorJoseph Spiros <joseph.spiros@ithinksw.com>
Tue, 22 Jun 2010 16:12:37 +0000 (12:12 -0400)
committerJoseph Spiros <joseph.spiros@ithinksw.com>
Tue, 22 Jun 2010 16:12:37 +0000 (12:12 -0400)
admin.py
models.py
validators.py

index 64893d5..9e991d9 100644 (file)
--- a/admin.py
+++ b/admin.py
@@ -228,7 +228,7 @@ class PageAdmin(NodeAdmin):
                                initial_content = None
                                try:
                                        initial_content = page.contentreferences.get(name__exact=container_name, content_type=container_content_type).content.pk
-                               except ContentReference.DoesNotExist:
+                               except (ContentReference.DoesNotExist, AttributeError):
                                        pass
                                form.base_fields[('contentreference_container_%s' % container_name)] = forms.ModelChoiceField(label='References', widget=ModelLookupWidget(container_content_type), initial=initial_content, required=False, queryset=container_content_type.model_class().objects.all())
                return form
@@ -249,10 +249,17 @@ class PageAdmin(NodeAdmin):
                for container_name, container_content_type in contentreference_containers:
                        if ('contentreference_container_%s' % container_name) in form.cleaned_data:
                                content = form.cleaned_data[('contentreference_container_%s' % container_name)]
-                               contentreference, created = page.contentreferences.get_or_create(name=container_name, defaults={'content': content})
-                               if not created:
-                                       contentreference.content = content
-                                       contentreference.save()
+                               try:
+                                       contentreference = page.contentreferences.get(name=container_name)
+                               except ContentReference.DoesNotExist:
+                                       contentreference = ContentReference(name=container_name, page=page, content_type=container_content_type)
+                               
+                               if content == None:
+                                       contentreference.content_id = None
+                               else:
+                                       contentreference.content_id = content.id
+                               
+                               contentreference.save()
 
 
 class TemplateAdmin(admin.ModelAdmin):
index 1c71889..c17cd70 100644 (file)
--- a/models.py
+++ b/models.py
@@ -19,6 +19,7 @@ from django.template.loader import get_template
 from django.http import Http404, HttpResponse, HttpResponseServerError, HttpResponseRedirect
 from django.core.servers.basehttp import FileWrapper
 from django.conf import settings
+from philo.validators import RedirectValidator
 
 
 def register_value_model(model):
@@ -213,13 +214,16 @@ class InheritableTreeEntity(TreeEntity):
        
        @property
        def instance(self):
-               return self.instance_type.get_object_for_this_type(id=self.id)
+               try:
+                       return self.instance_type.get_object_for_this_type(id=self.id)
+               except:
+                       return None
        
        def get_path(self, pathsep='/', field='slug'):
-               path = getattr(self.instance, field, '?')
+               path = getattr(self.instance, field, getattr(self.instance, 'slug', '?'))
                parent = self.parent
                while parent:
-                       path = getattr(parent.instance, field, '?') + pathsep + path
+                       path = getattr(parent.instance, field, getattr(parent.instance, 'slug', '?')) + pathsep + path
                        parent = parent.parent
                return path
        path = property(get_path)
@@ -272,7 +276,7 @@ class Redirect(Node):
                (302, 'Temporary'),
                (301, 'Permanent'),
        )
-       target = models.URLField(help_text='Must be a valid, absolute URL (i.e. http://)')
+       target = models.CharField(max_length=200,validators=[RedirectValidator()])
        status_code = models.IntegerField(choices=STATUS_CODES, default=302, verbose_name='redirect type')
        
        def render_to_response(self, request, path=None, subpath=None):
@@ -396,7 +400,7 @@ class ContentReference(models.Model):
        page = models.ForeignKey(Page, related_name='contentreferences')
        name = models.CharField(max_length=255)
        content_type = models.ForeignKey(ContentType, verbose_name='Content type')
-       content_id = models.PositiveIntegerField(verbose_name='Content ID')
+       content_id = models.PositiveIntegerField(verbose_name='Content ID', blank=True, null=True)
        content = generic.GenericForeignKey('content_type', 'content_id')
        
        def __unicode__(self):
index bc41d02..0c6fa78 100644 (file)
@@ -1,5 +1,7 @@
 from django.core.exceptions import ValidationError
 from django.utils.translation import ugettext_lazy as _
+from django.core.validators import RegexValidator
+import re
 
 
 class TreeParentValidator(object):
@@ -42,7 +44,8 @@ class TreeParentValidator(object):
        def get_message(self):
                return self.static_message or _(u"A %s can't be its own parent." % self.instance.__class__.__name__)
        message = property(get_message)
-       
+
+
 class TreePositionValidator(object):
        code = 'invalid'
        
@@ -51,7 +54,7 @@ class TreePositionValidator(object):
                self.slug = slug
                self.obj_class = obj_class
                self.static_message = message
-                       
+               
                if code is not None:
                        self.code = code
        
@@ -68,10 +71,37 @@ class TreePositionValidator(object):
                        
                        if obj.id != value.id:
                                raise ValidationError(self.message)
-                               
+               
                except self.obj_class.DoesNotExist:
                        pass
        
        def get_message(self):
                return self.static_message or _(u"A %s with that path (parent and slug) already exists." % self.obj_class.__name__)
        message = property(get_message)
+
+
+class RedirectValidator(RegexValidator):
+       """Based loosely on the URLValidator, but no option to verify_exists"""
+       regex = re.compile(
+               r'^(?:https?://' # http:// or https://
+               r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?|' #domain...
+               r'localhost|' #localhost...
+               r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' # ...or ip
+               r'(?::\d+)?' # optional port
+               r'(?:/?|[/?#]?\S+)|'
+               r'[^?#\s]\S*)$',
+               re.IGNORECASE)
+       message = _(u'Enter a valid absolute or relative redirect target')
+
+
+class URLLinkValidator(RegexValidator):
+       """Based loosely on the URLValidator, but no option to verify_exists"""
+       regex = re.compile(
+               r'^(?:https?://' # http:// or https://
+               r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?|' #domain...
+               r'localhost|' #localhost...
+               r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' # ...or ip
+               r'(?::\d+)?' # optional port
+               r'|)' # also allow internal links
+               r'(?:/?|[/?#]?\S+)$', re.IGNORECASE)
+       message = _(u'Enter a valid absolute or relative redirect target')