Reputation: 151
I'll be as brief as possible.
I want to able to do this
{{ video.youtube_url.video_id }}
by implementing something like the following custom field:
class YouTubeURLField(URLField):
description = _("YouTubeURL")
def _video_id(self):
return re.search('(?<=\?v\=)[\w-]+', self.value)
video_id = property(_video_id)
def __init__(self, verbose_name=None, name=None, verify_exists=True, **kwargs):
super(YouTubeURLField, self).__init__(**kwargs)
kwargs['max_length'] = kwargs.get('max_length', 200)
CharField.__init__(self, verbose_name, name, **kwargs)
self.validators.append(YouTubeURLValidator(verify_exists=verify_exists))
This:
def _video_id(self):
return re.search('(?<=\?v\=)[\w-]+', self.value)
video_id = property(_video_id)
Does not sucessfully add a "video_id" attribute to my custom YouTubeURLField.
Everything else works flawlessly.
I understand there maybe better design considerations in terms of the YouTube custom field, but I'd rather just understand, first, why this doesn't work.
Upvotes: 1
Views: 1652
Reputation: 151
I wanted to do it this way, because it seems it makes more sense from a design stand point. The video id is an attribute of the YouTube URL and not of the model itself.
I figured it out. I overrode the to_python function to return a YouTubeURL object.
class YouTubeURL(object):
def __init__(self, value):
self.value = value
@property
def video_id(self):
regex = re.compile(r'/v/([A-Za-z0-9\-_]+)', re.IGNORECASE)
id = regex.search(self.value)
return id.group(1)
def __unicode__(self):
return "%s" % (self.value,)
def __str__(self):
return "%s" % (self.value,)
def __len__(self):
return len(self.value)
class YouTubeURLField(URLField):
description = _("YouTubeURL")
__metaclass__ = SubfieldBase
def to_python(self, value):
return YouTubeURL(value)
def __init__(self, verbose_name=None, name=None, verify_exists=True, **kwargs):
super(YouTubeURLField, self).__init__(**kwargs)
kwargs['max_length'] = kwargs.get('max_length', 200)
CharField.__init__(self, verbose_name, name, **kwargs)
self.validators.append(YouTubeURLValidator(verify_exists=verify_exists))
Upvotes: -1
Reputation: 2219
Is there a reason you can't have it as a property of the model?
In order to access data from an object not directly contained within the fields I frequently implement a pattern along the lines of:
class: Sheep(models.Model):
name = models.CharField(max_length=200)
@property
def sheep_says(self):
return "Baa... my name is %s ... baa" % self.name
Which you would then access in the template with:
{{ sheep.sheep_says }}
Upvotes: 0
Reputation: 799110
Django fields are descriptors, which means that accessing them does not return the field, but rather the field value. You will need to override the Django field methods in order to return an object that has the attributes you care about, as well as a sanely-defined __unicode__()
method.
Upvotes: 2