diff --git a/doc/source/coding_rules.rst b/doc/source/coding_rules.rst new file mode 100644 index 00000000..421a8d79 --- /dev/null +++ b/doc/source/coding_rules.rst @@ -0,0 +1,57 @@ + +============ +Coding rules +============ + +Django models +============= + +* All model names in singular an CamelCase. + +* All models have a **Meta** with at least: + + - **verbose_name** and **verbose_name_plural**: unicode strings, lowercase, with spaces. + - **ordering**: return a consistent order, using pk if no other unique field or combination exists. + +* All models have **__unicode__** method, returning a human-readable, descriptive, short text. + +* All fields have **verbose_name**. Also **help_text** if needed to fully explain the field meaning. + +* All fields have explicit **blank** and **null** parameters. Use only those combinations, unless + there a documented need of other thing: + + Normal fields (IntegerField, DateField, ForeignKey, FileField...) + - (optional) **null = True**, **blank = True** + - (required) **null = False**, **blank = False** + + Text fields (CharField, TextField, URLField...) + - (optional) **null = False**, **blank = True** + - (required) **null = False**, **blank = False** + + Boolean fields: + - (two values, T/F) **null = False**, **blank = True** + - (three values, T/F/Null) **null = False**, **blank = True** + +* Don't create text fields with **null = True**, unless you need to distinguish between empty string and None. + +* Don't create boolean fields with **blank = False**, otherwise they could only be True. + +Example:: + + class SomeClass(models.Model): + name = models.CharField(max_length=100, null = False, blank = False, unique=True, + verbose_name = _(u'name')) + slug = models.SlugField(max_length=100, null = False, blank = False, unique=True, + verbose_name = _(u'slug'), + help_text = (u'Identifier of this object. Only letters, digits and underscore "_" allowed.')) + text = models.TextField(null = False, blank = True, + verbose_name = _(u'text')) + + class Meta: + verbose_name = _(u'some class') + verbose_name_plural = _(u'some classes') + ordering = ['name'] + + def __unicode__(self): + return self.name + diff --git a/doc/source/index.rst b/doc/source/index.rst index 99b43eb5..16d33901 100755 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -30,6 +30,7 @@ Contents: overview.rst settings.rst + coding_rules.rst diff --git a/greenmine/base/models.py b/greenmine/base/models.py index 0d11fe14..6f4f1d06 100644 --- a/greenmine/base/models.py +++ b/greenmine/base/models.py @@ -62,9 +62,13 @@ class Role(models.Model): permissions = models.ManyToManyField('auth.Permission', verbose_name=_('permissions'), blank=True) - def __unicode__(self): - return unicode(self.name) + class Meta: + verbose_name = u'role' + verbose_name_plural = u'roles' + ordering = ['slug'] + def __unicode__(self): + return self.name # Patch api view for correctly return 401 responses on diff --git a/greenmine/documents/models.py b/greenmine/documents/models.py index c2b80b0b..b18bb031 100644 --- a/greenmine/documents/models.py +++ b/greenmine/documents/models.py @@ -20,16 +20,22 @@ class Document(models.Model): null=True, blank=True) tags = DictField() - def save(self, *args, **kwargs): - if not self.slug: - self.slug = slugify(self.title, self.__class__) - super(Document, self).save(*args, **kwargs) - class Meta: - ordering = ['title'] + verbose_name = u'document' + verbose_name_plural = u'document' + ordering = ['project', 'title', 'id'] permissions = ( ('can_download_from_my_projects', 'Can download the documents from my projects'), ('can_download_from_other_projects', 'Can download the documents from other projects'), ('can_change_owned_documents', 'Can modify owned documents'), ('can_view_documents', 'Can modify owned documents'), ) + + def __unicode__(self): + return self.title + + def save(self, *args, **kwargs): + if not self.slug: + self.slug = slugify(self.title, self.__class__) + super(Document, self).save(*args, **kwargs) + diff --git a/greenmine/questions/models.py b/greenmine/questions/models.py index 6bd6c784..e804fe17 100644 --- a/greenmine/questions/models.py +++ b/greenmine/questions/models.py @@ -27,11 +27,17 @@ class Question(models.Model): tags = DictField() class Meta: + verbose_name = u'question' + verbose_name_plural = u'questions' + ordering = ['project', 'subject', 'id'] permissions = ( ('can_reply_question', 'Can reply questions'), ('can_change_owned_question', 'Can modify owned questions'), ) + def __unicode__(self): + return self.subject + def save(self, *args, **kwargs): if not self.slug: self.slug = slugify_uniquely(self.subject, self.__class__) @@ -48,3 +54,12 @@ class QuestionResponse(models.Model): question = models.ForeignKey('Question', related_name='responses') owner = models.ForeignKey('base.User', related_name='questions_responses') tags = DictField() + + class Meta: + verbose_name = u'question response' + verbose_name_plural = u'question responses' + ordering = ['question', 'created_date'] + + def __unicode__(self): + return u'{0} - response {1}'.format(unicode(self.question), self.id) + diff --git a/greenmine/scrum/models.py b/greenmine/scrum/models.py index db11ebd5..cc9a4b9f 100644 --- a/greenmine/scrum/models.py +++ b/greenmine/scrum/models.py @@ -22,10 +22,13 @@ class Severity(models.Model): project = models.ForeignKey("Project", related_name="severities") class Meta: + verbose_name = u'severity' + verbose_name_plural = u'severities' + ordering = ['project', 'name'] unique_together = ('project', 'name') def __unicode__(self): - return u"project({0})/severity({1})".format(self.project.id, self.name) + return u"project {0} - {1}".format(self.project_id, self.name) class IssueStatus(models.Model): @@ -35,10 +38,13 @@ class IssueStatus(models.Model): project = models.ForeignKey("Project", related_name="issuestatuses") class Meta: + verbose_name = u'issue status' + verbose_name_plural = u'issue statuses' + ordering = ['project', 'name'] unique_together = ('project', 'name') def __unicode__(self): - return u"project({0})/issue-status({1})".format(self.project.id, self.name) + return u"project {0} - {1}".format(self.project_id, self.name) class TaskStatus(models.Model): @@ -49,10 +55,13 @@ class TaskStatus(models.Model): project = models.ForeignKey("Project", related_name="taskstatuses") class Meta: + verbose_name = u'task status' + verbose_name_plural = u'task statuses' + ordering = ['project', 'name'] unique_together = ('project', 'name') def __unicode__(self): - return u"project({0})/task-status({1})".format(self.project.id, self.name) + return u"project {0} - {1}".format(self.project_id, self.name) class UserStoryStatus(models.Model): @@ -62,10 +71,13 @@ class UserStoryStatus(models.Model): project = models.ForeignKey("Project", related_name="usstatuses") class Meta: + verbose_name = u'user story status' + verbose_name_plural = u'user story statuses' + ordering = ['project', 'name'] unique_together = ('project', 'name') def __unicode__(self): - return u"project({0})/us-status({1})".format(self.project.id, self.name) + return u"project {0} - {1}".format(self.project_id, self.name) class Priority(models.Model): @@ -74,10 +86,13 @@ class Priority(models.Model): project = models.ForeignKey("Project", related_name="priorities") class Meta: + verbose_name = u'priority' + verbose_name_plural = u'priorities' + ordering = ['project', 'name'] unique_together = ('project', 'name') def __unicode__(self): - return u"project({0})/priority({1})".format(self.project.id, self.name) + return u"project {0} - {1}".format(self.project_id, self.name) class IssueType(models.Model): @@ -87,10 +102,13 @@ class IssueType(models.Model): project = models.ForeignKey("Project", related_name="issuetypes") class Meta: + verbose_name = u'issue type' + verbose_name_plural = u'issue types' + ordering = ['project', 'name'] unique_together = ('project', 'name') def __unicode__(self): - return u"project({0})/type({1})".format(self.project.id, self.name) + return u"project {0} - {1}".format(self.project_id, self.name) class Points(models.Model): @@ -100,10 +118,13 @@ class Points(models.Model): project = models.ForeignKey("Project", related_name="points") class Meta: + verbose_name = u'point' + verbose_name_plural = u'points' + ordering = ['project', 'name'] unique_together = ('project', 'name') def __unicode__(self): - return u"project({0})/point({1})".format(self.project.id, self.name) + return u"project {0} - {1}".format(self.project_id, self.name) class Membership(models.Model): @@ -137,6 +158,9 @@ class Project(models.Model): tags = PickledObjectField() class Meta: + verbose_name = u'project' + verbose_name_plural = u'projects' + ordering = ['name'] permissions = ( ('can_list_projects', 'Can list projects'), ('can_view_project', 'Can view project'), @@ -147,7 +171,7 @@ class Project(models.Model): return self.name def __repr__(self): - return u"" % (self.slug) + return u"".format(self.id) def save(self, *args, **kwargs): if not self.slug: @@ -174,16 +198,11 @@ class Milestone(models.Model): disponibility = models.FloatField(null=True, default=0.0) order = models.PositiveSmallIntegerField("Order", default=1) - def save(self, *args, **kwargs): - if not self.slug: - self.slug = slugify_uniquely(self.name, self.__class__) - - super(Milestone, self).save(*args, **kwargs) - class Meta: - ordering = ['-created_date'] + verbose_name = u'milestone' + verbose_name_plural = u'milestones' + ordering = ['project', '-created_date'] unique_together = ('name', 'project') - permissions = ( ('can_view_milestone', 'Can view milestones'), ) @@ -192,7 +211,13 @@ class Milestone(models.Model): return self.name def __repr__(self): - return u"" % (self.id) + return u"".format(self.id) + + def save(self, *args, **kwargs): + if not self.slug: + self.slug = slugify_uniquely(self.name, self.__class__) + + super(Milestone, self).save(*args, **kwargs) class UserStory(models.Model): @@ -223,7 +248,9 @@ class UserStory(models.Model): tags = PickledObjectField() class Meta: - ordering = ['order'] + verbose_name = u'user story' + verbose_name_plural = u'user stories' + ordering = ['project', 'order'] unique_together = ('ref', 'project') permissions = ( ('can_comment_userstory', 'Can comment user stories'), @@ -233,12 +260,12 @@ class UserStory(models.Model): ('can_add_userstory_to_milestones', 'Can add user stories to milestones'), ) + def __unicode__(self): + return u"({1}) {0}".format(self.ref, self.subject) + def __repr__(self): return u"" % (self.id) - def __unicode__(self): - return u"{0} ({1})".format(self.subject, self.ref) - @property def is_closed(self): return self.status.is_closed @@ -256,7 +283,15 @@ class Attachment(models.Model): attached_file = models.FileField(upload_to="files/msg", max_length=500, null=True, blank=True) + class Meta: + verbose_name = u'attachment' + verbose_name_plural = u'attachments' + ordering = ['project', 'created_date'] + def __unicode__(self): + return u'content_type {0} - object_id {1} - attachment {2}'.format( + self.content_type, self.object_id, self.id + ) class Task(models.Model): uuid = models.CharField(max_length=40, unique=True, blank=True) @@ -291,6 +326,9 @@ class Task(models.Model): tags = PickledObjectField() class Meta: + verbose_name = u'task' + verbose_name_plural = u'tasks' + ordering = ['project', 'created_date'] unique_together = ('ref', 'project') permissions = ( ('can_comment_task', 'Can comment tasks'), @@ -304,7 +342,7 @@ class Task(models.Model): ) def __unicode__(self): - return self.subject + return u"({1}) {0}".format(self.ref, self.subject) def save(self, *args, **kwargs): if self.id: @@ -348,6 +386,9 @@ class Issue(models.Model): tags = PickledObjectField() class Meta: + verbose_name = u'issue' + verbose_name_plural = u'issues' + ordering = ['project', 'created_date'] unique_together = ('ref', 'project') permissions = ( ('can_comment_issue', 'Can comment issues'), @@ -360,7 +401,7 @@ class Issue(models.Model): ) def __unicode__(self): - return self.subject + return u"({1}) {0}".format(self.ref, self.subject) def save(self, *args, **kwargs): if self.id: diff --git a/greenmine/wiki/models.py b/greenmine/wiki/models.py index 270d824b..0abc7d2f 100644 --- a/greenmine/wiki/models.py +++ b/greenmine/wiki/models.py @@ -16,12 +16,19 @@ class WikiPage(models.Model): created_date = models.DateTimeField(auto_now_add=True) class Meta: + verbose_name = u'wiki page' + verbose_name_plural = u'wiki pages' + ordering = ['project', 'slug'] permissions = ( ('can_view_wikipage', 'Can modify owned wiki pages'), ('can_change_owned_wikipage', 'Can modify owned wiki pages'), ) + def __unicode__(self): + return u"project {0} - {1}".format(self.project_id, self.subject) + +# TODO: why don't use scrum.Attachment? class WikiPageAttachment(models.Model): wikipage = models.ForeignKey('WikiPage', related_name='attachments') owner = models.ForeignKey("base.User", related_name="wikifiles") @@ -29,3 +36,12 @@ class WikiPageAttachment(models.Model): modified_date = models.DateTimeField(auto_now_add=True) attached_file = models.FileField(upload_to="files/wiki", max_length=500, null=True, blank=True) + + class Meta: + verbose_name = u'wiki page attachment' + verbose_name_plural = u'wiki page attachments' + ordering = ['wikipage', 'created_date'] + + def __unicode__(self): + return u"project {0} - page {1} - attachment {2}".format(self.wikipage.project_id, self.wikipage.subject, self.id) + diff --git a/manage.py b/manage.py old mode 100644 new mode 100755