#!/usr/bin/env python # -*- coding: utf-8 -*- # Copyright (C) 2010 Étienne Loks # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as # published by the Free Software Foundation, either version 3 of the # License, or (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # See the file COPYING for details. """ Models description """ import datetime from django.core.exceptions import ObjectDoesNotExist, ValidationError from django.core.validators import validate_slug from django.utils.translation import ugettext_lazy as _, ugettext from django.db.utils import DatabaseError from django.db.models import Q from django.contrib.auth.models import User from django.contrib.gis.db import models from django.contrib import admin from simple_history.models import HistoricalRecords from ishtar import settings # valid ID validator for models def valid_id(cls): def func(value): try: cls.objects.get(pk=value) except ObjectDoesNotExist: raise ValidationError(_(u"Not a valid item.")) return func # unique validator for models def is_unique(cls, field): def func(value): query = {field:value} try: assert cls.objects.filter(**query).count() == 0 except AssertionError: raise ValidationError(_(u"This item already exist.")) return func class OwnPerms: """ Manage special permissions for object's owner """ @classmethod def get_query_owns(cls, user): """ Query object to get own items """ return None # implement for each object def is_own(self, user): """ Check if the current object is owned by the user """ query = self.get_query_owns(user) if not query: return False query = query & Q(pk=self.pk) return cls.objects.filter(query).count() @classmethod def has_item_of(cls, user): """ Check if the user own some items """ query = cls.get_query_owns(user) if not query: return False return cls.objects.filter(query).count() @classmethod def get_owns(cls, user): """ Get Own items """ if isinstance(user, User): user = IshtarUser.objects.get(user_ptr=user) if user.is_anonymous(): return [] query = cls.get_query_owns(user) if not query: return [] return cls.objects.filter(query).order_by(*cls._meta.ordering).all() class GeneralType(models.Model): """ Abstract class for "types" """ label = models.CharField(_(u"Label"), max_length=100) txt_idx = models.CharField(_(u"Textual identifier"), validators=[validate_slug], max_length=30, unique=True) comment = models.TextField(_(u"Comment"), blank=True, null=True) available = models.BooleanField(_(u"Available")) class Meta: abstract = True def __unicode__(self): return self.label @classmethod def get_types(cls): yield ('', '--') for item in cls.objects.filter(available=True).all(): yield (item.id, _(item.label)) class BaseHistorizedItem(models.Model): history_modifier = models.ForeignKey(User, related_name='+', verbose_name=_(u"Last modifier")) def save(self, *args, **kwargs): try: self.history_modifier except ObjectDoesNotExist: return super(BaseHistorizedItem, self).save(*args, **kwargs) return True class Meta: abstract = True class LightHistorizedItem(BaseHistorizedItem): history_date = models.DateTimeField(default=datetime.datetime.now) class Meta: abstract = True class Departement(models.Model): label = models.CharField(_(u"Label"), max_length=30) number = models.CharField(_(u"Number"), unique=True, max_length=3) class Meta: verbose_name = _(u"Departement") verbose_name_plural = _(u"Departements") ordering = ['number'] def __unicode__(self): return unicode(self.number) + u" - " + self.label class Address(BaseHistorizedItem): address = models.TextField(_(u"Address"), null=True, blank=True) address_complement = models.TextField(_(u"Address complement"), null=True, blank=True) postal_code = models.CharField(_(u"Postal code"), max_length=10, null=True, blank=True) town = models.CharField(_(u"Town"), max_length=30, null=True, blank=True) country = models.CharField(_(u"Country"), max_length=30, null=True, blank=True) phone = models.CharField(_(u"Phone"), max_length=18, null=True, blank=True) mobile_phone = models.CharField(_(u"Mobile phone"), max_length=18, null=True, blank=True) history = HistoricalRecords() class Meta: abstract = True class OrganizationType(GeneralType): class Meta: verbose_name = _(u"Organization type") verbose_name_plural = _(u"Organization types") class Organization(Address, OwnPerms): name = models.CharField(_(u"Name"), max_length=100) organization_type = models.ForeignKey(OrganizationType, verbose_name=_(u"Type")) history = HistoricalRecords() class Meta: verbose_name = _(u"Organization") verbose_name_plural = _(u"Organizations") permissions = ( ("view_own_organization", ugettext(u"Can view own Organization")), ("add_own_organization", ugettext(u"Can add own Organization")), ("change_own_organization", ugettext(u"Can change own Organization")), ("delete_own_organization", ugettext(u"Can delete own Organization")), ) def __unicode__(self): return self.name class PersonType(GeneralType): class Meta: verbose_name = _(u"Person type") verbose_name_plural = _(u"Person types") class Person(Address, OwnPerms) : TYPE = (('Mr', _(u'Mr')), ('Ms', _(u'Miss')), ('Md', _(u'Mrs')), ('Dr', _(u'Doctor')), ) title = models.CharField(_(u"Title"), max_length=2, choices=TYPE) surname = models.CharField(_(u"Surname"), max_length=20) name = models.CharField(_(u"Name"), max_length=30) email = models.CharField(_(u"Email"), max_length=40, blank=True, null=True) person_type = models.ForeignKey(PersonType, verbose_name=_(u"Type")) attached_to = models.ForeignKey('Organization', verbose_name=_(u"Is attached to"), blank=True, null=True) is_author = models.NullBooleanField(_(u"Is an author?"), blank=True, null=True) in_charge_storage = models.NullBooleanField(_(u"In charge of a storage?"), blank=True, null=True) class Meta: verbose_name = _(u"Person") verbose_name_plural = _(u"Persons") permissions = ( ("view_person", ugettext(u"Can view Person")), ("view_own_person", ugettext(u"Can view own Person")), ("add_own_person", ugettext(u"Can add own Person")), ("change_own_person", ugettext(u"Can change own Person")), ("delete_own_person", ugettext(u"Can delete own Person")), ) def __unicode__(self): lbl = u"%s %s - " % (self.name, self.surname) if self.attached_to: lbl += unicode(self.attached_to) else: lbl += self.email return lbl class IshtarUser(User): person = models.ForeignKey(Person, verbose_name=_(u"Person"), unique=True) class Meta: verbose_name = _(u"Ishtar user") verbose_name_plural = _(u"Ishtar users") class FileType(GeneralType): class Meta: verbose_name = _(u"Archaeological file type") verbose_name_plural = _(u"Archaeological file types") @classmethod def is_preventive(cls, file_type_id): try: preventive = FileType.objects.get(txt_idx="preventive").pk return file_type_id == preventive except ObjectDoesNotExist: return False class PermitType(GeneralType): class Meta: verbose_name = _(u"Permit type") verbose_name_plural = _(u"Permit types") if settings.COUNTRY == 'fr': class SaisineType(GeneralType): delay = models.IntegerField(_(u"Delay (in days)")) class Meta: verbose_name = u"Type Saisine" verbose_name_plural = u"Types Saisine" class File(BaseHistorizedItem, OwnPerms): year = models.IntegerField(_(u"Year"), default=lambda:datetime.datetime.now().year) numeric_reference = models.IntegerField(_(u"Numeric reference")) internal_reference = models.CharField(_(u"Internal reference"), max_length=60, unique=True) file_type = models.ForeignKey(FileType, verbose_name=_(u"File type")) in_charge = models.ForeignKey(Person, related_name='+', verbose_name=_(u"Person in charge")) general_contractor = models.ForeignKey(Person, related_name='+', verbose_name=_(u"General contractor"), blank=True, null=True) town_planning_service = models.ForeignKey(Organization, related_name='+', verbose_name=_(u"Town planning service"), blank=True, null=True) permit_type = models.ForeignKey(PermitType, verbose_name=_(u"Permit type"), blank=True, null=True) permit_reference = models.CharField(_(u"Permit reference"), max_length=60, blank=True, null=True) is_active = models.BooleanField(_(u"Is active?"), default=True) towns = models.ManyToManyField("Town") creation_date = models.DateField(_(u"Creation date"), default=datetime.datetime.now) reception_date = models.DateField(_(u'Reception date'), blank=True, null=True) if settings.COUNTRY == 'fr': saisine_type = models.ForeignKey(SaisineType, blank=True, null=True, verbose_name= u"Type de saisine") reference_number = models.IntegerField(_(u"Reference number"), blank=True, null=True) total_surface = models.IntegerField(_(u"Total surface")) total_developed_surface = models.IntegerField(_(u"Total developed surface"), blank=True, null=True) address = models.TextField(_(u"Main address"), null=True, blank=True) address_complement = models.TextField(_(u"Main address - complement"), null=True, blank=True) postal_code = models.CharField(_(u"Main address - postal code"), max_length=10, null=True, blank=True) comment = models.TextField(_(u"Comment")) history = HistoricalRecords() class Meta: verbose_name = _(u"Archaeological file") verbose_name_plural = _(u"Archaeological files") permissions = ( ("view_own_file", ugettext(u"Can view own Archaelogical file")), ("add_own_file", ugettext(u"Can add own Archaelogical file")), ("change_own_file", ugettext(u"Can change own Archaelogical file")), ("delete_own_file", ugettext(u"Can delete own Archaelogical file")), ) ordering = ['-year', '-numeric_reference'] def __unicode__(self): items = [unicode(_('Intercommunal'))] if self.towns.count() == 1: items[0] = unicode(self.towns.all()[0]) items.append("-".join((unicode(self.year), unicode(self.numeric_reference)))) items += [unicode(getattr(self, k))[:36] for k in ['internal_reference',] if getattr(self, k)] return u" - ".join(items) @classmethod def get_query_owns(cls, user): return Q(history_modifier=user) & Q(is_active=True) class OperationType(GeneralType): class Meta: verbose_name = _(u"Operation type") verbose_name_plural = _(u"Operation types") class RemainType(GeneralType): class Meta: verbose_name = _(u"Remain type") verbose_name_plural = _(u"Remain types") class Operation(BaseHistorizedItem, OwnPerms): start_date = models.DateField(_(u"Start date"), null=True, blank=True) end_date = models.DateField(_(u"Closing date"), null=True, blank=True) in_charge = models.ForeignKey('Person', related_name='+', verbose_name=_(u"In charge")) year = models.IntegerField(_(u"Year")) operation_code = models.IntegerField(_(u"Operation code")) associated_file = models.ForeignKey(File, related_name='+', verbose_name=_(u"File"), blank=True, null=True) operation_type = models.ForeignKey(OperationType, related_name='+', verbose_name=_(u"Operation type")) remains = models.ManyToManyField("RemainType", verbose_name=_(u'Remains')) towns = models.ManyToManyField("Town", verbose_name=_(u"Towns")) if settings.COUNTRY == 'fr': code_patriarche = models.IntegerField(u"Code PATRIARCHE", null=True, blank=True) code_dracar = models.CharField(u"Code DRACAR", max_length=10, null=True, blank=True) comment = models.TextField(_(u"Comment"), null=True, blank=True) history = HistoricalRecords() class Meta: verbose_name = _(u"Operation") verbose_name_plural = _(u"Operations") permissions = ( ("view_own_operation", ugettext(u"Can view own Operation")), ("add_own_operation", ugettext(u"Can add own Operation")), ("change_own_operation", ugettext(u"Can change own Operation")), ("delete_own_operation", ugettext(u"Can delete own Operation")), ) def __unicode__(self): items = [unicode(_('Intercommunal'))] if self.towns.count() == 1: items[0] = unicode(self.towns.all()[0]) items.append("-".join((unicode(self.year), unicode(self.operation_code)))) return u" - ".join(items) def is_own(self, person): return False @classmethod def get_query_owns(cls, user): return Q(in_charge=user.person)|Q(history_modifier=user)\ & Q(end_date__isnull=True) class Parcel(LightHistorizedItem): associated_file = models.ForeignKey(File, related_name='parcels', blank=True, null=True, verbose_name=_(u"File")) operation = models.ForeignKey(Operation, related_name='parcel', blank=True, null=True, verbose_name=_(u"Operation")) year = models.IntegerField(_(u"Year"), default=lambda:datetime.datetime.now().year) town = models.ForeignKey("Town", related_name='+', verbose_name=_(u"Town")) section = models.CharField(_(u"Section"), max_length=4) parcel_number = models.CharField(_(u"Parcel number"), max_length=6) class Meta: verbose_name = _(u"Parcel") verbose_name_plural = _(u"Parcels") def __unicode__(self): return u" - ".join([unicode(item) for item in \ [self.associated_file, self.operation, self.section, self.parcel_number] if item]) class Period(GeneralType) : order = models.IntegerField(_(u"Order")) start_date = models.IntegerField(_(u"Start date")) end_date = models.IntegerField(_(u"End date")) parent = models.ForeignKey("Period", verbose_name=_(u"Parent period")) class Meta: verbose_name = _(u"Type Period") verbose_name_plural = _(u"Types Period") def __unicode__(self): return self.label class DatingType(GeneralType): class Meta: verbose_name = _(u"Dating type") verbose_name_plural = _(u"Dating types") class DatingQuality(GeneralType): class Meta: verbose_name = _(u"Dating quality") verbose_name_plural = _(u"Dating qualities") class Dating(models.Model): period = models.ForeignKey(Period, verbose_name=_(u"Period")) start_date = models.IntegerField(_(u"Start date")) end_date = models.IntegerField(_(u"End date")) dating_type = models.ForeignKey(DatingType, verbose_name=_(u"Dating type")) quality = models.ForeignKey(DatingQuality, verbose_name=_(u"Quality")) class Meta: verbose_name = _(u"Dating") verbose_name_plural = _(u"Datings") class RegistrationUnit(BaseHistorizedItem, OwnPerms): parcel = models.ForeignKey(Parcel, verbose_name=_(u"Parcel")) label = models.CharField(_(u"Label"), max_length=200) description = models.TextField(_("Description")) lenght = models.IntegerField(_(u"Lenght")) width = models.IntegerField(_(u"Width")) thickness = models.IntegerField(_(u"Thickness")) depth = models.IntegerField(_(u"Depth")) has_furniture = models.BooleanField(u"Has furniture?") interpretation = models.TextField(_(u"Interpretation")) filling = models.TextField(_(u"Filling")) datings = models.ManyToManyField(Dating) history = HistoricalRecords() class Meta: verbose_name = _(u"Registration Unit") verbose_name_plural = _(u"Registration Units") permissions = ( ("view_own_registrationunit", ugettext(u"Can view own Registration Unit")), ("add_own_registrationunit", ugettext(u"Can add own Registration Unit")), ("change_own_registrationunit", ugettext(u"Can change own Registration Unit")), ("delete_own_registrationunit", ugettext(u"Can delete own Registration Unit")), ) def __unicode__(self): return u"%s - %s" % (self.parcel, self.label) class SourceType(GeneralType): class Meta: verbose_name = _(u"Source type") verbose_name_plural = _(u"Source types") class Source(models.Model) : title = models.CharField(_(u"Title"), max_length=200) source_type = models.ForeignKey(SourceType, verbose_name=_(u"Type")) class Meta: verbose_name = _(u"Source") verbose_name_plural = _(u"Sources") def __unicode__(self): return self.title class MaterialType(GeneralType): recommendation = models.TextField(_(u"Recommendation")) parent = models.ForeignKey("MaterialType", blank=True, null=True, verbose_name=_(u"Parent material")) class Meta: verbose_name = _(u"Material type") verbose_name_plural = _(u"Material types") class BaseItem(BaseHistorizedItem, OwnPerms): label = models.CharField(_(u"Label"), max_length=60) description = models.TextField(_(u"Description")) registration_unit = models.ForeignKey(RegistrationUnit, verbose_name=_(u"Registration Unit")) is_isolated = models.BooleanField(_(u"Is isolated?")) documentations = models.ManyToManyField(Source) history = HistoricalRecords() class Meta: verbose_name = _(u"Base item") verbose_name_plural = _(u"Base items") permissions = ( ("view_own_baseitem", ugettext(u"Can view own Base item")), ("add_own_baseitem", ugettext(u"Can add own Base item")), ("change_own_baseitem", ugettext(u"Can change own Base item")), ("delete_own_baseitem", ugettext(u"Can delete own Base item")), ) def __unicode__(self): return self.label class Item(BaseHistorizedItem, OwnPerms): base_items = models.ManyToManyField(BaseItem, verbose_name=_(u"Base item")) order = models.IntegerField(_(u"Order")) label = models.CharField(_(u"Label"), max_length=60) description = models.TextField(_(u"Description")) material_type = models.ForeignKey(MaterialType, verbose_name = _(u"Material type")) volume = models.FloatField(_(u"Volume")) weight = models.IntegerField(_(u"Weight")) item_number = models.IntegerField(_("Item number")) upstream_treatment = models.ForeignKey("Treatment", related_name='downstream_treatment', verbose_name=_("Upstream treatment")) downstream_treatment = models.ForeignKey("Treatment", related_name='upstream_treatment', verbose_name=_("Downstream treatment")) dating = models.ForeignKey(Dating, verbose_name=_(u"Dating")) history = HistoricalRecords() class Meta: verbose_name = _(u"Item") verbose_name_plural = _(u"Items") permissions = ( ("view_own_item", ugettext(u"Can view own Item")), ("add_own_item", ugettext(u"Can add own Item")), ("change_own_item", ugettext(u"Can change own Item")), ("delete_own_item", ugettext(u"Can delete own Item")), ) def __unicode__(self): return self.label class ParcelOwner(LightHistorizedItem): owner = models.ForeignKey(Person, verbose_name=_(u"Owner")) parcel = models.ForeignKey(Parcel, verbose_name=_(u"Parcel")) start_date = models.DateField(_(u"Start date")) end_date = models.DateField(_(u"End date")) class Meta: verbose_name = _(u"Parcel owner") verbose_name_plural = _(u"Parcel owners") def __unicode__(self): return self.owner + u" - " + self.parcel class WarehouseType(GeneralType): class Meta: verbose_name = _(u"Warehouse type") verbose_name_plural = _(u"Warehouse types") class Warehouse(Address, OwnPerms): name = models.CharField(_(u"Name"), max_length=40) warehouse_type = models.ForeignKey(WarehouseType, verbose_name=_(u"Warehouse type")) person_in_charge = models.ForeignKey(Person, verbose_name=_(u"Person in charge")) comment = models.TextField(_(u"Comment")) class Meta: verbose_name = _(u"Warehouse") verbose_name_plural = _(u"Warehouses") permissions = ( ("view_own_warehouse", ugettext(u"Can view own Warehouse")), ("add_own_warehouse", ugettext(u"Can add own Warehouse")), ("change_own_warehouse", ugettext(u"Can change own Warehouse")), ("delete_own_warehouse", ugettext(u"Can delete own Warehouse")), ) def __unicode__(self): return unicode(self.warehouse_type) class ActType(GeneralType): TYPE = (('F', _(u'Archaelogical file')), ('O', _(u'Operation')), ) intented_to = models.CharField(_(u"Intended to"), max_length=1, choices=TYPE) class Meta: verbose_name = _(u"Act type") verbose_name_plural = _(u"Act types") class AdministrativeAct(BaseHistorizedItem, OwnPerms): act_type = models.ForeignKey(ActType, verbose_name=_(u"Act type")) in_charge = models.ForeignKey(Person, blank=True, null=True, related_name='+', verbose_name=_(u"Person in charge of the operation")) operator = models.ForeignKey(Organization, blank=True, null=True, verbose_name=_(u"Archaeological preventive operator")) scientific = models.ForeignKey(Person, blank=True, null=True, related_name='+', verbose_name=_(u"Person in charge of the scientific part")) signatory = models.ForeignKey(Person, blank=True, null=True, related_name='+', verbose_name=_(u"Signatory")) operation = models.ForeignKey(Operation, blank=True, null=True, related_name='+', verbose_name=_(u"Operation")) associated_file = models.ForeignKey(File, blank=True, null=True, related_name='+', verbose_name=_(u"Archaelogical file")) signature_date = models.DateField(_(u"Signature date")) act_object = models.CharField(_(u"Object"), max_length=200) if settings.COUNTRY == 'fr': ref_sra = models.CharField(u"Référence SRA", max_length=15) history = HistoricalRecords() class Meta: verbose_name = _(u"Administrative act") verbose_name_plural = _(u"Administrative acts") permissions = ( ("view_own_administrativeact", ugettext(u"Can view own Administrative act")), ("add_own_administrativeact", ugettext(u"Can add own Administrative act")), ("change_own_administrativeact", ugettext(u"Can change own Administrative act")), ("delete_own_administrativeact", ugettext(u"Can delete own Administrative act")), ) def __unicode__(self): return self.operation + u" - " + self.fact_object class ContainerType(GeneralType): lenght = models.IntegerField(_(u"Lenght")) width = models.IntegerField(_(u"Width")) height = models.IntegerField(_(u"Height")) volume = models.IntegerField(_(u"Volume")) reference = models.CharField(_(u"Reference"), max_length=30) class Meta: verbose_name = _(u"Container type") verbose_name_plural = _(u"Container types") class Container(LightHistorizedItem): reference = models.CharField(_(u"Reference"), max_length=15) location = models.ForeignKey(Warehouse, verbose_name=_(u"Location")) container_type = models.ForeignKey(ContainerType, verbose_name=_("Container type")) reference = models.CharField(_(u"Reference"), max_length=40) comment = models.TextField(_(u"Comment")) class Meta: verbose_name = _(u"Container") verbose_name_plural = _(u"Containers") if settings.COUNTRY == 'fr': class Arrondissement(models.Model): name = models.CharField(u"Nom", max_length=30) department = models.ForeignKey(Departement, verbose_name=u"Département") def __unicode__(self): return u"%s - %s" % (self.name, unicode(self.department)) class Canton(models.Model): name = models.CharField(u"Nom", max_length=30) arrondissement = models.ForeignKey(Arrondissement, verbose_name=u"Arrondissement") def __unicode__(self): return u"%s - %s" % (self.name, unicode(self.arrondissement)) class Town(models.Model): name = models.CharField(_(u"Name"), max_length=100) surface = models.IntegerField(_(u"Surface"), blank=True, null=True) center = models.PointField(_(u"Localisation"), srid=settings.SRID, blank=True, null=True) if settings.COUNTRY == 'fr': numero_insee = models.CharField(u"Numéro INSEE", max_length=6, unique=True) departement = models.ForeignKey(Departement, verbose_name=u"Département", null=True, blank=True) canton = models.ForeignKey(Canton, verbose_name=u"Canton", null=True, blank=True) objects = models.GeoManager() class Meta: verbose_name = _(u"Town") verbose_name_plural = _(u"Towns") if settings.COUNTRY == 'fr': ordering = ['numero_insee'] def __unicode__(self): if settings.COUNTRY == "fr": return " - ".join((self.name, self.numero_insee)) return self.name class TreatmentType(GeneralType): virtual = models.BooleanField(_(u"Virtual")) class Meta: verbose_name = _(u"Treatment type") verbose_name_plural = _(u"Treatment types") class Treatment(BaseHistorizedItem, OwnPerms): container = models.ForeignKey(Container, verbose_name=_(u"Container")) treatment_type = models.ForeignKey(TreatmentType, verbose_name=_(u"Treatment type")) location = models.ForeignKey(Warehouse, verbose_name=_(u"Location")) person = models.ForeignKey(Person, verbose_name=_(u'Person')) start_date = models.DateField(_(u"Start date")) end_date = models.DateField(_(u"End date")) history = HistoricalRecords() class Meta: verbose_name = _(u"Treatment") verbose_name_plural = _(u"Treatments") permissions = ( ("view_own_treatment", ugettext(u"Can view own Treatment")), ("add_own_treatment", ugettext(u"Can add own Treatment")), ("change_own_treatment", ugettext(u"Can change own Treatment")), ("delete_own_treatment", ugettext(u"Can delete own Treatment")), ) def __unicode__(self): return self.item class AuthorType(GeneralType): class Meta: verbose_name = _(u"Author type") verbose_name_plural = _(u"Author types") class Author(models.Model): person = models.ForeignKey(Person, verbose_name=_(u"Person")) source = models.ForeignKey(Source, verbose_name=_(u"Source")) author_type = models.ForeignKey(AuthorType, verbose_name=_(u"Author type")) class Meta: verbose_name = _(u"Author") verbose_name_plural = _(u"Authors") def __unicode__(self): return self.person + u" - " + self.source class Property(LightHistorizedItem): item = models.ForeignKey(Item, verbose_name=_(u"Item")) administrative_act = models.ForeignKey(AdministrativeAct, verbose_name=_(u"Administrative act")) person = models.ForeignKey(Person, verbose_name=_(u"Person")) start_date = models.DateField(_(u"Start date")) end_date = models.DateField(_(u"End date")) class Meta: verbose_name = _(u"Property") verbose_name_plural = _(u"Properties") def __unicode__(self): return self.person + u" - " + self.item