class Resource(GeoRefModel, BaseModel): """Resources model""" name = models.CharField(max_length=256, default=_('Resource without name')) # slug = models.CharField(max_length=256, blank=False, db_index=True) kind = models.ForeignKey(ResourceKind, null=True, blank=True) description = models.TextField() short_description = models.CharField(max_length=250, null=True, blank=True) contacts = ContactsField() tags = TaggableManager() community = models.ManyToManyField(Community, related_name='resources', null=True, blank=True) # TODO remove me # Meta info creator = models.ForeignKey(User, editable=False, null=True, related_name='created_resources') creation_date = models.DateTimeField(auto_now_add=True) last_editor = models.ForeignKey(User, editable=False, null=True, blank=True) last_update = models.DateTimeField(auto_now=True) class Map: title = _('Resource') editable = True background_color = '#28CB05' border_color = '#1D9104' geometries = (POLYGON, LINESTRING, POINT) form_view_name = 'new_resource_from_map' zindex = 15 def __unicode__(self): return unicode(self.name) image = "img/resource.png" image_off = "img/resource-off.png" default_logo_url = "img/logo-resource.png" def files_set(self): """ pseudo-reverse query for retrieving Resource Files""" return UploadedFile.get_files_for(self) @property def home_url_params(self): return dict(id=self.id) @property def view_url(self): return reverse('view_resource', kwargs=self.home_url_params) @property def edit_url(self): return reverse('edit_resource', kwargs=self.home_url_params) @property def admin_url(self): return reverse('admin:{}_{}_change'.format(self._meta.app_label, self._meta.module_name), args=[self.id]) @property def perm_id(self): return 'r%d' % self.id def save(self, *args, **kwargs): r_ = super(Resource, self).save(*args, **kwargs) index_object_for_search.send(sender=self, obj=self) return r_ # ========================================================================== # Utils # def from_dict(self, data): # keys = ['id', 'name', 'contact', 'geojson', 'creation_date', # 'is_admin', 'is_active', 'about_me'] # date_keys = ['creation_date'] # build_obj_from_dict(self, data, keys, date_keys) def to_dict(self): fields_and_defaults = [ ('name', None), ('kind_id', None), ('description', None), ('short_description ', None), ('creator_id', None), ('creation_date', None), ('last_editor_id', None), ('last_update', None), ('geojson', {}), ('contacts', {}), ] dict_ = {v[0]: getattr(self, v[0], v[1]) for v in fields_and_defaults} dict_['tags'] = [tag.name for tag in self.tags.all()] return dict_
class Community(GeoRefModel, BaseModel): name = models.CharField(max_length=256, blank=False) # Auto-generated url slug. It's not editable via ModelForm. slug = models.SlugField(max_length=256, blank=False, db_index=True) population = models.IntegerField(null=True, blank=True) description = models.TextField(null=True, blank=True) short_description = models.CharField(max_length=250, null=True, blank=True) contacts = ContactsField() tags = TaggableManager() # Meta info creator = models.ForeignKey(User, editable=False, null=True, related_name='created_communities') creation_date = models.DateTimeField(auto_now_add=True) last_editor = models.ForeignKey(User, editable=False, null=True, blank=True) last_update = models.DateTimeField(auto_now=True) def __unicode__(self): return self.name class Map: title = _('Community') editable = True background_color = '#ffc166' border_color = '#ff2e2e' geometries = (POLYGON, ) form_view_name = 'new_community' min_zoom_geometry = 10 max_zoom_geometry = 100 #min_zoom_point = 0 #max_zoom_point = 0 #min_zoom_icon = 0 #max_zoom_icon = 0 zindex = 5 class Meta: verbose_name = "community" verbose_name_plural = "communities" def save(self, *args, **kwargs): self.slug = slugify(self.name) r_ = super(Community, self).save(*args, **kwargs) index_object_for_search.send(sender=self, obj=self) return r_ image = "img/community.png" image_off = "img/community-off.png" default_logo_url = "img/logo-community.png" # TODO: order communities from the database def closest_communities(self, max=3, radius=Distance(km=25)): center = self.geometry.centroid unordered = Community.objects.filter(polys__distance_lte=(center, radius)) closest = sorted(unordered, key=lambda c: c.geometry.distance(center)) return closest[1:(max + 1)] # url aliases @property def view_url(self): return reverse('view_community', kwargs={'id': self.id}) @property def edit_url(self): return reverse('edit_community', kwargs={'id': self.id}) @property def admin_url(self): return reverse('admin:{}_{}_change'.format(self._meta.app_label, self._meta.module_name), args=[self.id]) @property def perm_id(self): return 'c%d' % self.id # ========================================================================== # Utils # def from_dict(self, data): # keys = ['id', 'name', 'contact', 'geojson', 'creation_date', # 'is_admin', 'is_active', 'about_me'] # date_keys = ['creation_date'] # build_obj_from_dict(self, data, keys, date_keys) def to_dict(self): fields_and_defaults = [('name', None), ('slug', None), ('population', None), ('description', None), ('short_description ', None), ('creator_id', None), ('creation_date', None), ('last_editor_id', None), ('last_update', None), ('geojson', {}), ('contacts', {})] dict_ = {v[0]: getattr(self, v[0], v[1]) for v in fields_and_defaults} dict_['tags'] = [tag.name for tag in self.tags.all()] return dict_
class Organization(GeoRefModel, BaseModel): name = models.CharField(max_length=320, unique=True) slug = models.SlugField(max_length=320, db_index=True) # used anywhere? description = models.TextField(null=True, blank=True) short_description = models.CharField(max_length=250, null=True, blank=True) logo = models.ForeignKey(UploadedFile, null=True, blank=True) logo_category = models.ForeignKey('OrganizationCategory', null=True, blank=True, related_name='organization_category_logo') logo_choice = models.CharField(max_length=3, choices=LOGO_CHOICES, null=True, blank=True) # Meta info creator = models.ForeignKey(User, editable=False, null=True, related_name='created_organizations') creation_date = models.DateTimeField(auto_now_add=True) last_editor = models.ForeignKey(User, editable=False, null=True, blank=True) last_update = models.DateTimeField(auto_now=True) community = models.ManyToManyField(Community, null=True, blank=True) # TODO remove-me contacts = ContactsField() categories = models.ManyToManyField('OrganizationCategory', null=True, blank=True) target_audiences = models.ManyToManyField(TargetAudience, null=True, blank=True) tags = TaggableManager() class Map: editable = True title = _('Organization') tooltip = _('Add an organization') background_color = '#3a61d6' border_color = '#1f49b2' geometries = (POLYGON, POINT) form_view_name = 'new_organization_from_map' @property def communities(self): from relations.models import Relation return [rel['target'] for rel in Relation.relations_for(self) if rel['target'].__class__.__name__ == 'Community'] @property def related_items(self): return [c for c in self.communities] # + \ # [r for r in self.supported_resources] + \ # [p.need for p in self.supported_proposals] + \ # [o for o in self.supported_organizations] @property def as_investor(self): investor, created = Investor.get_or_create_for(self) return investor def __unicode__(self): return unicode(self.name) def save(self, *args, **kwargs): self.slug = slugify(self.name) r_ = super(Organization, self).save(*args, **kwargs) index_object_for_search.send(sender=self, obj=self) return r_ def files_set(self): """ pseudo-reverse query for retrieving Organization Files""" return UploadedFile.get_files_for(self) @property def logo_url(self): if self.logo and not self.logo_category: return self.logo.file.url elif not self.logo and self.logo_category: return '/static/' + self.logo_category.image else: if self.logo_choice == 'CAT': return '/static/' + self.logo_category.image elif self.logo_choice == 'UP': return self.logo.file.url else: return '/static/img/logo.png' image = "img/organization.png" image_off = "img/organization-off.png" # url aliases @property def home_url_params(self): return dict(id=self.id) @property def view_url(self): return reverse('view_organization', kwargs=self.home_url_params) @property def edit_url(self): return reverse('edit_organization', kwargs=self.home_url_params) @property def admin_url(self): return reverse('admin:{}_{}_change'.format(self._meta.app_label, self._meta.module_name), args=[self.id]) @property def related_items_url(self): return reverse('view_organization_related_items', kwargs=self.home_url_params) @property def json(self): return to_json({ 'name': self.name, 'slug': self.slug, 'logo_url': self.logo_url, 'view_url': self.view_url, }) def perm_id(self): return 'o%d' % self.id # ========================================================================== # Utils # def from_dict(self, data): # keys = ['id', 'name', 'contact', 'geojson', 'creation_date', # 'is_admin', 'is_active', 'about_me'] # date_keys = ['creation_date'] # build_obj_from_dict(self, data, keys, date_keys) def to_dict(self): fields_and_defaults = [ ('name', None), ('slug', None), ('description', None), ('short_description ', None), ('creator_id', None), ('creation_date', None), ('last_editor_id', None), ('last_update', None), ('logo_id', None), ('logo_category_id', None), ('logo_choice', None), ('contacts', {}), ('geojson', {}) ] dict_ = {v[0]: getattr(self, v[0], v[1]) for v in fields_and_defaults} dict_['tags'] = [tag.name for tag in self.tags.all()] dict_['target_audiences'] = [ta.name for ta in self.target_audiences.all()] dict_['categories'] = [cat.id for cat in self.categories.all()] return dict_
class Proposal(models.Model): """A proposed solution for solving a need""" class Meta: verbose_name = "proposal" verbose_name_plural = "proposals" title = models.CharField(max_length=256) description = models.TextField() short_description = models.CharField(max_length=250, null=True, blank=True) number = models.IntegerField(null=False, blank=True, editable=False) contacts = ContactsField() tags = TaggableManager() # Meta info creator = models.ForeignKey(User, editable=False, null=True, related_name='created_proposals') creation_date = models.DateTimeField(auto_now_add=True) last_editor = models.ForeignKey(User, editable=False, null=True, blank=True) last_update = models.DateTimeField(auto_now=True) # Relationships need = models.ForeignKey(Need, related_name='proposals') # TODO: Also: organizations = model.ManyToManyField(Organization) cost = models.DecimalField(decimal_places=2, max_digits=14, null=True, blank=True) report = models.TextField(null=True, blank=True) investments = generic.GenericRelation( Investment, content_type_field='grantee_content_type', object_id_field='grantee_object_id') #dummy? readding to data charge to work realizers = models.ManyToManyField(User, related_name='user_realizers') @property def name(self): return self.title @property def community(self): return self.need.community @property def geometry(self): return self.need.geometry def save(self, *args, **kwargs): if not self.id: # auto numbering a need's proposals self.number = Proposal.objects.filter(need=self.need).count() + 1 super(Proposal, self).save(*args, **kwargs) def __unicode__(self): return unicode(self.title) # Url aliases @property def home_url_params(self): return dict(id=self.id) @property def view_url(self): return reverse('view_proposal', kwargs=self.home_url_params) @property def edit_url(self): return reverse('edit_proposal', kwargs=self.home_url_params) @property def admin_url(self): return reverse('admin:{}_{}_change'.format(self._meta.app_label, self._meta.module_name), args=[self.id]) @property def new_investment_url(self): return reverse('new_investment') + '?type=proposal&obj={id}'.format( id=self.id) @property def perm_id(self): return 'p%d' % self.id
class Need(GeoRefModel, BaseModel): class Meta: verbose_name = "need" verbose_name_plural = "needs" name = models.CharField(max_length=256, blank=False) slug = models.CharField(max_length=256, blank=False, db_index=True) description = models.TextField() short_description = models.CharField(max_length=250, null=True, blank=True) # Meta info creator = models.ForeignKey(User, editable=False, null=True, related_name='created_needs') creation_date = models.DateTimeField(auto_now_add=True) last_editor = models.ForeignKey(User, editable=False, null=True, blank=True) last_update = models.DateTimeField(auto_now=True) contacts = ContactsField() # Relationships community = models.ManyToManyField( Community, related_name="needs", # TODO: remove-me null=True, blank=True) categories = models.ManyToManyField(NeedCategory) target_audiences = models.ManyToManyField(TargetAudience, blank=False) tags = TaggableManager() class Map: title = _('Need') editable = True background_color = '#f42c5e' border_color = '#d31e52' geometries = (POLYGON, LINESTRING, POINT) categories = NeedCategory.categories form_view_name = 'new_need_from_map' form_view_kwargs = {} def __unicode__(self): return unicode(self.name) def save(self, *args, **kwargs): self.slug = slugify(self.name) r_ = super(Need, self).save(*args, **kwargs) index_object_for_search.send(sender=self, obj=self) return r_ image = "img/need.png" image_off = "img/need-off.png" default_logo_url = "img/logo-need.png" # Url aliases @property def home_url_params(self): return {'id': self.id} @property def view_url(self): return reverse('view_need', kwargs=self.home_url_params) @property def edit_url(self): return reverse('edit_need', kwargs=self.home_url_params) @property def admin_url(self): return reverse('admin:{}_{}_change'.format(self._meta.app_label, self._meta.module_name), args=[self.id]) @property def title(self): return self.name @property def perm_id(self): return 'n%d' % self.id # ========================================================================== # Utils # def from_dict(self, data): # keys = ['id', 'name', 'contact', 'geojson', 'creation_date', # 'is_admin', 'is_active', 'about_me'] # date_keys = ['creation_date'] # build_obj_from_dict(self, data, keys, date_keys) def to_dict(self): fields_and_defaults = [ ('name', None), ('slug', None), ('description', None), ('short_description ', None), ('creator_id', None), ('creation_date', None), ('last_editor_id', None), ('last_update', None), ('geojson', {}), ('contacts', {}), ] dict_ = {v[0]: getattr(self, v[0], v[1]) for v in fields_and_defaults} dict_['tags'] = [tag.name for tag in self.tags.all()] dict_['target_audiences'] = [ ta.name for ta in self.target_audiences.all() ] dict_['categories'] = [cat.id for cat in self.categories.all()] return dict_
class User(GeoRefModel, BaseModel): """ User model. Replaces django.contrib.auth, CAS and social_auth with our own unified solution. its intended to use with external login providers. password: is set only if not created through external providers """ name = models.CharField(max_length=256, null=False) email = models.CharField(max_length=512, null=False, unique=True) about_me = models.TextField(null=True, blank=True, default='') password = models.CharField(max_length=256, null=False) contacts = ContactsField() creation_date = models.DateField(null=True, blank=True, auto_now_add=True) language = models.CharField(max_length=10, null=True, blank=True) # last_access = models.DateTimeField(null=True, blank=True) is_admin = models.BooleanField(default=False) is_active = models.BooleanField(default=False) # Deprecated # verification_key = models.CharField(max_length=32, null=True) # Attributes used by PermissionMixin private_fields = ['email'] internal_fields = ['password'] class Map: editable = False geometries = [POINT] categories = ['me', 'user'] min_zoom_geometry = 0 max_zoom_geometry = 100 min_zoom_point = 100 max_zoom_point = 100 min_zoom_icon = 100 max_zoom_icon = 10 @classmethod def calc_hash(self, s, salt=None): if not salt: salt = settings.USER_PASSWORD_SALT return unicode(sha1(salt + s).hexdigest()) def set_password(self, s, salt=None): self.password = self.calc_hash(s, salt=salt) def set_language(self, language_code): if translation.check_for_language(language_code): self.language = language_code return True return False def verify_password(self, s, salt=None): return self.password == self.calc_hash(s, salt) def is_authenticated(self): return True def is_anonymous(self): return False def is_superuser(self): return self.is_admin def __unicode__(self): return unicode(self.name) @property def url(self): return reverse('user_view', kwargs={'id': self.id}) @property def view_url(self): return self.url def files_set(self): """ pseudo-reverse query for retrieving Resource Files""" return UploadedFile.get_files_for(self) @property def avatar(self): url = '{}img/user-placeholder.png'.format(settings.STATIC_URL) files = self.files_set() for fl in files: if os.path.exists(fl.file.url[1:]): url = fl.file.url break return url def _social_auth_by_name(self, name): """ Retrieve the SocialAuth entry for this User given a high level social provider name. """ credentials = self.socialauth_set.filter(provider=PROVIDERS[name]) return credentials.get() if credentials.exists() else None def google(self): return self._social_auth_by_name('google') def facebook(self): return self._social_auth_by_name('facebook') # ==================== Interface for django admin ======================= # def is_staff(self): return self.is_admin def has_module_perms(self, mod): return self.is_admin def has_perm(self, perm): return self.is_admin # dummy fix for django weirdness =/ def get_and_delete_messages(self): pass # ==================== utils =========================================== # def from_dict(self, data): keys = [ 'id', 'name', 'email', 'password', 'contacts', 'geojson', 'creation_date', 'is_admin', 'is_active', 'about_me' ] date_keys = ['creation_date'] build_obj_from_dict(self, data, keys, date_keys) def to_dict(self): fields_and_defaults = [('id', None), ('name', None), ('email', None), ('contacts', {}), ('geojson', {}), ('url', ''), ('password', None), ('creation_date', None), ('is_admin', False), ('is_active', False), ('avatar', None), ('about_me', '')] dict_ = {v[0]: getattr(self, v[0], v[1]) for v in fields_and_defaults} return dict_ def is_valid(self, ignore=[]): self.errors = {} valid = True # verify required fields required = ['name', 'email', 'password'] for field in required: if not field in ignore and not getattr(self, field, None): valid, self.errors[field] = False, _('Required field') if not self.id: # new User if SocialAuth.objects.filter(email=self.email).exists(): valid = False self.errors['email'] = _( 'This email is registered on our ' 'system. You might have logged before with a social ' 'account (Facebook or Google). Please, skip this step ' 'and just login.') if User.objects.filter(email=self.email).exists(): valid = False self.errors['email'] = _('Email address already in use') return valid def send_confirmation_mail(self, request): """ send async confirmation mail """ key = Locker.deposit(self.id) verification_url = request.build_absolute_uri( reverse('user_verification', args=(key, ))) send_mail_async(title=_('Welcome to MootiroMaps'), receivers=[self.email], message=CONFIRMATION_EMAIL_MSG.format( name=self.name, verification_url=verification_url)) def send_recovery_mail(self, request): """ send async recovery mail """ key = Locker.deposit(self.id) recovery_url = request.build_absolute_uri( reverse('recover_password', args=(key, ))) send_mail_async(title=_('Password recovery'), receivers=[self.email], message=RECOVERY_EMAIL_MSG.format( name=self.name, recovery_url=recovery_url)) # DEPRECATED # def contributions(self, page=1, num=None): # """ return user's update """ # return get_user_updates(self, page=page, num=num) #### Compatibility (to be deprecated soon) def get_first_name(self): return self.name.split(' ')[0] def save(self, *args, **kwargs): r = super(User, self).save(*args, **kwargs) index_object_for_search.send(sender=self, obj=self) return r def projects_contributed(self): from komoo_project.models import Project return Project.get_projects_for_contributor(self)
class Project(BaseModel, geomodels.Model): name = models.CharField(max_length=1024) slug = models.SlugField(max_length=1024) description = models.TextField() short_description = models.CharField(max_length=250, null=True, blank=True) tags = TaggableManager() contributors = models.ManyToManyField(User, null=True, blank=True, related_name='project_contributors') community = models.ManyToManyField(Community, null=True, blank=True) contacts = ContactsField() logo = models.ForeignKey(UploadedFile, null=True, blank=True) creator = models.ForeignKey(User, editable=False, null=True, related_name='created_projects') creation_date = models.DateTimeField(auto_now_add=True) last_editor = models.ForeignKey(User, editable=False, null=True, blank=True, related_name='project_last_editor') last_update = models.DateTimeField(auto_now=True) _maptype = models.CharField(db_column='maptype', max_length=32, null=True, default=DEFAULT_MAPTYPE, editable=False) bounds_cache = geomodels.PolygonField(null=True, blank=True, editable=False) custom_bounds = geomodels.PolygonField(null=True, blank=True, editable=False) def __unicode__(self): return unicode(self.name) def slug_exists(self, slug): return Project.objects.filter(slug=slug).exists() def save(self, *a, **kw): self.slug = slugify(self.name) r = super(Project, self).save(*a, **kw) index_object_for_search.send(sender=self, obj=self) return r def partners_logo(self): """ pseudo-reverse query for retrieving the partners logo""" return UploadedFile.get_files_for(self) @property def all_contributors(self): seen = set() seen_add = seen.add iterable = itertools.chain(self.contributors.all(), [self.creator]) for element in itertools.ifilterfalse(seen.__contains__, iterable): seen_add(element) yield element @property def layers(self): return [ layer.to_dict() for layer in self.project_layers.order_by('position') ] @layers.setter def layers(self, data): for layer_ in data: id = layer_.get('id', None) if not id: # Create new layer layer = Layer() layer.project = self else: layer = Layer.objects.get(id=int(id)) if layer_.get('delete', False): # The layers is marked to be removed layer.delete() else: layer.from_dict(layer_) layer.save() @property def public(self): ''' Temporary property to avoid crashes. ''' return True @property def public_discussion(self): ''' Temporary property to avoid crashes. ''' return True def user_can_edit(self, user): return True def user_can_discuss(self, user): return True @property def home_url_params(self): return dict(id=self.id) @property def view_url(self): return reverse('project_view', kwargs=self.home_url_params) @property def edit_url(self): return reverse('project_edit', kwargs=self.home_url_params) @property def perm_id(self): return 'j%d' % self.id # project, and not Proposal @property def logo_url(self): if self.logo: return self.logo.file.url else: return '{}img/project-placeholder.png'.format(settings.STATIC_URL) @property def related_objects(self): """Returns a queryset for the objects for a given project""" return ProjectRelatedObject.objects.filter(project=self) def filter_related_items(self, query, models): items = [] for model in models: ct = ContentType.objects.get_for_model(model) obj_ids = (self.related_objects.values_list( "object_id", flat=True).filter(content_type=ct)) obj = model.objects.filter(Q(pk__in=obj_ids) & query) for o in obj: items.append(o) return items def save_related_object(self, related_object, user=None, silent=False): ct = ContentType.objects.get_for_model(related_object) # Adds the object to project obj, created = ProjectRelatedObject.objects.get_or_create( content_type_id=ct.id, object_id=related_object.id, project_id=self.id) self._update_bounds_cache() if user: # Adds user as contributor self.contributors.add(user) # Creates update entry if created and not silent: from update.models import Update from update.signals import create_update create_update.send(sender=obj.__class__, user=user, instance=obj, type=Update.EDIT) return created @property def related_items(self): #return itertools.chain(self.all_contributors, # self.filter_related_items(Q(), get_models())) return self.filter_related_items(Q(), get_models()) @property def bounds(self): if not self.bounds_cache: self._update_bounds_cache() return self.bounds_cache def _update_bounds_cache(self): # Get the project items items = self.related_items bounds = None for item in items: if not item.geometry.empty: if not bounds: bounds = item.bounds else: bounds = Polygon.from_bbox( bounds.envelope.union(item.bounds.envelope).extent) self.bounds_cache = bounds self.save() return bounds @property def bbox(self): coords = self.bounds.coords[0] return [coords[0][1], coords[0][0], coords[2][1], coords[2][0]] @property def custom_bbox(self): if not self.custom_bounds: return None coords = self.custom_bounds.coords[0] return [coords[0][1], coords[0][0], coords[2][1], coords[2][0]] @custom_bbox.setter def custom_bbox(self, value): self.custom_bounds = Polygon.from_bbox(tuple(value)) @property def maptype(self): return self._maptype or DEFAULT_MAPTYPE @maptype.setter def maptype(self, value): self._maptype = value @property def json(self): return to_json({ 'name': self.name, 'slug': self.slug, 'logo_url': self.logo_url, 'view_url': self.view_url, 'partners_logo': [{ 'url': logo.file.url } for logo in self.partners_logo()], 'bbox': self.bbox, 'custom_bbox': self.custom_bbox, 'maptype': self.maptype, }) @property def geojson(self): items = [] for obj in self.related_items: if obj and not obj.is_empty(): items.append(obj) return create_geojson(items) @classmethod def get_projects_for_contributor(cls, user): return Project.objects.filter( Q(contributors__in=[user]) | Q(creator=user)).distinct() # ========================================================================== # Utils # def from_dict(self, data): # keys = ['id', 'name', 'contact', 'geojson', 'creation_date', # 'is_admin', 'is_active', 'about_me'] # date_keys = ['creation_date'] # build_obj_from_dict(self, data, keys, date_keys) def to_dict(self): fields_and_defaults = [ ('name', None), ('slug', None), ('description', None), ('short_description ', None), ('creator_id', None), ('creation_date', None), ('last_editor_id', None), ('last_update', None), ('logo_id', None), ('contacts', {}), ('bounds', None), ] dict_ = {v[0]: getattr(self, v[0], v[1]) for v in fields_and_defaults} dict_['tags'] = [tag.name for tag in self.tags.all()] dict_['community'] = [comm.id for comm in self.community.all()] dict_['contributors'] = [cont.name for cont in self.contributors.all()] # TODO: related_objects return dict_
class Investment(models.Model): """A donation of money (or any other stuff) for either an Organization, a Proposal or a Resource in the system. """ CURRENCIES_CHOICES = ( ('BRL', _('Brazilian Real (BRL)')), ('USD', _('US-Dollar (USD)')), ('EUR', _('Euro')), ) name = models.CharField(max_length=256) # Auto-generated url slug. It's not editable via ModelForm. slug = models.CharField(max_length=256, null=False, blank=False, db_index=True, editable=False) description = models.TextField() short_description = models.CharField(max_length=250, null=True, blank=True) contacts = ContactsField() value = models.DecimalField(decimal_places=2, max_digits=14, null=True, blank=True) currency = models.CharField(max_length=3, choices=CURRENCIES_CHOICES, null=True, blank=True) date = models.DateField(null=False) # TODO: remove over_period. Get this info by existence of an end_date over_period = models.BooleanField(default=False) end_date = models.DateField(null=True) # Meta info creator = models.ForeignKey(User, editable=False, null=True, related_name='created_investments') creation_date = models.DateTimeField(auto_now_add=True) last_editor = models.ForeignKey(User, editable=False, null=True, blank=True) last_update = models.DateTimeField(auto_now=True) # Relationships investor = models.ForeignKey(Investor, related_name="investments", null=True, blank=True) # Grantee generic relationship grantee_content_type = models.ForeignKey(ContentType, editable=False) grantee_object_id = models.PositiveIntegerField(editable=False) grantee = generic.GenericForeignKey('grantee_content_type', 'grantee_object_id') tags = TaggableManager() def __unicode__(self): return unicode(self.name) @property def title(self): return self.name @property def community(self): return self.grantee.community def save(self, *args, **kwargs): # TODO: validate grantee as either a Proposal, a Resource or # an Organization # TODO: validate investor as either a User or an Organization self.slug = slugify(self.name) super(Investment, self).save(*args, **kwargs) # Url aliases @property def view_url(self): return reverse('view_investment', kwargs={'id': self.id}) @property def edit_url(self): return reverse('edit_investment', kwargs={'id': self.id}) @property def perm_id(self): return 'i%d' % self.id def is_empty(self): return True