From 5638cf3da34bacd1280904feea07907792c406e2 Mon Sep 17 00:00:00 2001 From: Henrik Levkowetz Date: Tue, 20 Feb 2018 15:36:05 +0000 Subject: [PATCH] Changed all usage of ForeignKey and OneToOneFiled in model.py files to the compatibility versions from ietf.utils.models. - Legacy-Id: 14661 --- ietf/community/models.py | 17 ++-- ietf/dbtemplate/models.py | 5 +- ietf/doc/models.py | 81 ++++++++++--------- ietf/doc/views_downref.py | 2 +- ietf/group/models.py | 47 +++++------ ietf/iesg/models.py | 2 + ietf/ipr/models.py | 27 ++++--- ietf/liaisons/forms.py | 16 ++-- ietf/liaisons/models.py | 25 +++--- ietf/mailinglists/models.py | 3 +- ietf/mailtrigger/models.py | 1 + ietf/meeting/models.py | 67 +++++++-------- ietf/message/models.py | 13 +-- ietf/name/models.py | 4 +- ietf/nomcom/models.py | 54 ++++++------- ietf/person/models.py | 17 ++-- ietf/redirects/models.py | 6 +- ietf/review/models.py | 41 +++++----- ietf/secr/meetings/models.py | 8 +- ietf/secr/proceedings/models.py | 1 + ietf/stats/models.py | 12 ++- ietf/submit/models.py | 19 ++--- ietf/urls.py | 2 +- ietf/utils/html.py | 4 +- ietf/utils/text.py | 4 +- patch/fix-django-unicode-comparison-bug.patch | 2 +- 26 files changed, 253 insertions(+), 227 deletions(-) diff --git a/ietf/community/models.py b/ietf/community/models.py index 928e1b2e4..e138ac97d 100644 --- a/ietf/community/models.py +++ b/ietf/community/models.py @@ -6,10 +6,11 @@ from django.urls import reverse as urlreverse from ietf.doc.models import Document, DocEvent, State from ietf.group.models import Group from ietf.person.models import Person, Email +from ietf.utils.models import ForeignKey, OneToOneField class CommunityList(models.Model): - user = models.ForeignKey(User, blank=True, null=True) - group = models.ForeignKey(Group, blank=True, null=True) + user = ForeignKey(User, blank=True, null=True) + group = ForeignKey(Group, blank=True, null=True) added_docs = models.ManyToManyField(Document) def long_name(self): @@ -59,13 +60,13 @@ class SearchRule(models.Model): ('name_contains', 'All I-Ds with particular text/regular expression in the name'), ] - community_list = models.ForeignKey(CommunityList) + community_list = ForeignKey(CommunityList) rule_type = models.CharField(max_length=30, choices=RULE_TYPES) # these are filled in depending on the type - state = models.ForeignKey(State, blank=True, null=True) - group = models.ForeignKey(Group, blank=True, null=True) - person = models.ForeignKey(Person, blank=True, null=True) + state = ForeignKey(State, blank=True, null=True) + group = ForeignKey(Group, blank=True, null=True) + person = ForeignKey(Person, blank=True, null=True) text = models.CharField(verbose_name="Text/RegExp", max_length=255, blank=True, default="") # store a materialized view/index over which documents are matched @@ -78,8 +79,8 @@ class SearchRule(models.Model): return "%s %s %s/%s/%s/%s" % (self.community_list, self.rule_type, self.state, self.group, self.person, self.text) class EmailSubscription(models.Model): - community_list = models.ForeignKey(CommunityList) - email = models.ForeignKey(Email) + community_list = ForeignKey(CommunityList) + email = ForeignKey(Email) NOTIFICATION_CHOICES = [ ("all", "All changes"), diff --git a/ietf/dbtemplate/models.py b/ietf/dbtemplate/models.py index 7b786c4d5..58db65a71 100644 --- a/ietf/dbtemplate/models.py +++ b/ietf/dbtemplate/models.py @@ -2,6 +2,7 @@ from django.db import models from ietf.group.models import Group from ietf.name.models import DBTemplateTypeName +from ietf.utils.models import ForeignKey, OneToOneField TEMPLATE_TYPES = ( @@ -15,9 +16,9 @@ class DBTemplate(models.Model): path = models.CharField( max_length=255, unique=True, blank=False, null=False, ) title = models.CharField( max_length=255, blank=False, null=False, ) variables = models.TextField( blank=True, null=True, ) - type = models.ForeignKey( DBTemplateTypeName, ) + type = ForeignKey( DBTemplateTypeName, ) content = models.TextField( blank=False, null=False, ) - group = models.ForeignKey( Group, blank=True, null=True, ) + group = ForeignKey( Group, blank=True, null=True, ) def __unicode__(self): return self.title diff --git a/ietf/doc/models.py b/ietf/doc/models.py index c3c10a844..8b33e3d97 100644 --- a/ietf/doc/models.py +++ b/ietf/doc/models.py @@ -27,6 +27,7 @@ from ietf.utils import log from ietf.utils.admin import admin_link from ietf.utils.validators import validate_no_control_chars from ietf.utils.mail import formataddr +from ietf.utils.models import ForeignKey, OneToOneField logger = logging.getLogger('django') @@ -52,7 +53,7 @@ def check_statetype_slugs(app_configs, **kwargs): return errors class State(models.Model): - type = models.ForeignKey(StateType) + type = ForeignKey(StateType) slug = models.SlugField() name = models.CharField(max_length=255) used = models.BooleanField(default=True) @@ -74,13 +75,13 @@ class DocumentInfo(models.Model): """Any kind of document. Draft, RFC, Charter, IPR Statement, Liaison Statement""" time = models.DateTimeField(default=datetime.datetime.now) # should probably have auto_now=True - type = models.ForeignKey(DocTypeName, blank=True, null=True) # Draft, Agenda, Minutes, Charter, Discuss, Guideline, Email, Review, Issue, Wiki, External ... + type = ForeignKey(DocTypeName, blank=True, null=True) # Draft, Agenda, Minutes, Charter, Discuss, Guideline, Email, Review, Issue, Wiki, External ... title = models.CharField(max_length=255, validators=[validate_no_control_chars, ]) states = models.ManyToManyField(State, blank=True) # plain state (Active/Expired/...), IESG state, stream state tags = models.ManyToManyField(DocTagName, blank=True) # Revised ID Needed, ExternalParty, AD Followup, ... - stream = models.ForeignKey(StreamName, blank=True, null=True) # IETF, IAB, IRTF, Independent Submission - group = models.ForeignKey(Group, blank=True, null=True) # WG, RG, IAB, IESG, Edu, Tools + stream = ForeignKey(StreamName, blank=True, null=True) # IETF, IAB, IRTF, Independent Submission + group = ForeignKey(Group, blank=True, null=True) # WG, RG, IAB, IESG, Edu, Tools abstract = models.TextField(blank=True) rev = models.CharField(verbose_name="revision", max_length=16, blank=True) @@ -88,10 +89,10 @@ class DocumentInfo(models.Model): words = models.IntegerField(blank=True, null=True) formal_languages = models.ManyToManyField(FormalLanguageName, blank=True, help_text="Formal languages used in document") order = models.IntegerField(default=1, blank=True) # This is probably obviated by SessionPresentaion.order - intended_std_level = models.ForeignKey(IntendedStdLevelName, verbose_name="Intended standardization level", blank=True, null=True) - std_level = models.ForeignKey(StdLevelName, verbose_name="Standardization level", blank=True, null=True) - ad = models.ForeignKey(Person, verbose_name="area director", related_name='ad_%(class)s_set', blank=True, null=True) - shepherd = models.ForeignKey(Email, related_name='shepherd_%(class)s_set', blank=True, null=True) + intended_std_level = ForeignKey(IntendedStdLevelName, verbose_name="Intended standardization level", blank=True, null=True) + std_level = ForeignKey(StdLevelName, verbose_name="Standardization level", blank=True, null=True) + ad = ForeignKey(Person, verbose_name="area director", related_name='ad_%(class)s_set', blank=True, null=True) + shepherd = ForeignKey(Email, related_name='shepherd_%(class)s_set', blank=True, null=True) expires = models.DateTimeField(blank=True, null=True) notify = models.CharField(max_length=255, blank=True) external_url = models.URLField(blank=True) # Should be set for documents with type 'External'. @@ -482,9 +483,9 @@ class DocumentInfo(models.Model): STATUSCHANGE_RELATIONS = ('tops','tois','tohist','toinf','tobcp','toexp') class RelatedDocument(models.Model): - source = models.ForeignKey('Document') - target = models.ForeignKey('DocAlias') - relationship = models.ForeignKey(DocRelationshipName) + source = ForeignKey('Document') + target = ForeignKey('DocAlias') + relationship = ForeignKey(DocRelationshipName) def action(self): return self.relationship.name def __unicode__(self): @@ -536,9 +537,9 @@ class RelatedDocument(models.Model): return False class DocumentAuthorInfo(models.Model): - person = models.ForeignKey(Person) + person = ForeignKey(Person) # email should only be null for some historic documents - email = models.ForeignKey(Email, help_text="Email address used by author for submission", blank=True, null=True) + email = ForeignKey(Email, help_text="Email address used by author for submission", blank=True, null=True) affiliation = models.CharField(max_length=100, blank=True, help_text="Organization/company used by author for submission") country = models.CharField(max_length=255, blank=True, help_text="Country used by author for submission") order = models.IntegerField(default=1) @@ -555,7 +556,7 @@ class DocumentAuthorInfo(models.Model): ordering = ["document", "order"] class DocumentAuthor(DocumentAuthorInfo): - document = models.ForeignKey('Document') + document = ForeignKey('Document') def __unicode__(self): return u"%s %s (%s)" % (self.document.name, self.person, self.order) @@ -807,28 +808,28 @@ class Document(DocumentInfo): class DocumentURL(models.Model): - doc = models.ForeignKey(Document) - tag = models.ForeignKey(DocUrlTagName) + doc = ForeignKey(Document) + tag = ForeignKey(DocUrlTagName) desc = models.CharField(max_length=255, default='', blank=True) url = models.URLField(max_length=512) class RelatedDocHistory(models.Model): - source = models.ForeignKey('DocHistory') - target = models.ForeignKey('DocAlias', related_name="reversely_related_document_history_set") - relationship = models.ForeignKey(DocRelationshipName) + source = ForeignKey('DocHistory') + target = ForeignKey('DocAlias', related_name="reversely_related_document_history_set") + relationship = ForeignKey(DocRelationshipName) def __unicode__(self): return u"%s %s %s" % (self.source.doc.name, self.relationship.name.lower(), self.target.name) class DocHistoryAuthor(DocumentAuthorInfo): # use same naming convention as non-history version to make it a bit # easier to write generic code - document = models.ForeignKey('DocHistory', related_name="documentauthor_set") + document = ForeignKey('DocHistory', related_name="documentauthor_set") def __unicode__(self): return u"%s %s (%s)" % (self.document.doc.name, self.person, self.order) class DocHistory(DocumentInfo): - doc = models.ForeignKey(Document, related_name="history_set") + doc = ForeignKey(Document, related_name="history_set") # the name here is used to capture the canonical name at the time # - it would perhaps be more elegant to simply call the attribute # canonical_name and replace the function on Document with a @@ -878,7 +879,7 @@ class DocAlias(models.Model): to by RFC number, primarily, after achieving RFC status. """ name = models.CharField(max_length=255, primary_key=True) - document = models.ForeignKey(Document) + document = ForeignKey(Document) def __unicode__(self): return "%s-->%s" % (self.name, self.document.name) document_link = admin_link("document") @@ -887,8 +888,8 @@ class DocAlias(models.Model): verbose_name_plural = "document aliases" class DocReminder(models.Model): - event = models.ForeignKey('DocEvent') - type = models.ForeignKey(DocReminderTypeName) + event = ForeignKey('DocEvent') + type = ForeignKey(DocReminderTypeName) due = models.DateTimeField() active = models.BooleanField(default=True) @@ -972,8 +973,8 @@ class DocEvent(models.Model): """An occurrence for a document, used for tracking who, when and what.""" time = models.DateTimeField(default=datetime.datetime.now, help_text="When the event happened", db_index=True) type = models.CharField(max_length=50, choices=EVENT_TYPES) - by = models.ForeignKey(Person) - doc = models.ForeignKey('doc.Document') + by = ForeignKey(Person) + doc = ForeignKey('doc.Document') rev = models.CharField(verbose_name="revision", max_length=16, null=True, blank=True) desc = models.TextField() @@ -998,15 +999,15 @@ class NewRevisionDocEvent(DocEvent): pass class StateDocEvent(DocEvent): - state_type = models.ForeignKey(StateType) - state = models.ForeignKey(State, blank=True, null=True) + state_type = ForeignKey(StateType) + state = ForeignKey(State, blank=True, null=True) class ConsensusDocEvent(DocEvent): consensus = models.NullBooleanField(default=None) # IESG events class BallotType(models.Model): - doc_type = models.ForeignKey(DocTypeName, blank=True, null=True) + doc_type = ForeignKey(DocTypeName, blank=True, null=True) slug = models.SlugField() name = models.CharField(max_length=255) question = models.TextField(blank=True) @@ -1021,7 +1022,7 @@ class BallotType(models.Model): ordering = ['order'] class BallotDocEvent(DocEvent): - ballot_type = models.ForeignKey(BallotType) + ballot_type = ForeignKey(BallotType) def active_ad_positions(self): """Return dict mapping each active AD to a current ballot position (or None if they haven't voted).""" @@ -1083,9 +1084,9 @@ class BallotDocEvent(DocEvent): return positions class BallotPositionDocEvent(DocEvent): - ballot = models.ForeignKey(BallotDocEvent, null=True, default=None) # default=None is a temporary migration period fix, should be removed when charter branch is live - ad = models.ForeignKey(Person) - pos = models.ForeignKey(BallotPositionName, verbose_name="position", default="norecord") + ballot = ForeignKey(BallotDocEvent, null=True, default=None) # default=None is a temporary migration period fix, should be removed when charter branch is live + ad = ForeignKey(Person) + pos = ForeignKey(BallotPositionName, verbose_name="position", default="norecord") discuss = models.TextField(help_text="Discuss text if position is discuss", blank=True) discuss_time = models.DateTimeField(help_text="Time discuss text was written", blank=True, null=True) comment = models.TextField(help_text="Optional comment", blank=True) @@ -1102,8 +1103,8 @@ class TelechatDocEvent(DocEvent): returning_item = models.BooleanField(default=False) class ReviewRequestDocEvent(DocEvent): - review_request = models.ForeignKey('review.ReviewRequest') - state = models.ForeignKey(ReviewRequestStateName, blank=True, null=True) + review_request = ForeignKey('review.ReviewRequest') + state = ForeignKey(ReviewRequestStateName, blank=True, null=True) # charter events class InitialReviewDocEvent(DocEvent): @@ -1111,20 +1112,20 @@ class InitialReviewDocEvent(DocEvent): class AddedMessageEvent(DocEvent): import ietf.message.models - message = models.ForeignKey(ietf.message.models.Message, null=True, blank=True,related_name='doc_manualevents') + message = ForeignKey(ietf.message.models.Message, null=True, blank=True,related_name='doc_manualevents') msgtype = models.CharField(max_length=25) - in_reply_to = models.ForeignKey(ietf.message.models.Message, null=True, blank=True,related_name='doc_irtomanual') + in_reply_to = ForeignKey(ietf.message.models.Message, null=True, blank=True,related_name='doc_irtomanual') class SubmissionDocEvent(DocEvent): import ietf.submit.models - submission = models.ForeignKey(ietf.submit.models.Submission) + submission = ForeignKey(ietf.submit.models.Submission) # dumping store for removed events class DeletedEvent(models.Model): - content_type = models.ForeignKey(ContentType) + content_type = ForeignKey(ContentType) json = models.TextField(help_text="Deleted object in JSON format, with attribute names chosen to be suitable for passing into the relevant create method.") - by = models.ForeignKey(Person) + by = ForeignKey(Person) time = models.DateTimeField(default=datetime.datetime.now) def __unicode__(self): diff --git a/ietf/doc/views_downref.py b/ietf/doc/views_downref.py index 07234faf1..91cf88253 100644 --- a/ietf/doc/views_downref.py +++ b/ietf/doc/views_downref.py @@ -2,7 +2,7 @@ from __future__ import unicode_literals -from django.core.urlresolvers import reverse as urlreverse +from django.urls import reverse as urlreverse from django.http import HttpResponseRedirect from django.shortcuts import render diff --git a/ietf/group/models.py b/ietf/group/models.py index 9a5426da3..d9f8d9b71 100644 --- a/ietf/group/models.py +++ b/ietf/group/models.py @@ -15,14 +15,15 @@ from ietf.name.models import GroupStateName, GroupTypeName, DocTagName, GroupMil from ietf.person.models import Email, Person from ietf.utils.mail import formataddr from ietf.utils import log +from ietf.utils.models import ForeignKey, OneToOneField class GroupInfo(models.Model): time = models.DateTimeField(default=datetime.datetime.now) name = models.CharField(max_length=80) - state = models.ForeignKey(GroupStateName, null=True) - type = models.ForeignKey(GroupTypeName, null=True) - parent = models.ForeignKey('Group', blank=True, null=True) + state = ForeignKey(GroupStateName, null=True) + type = ForeignKey(GroupTypeName, null=True) + parent = ForeignKey('Group', blank=True, null=True) description = models.TextField(blank=True) list_email = models.CharField(max_length=64, blank=True) list_subscribe = models.CharField(max_length=255, blank=True) @@ -76,7 +77,7 @@ class Group(GroupInfo): objects = GroupManager() acronym = models.SlugField(max_length=40, unique=True, db_index=True) - charter = models.OneToOneField('doc.Document', related_name='chartered_group', blank=True, null=True) + charter = OneToOneField('doc.Document', related_name='chartered_group', blank=True, null=True) def latest_event(self, *args, **filter_args): """Get latest event of optional Python type and with filter @@ -193,14 +194,14 @@ class Group(GroupInfo): return desc class GroupHistory(GroupInfo): - group = models.ForeignKey(Group, related_name='history_set') + group = ForeignKey(Group, related_name='history_set') acronym = models.CharField(max_length=40) class Meta: verbose_name_plural="group histories" class GroupURL(models.Model): - group = models.ForeignKey(Group) + group = ForeignKey(Group) name = models.CharField(max_length=255) url = models.URLField() @@ -208,12 +209,12 @@ class GroupURL(models.Model): return u"%s (%s)" % (self.url, self.name) class GroupMilestoneInfo(models.Model): - group = models.ForeignKey(Group) + group = ForeignKey(Group) # a group has two sets of milestones, current milestones # (active/under review/deleted) and charter milestones (active # during a charter/recharter event), events for charter milestones # are stored on the charter document - state = models.ForeignKey(GroupMilestoneStateName) + state = ForeignKey(GroupMilestoneStateName) desc = models.CharField(verbose_name="Description", max_length=500) due = models.DateField() resolved = models.CharField(max_length=50, blank=True, help_text="Explanation of why milestone is resolved (usually \"Done\"), or empty if still due.") @@ -231,13 +232,13 @@ class GroupMilestone(GroupMilestoneInfo): class GroupMilestoneHistory(GroupMilestoneInfo): time = models.DateTimeField() - milestone = models.ForeignKey(GroupMilestone, related_name="history_set") + milestone = ForeignKey(GroupMilestone, related_name="history_set") class GroupStateTransitions(models.Model): """Captures that a group has overriden the default available document state transitions for a certain state.""" - group = models.ForeignKey(Group) - state = models.ForeignKey('doc.State', help_text="State for which the next states should be overridden") + group = ForeignKey(Group) + state = ForeignKey('doc.State', help_text="State for which the next states should be overridden") next_states = models.ManyToManyField('doc.State', related_name='previous_groupstatetransitions_states') def __unicode__(self): @@ -255,10 +256,10 @@ GROUP_EVENT_CHOICES = [ class GroupEvent(models.Model): """An occurrence for a group, used for tracking who, when and what.""" - group = models.ForeignKey(Group) + group = ForeignKey(Group) time = models.DateTimeField(default=datetime.datetime.now, help_text="When the event happened") type = models.CharField(max_length=50, choices=GROUP_EVENT_CHOICES) - by = models.ForeignKey(Person) + by = ForeignKey(Person) desc = models.TextField() def __unicode__(self): @@ -268,16 +269,16 @@ class GroupEvent(models.Model): ordering = ['-time', 'id'] class ChangeStateGroupEvent(GroupEvent): - state = models.ForeignKey(GroupStateName) + state = ForeignKey(GroupStateName) class MilestoneGroupEvent(GroupEvent): - milestone = models.ForeignKey(GroupMilestone) + milestone = ForeignKey(GroupMilestone) class Role(models.Model): - name = models.ForeignKey(RoleName) - group = models.ForeignKey(Group) - person = models.ForeignKey(Person) - email = models.ForeignKey(Email, help_text="Email address used by person for this role.") + name = ForeignKey(RoleName) + group = ForeignKey(Group) + person = ForeignKey(Person) + email = ForeignKey(Email, help_text="Email address used by person for this role.") def __unicode__(self): return u"%s is %s in %s" % (self.person.plain_name(), self.name.name, self.group.acronym or self.group.name) @@ -295,10 +296,10 @@ class RoleHistory(models.Model): # used on its own - there should always be a GroupHistory # accompanying a change in roles, so lookup the appropriate # GroupHistory instead - name = models.ForeignKey(RoleName) - group = models.ForeignKey(GroupHistory) - person = models.ForeignKey(Person) - email = models.ForeignKey(Email, help_text="Email address used by person for this role.") + name = ForeignKey(RoleName) + group = ForeignKey(GroupHistory) + person = ForeignKey(Person) + email = ForeignKey(Email, help_text="Email address used by person for this role.") def __unicode__(self): return u"%s is %s in %s" % (self.person.plain_name(), self.name.name, self.group.acronym) diff --git a/ietf/iesg/models.py b/ietf/iesg/models.py index 5c58ee00e..7ea8169f7 100644 --- a/ietf/iesg/models.py +++ b/ietf/iesg/models.py @@ -36,6 +36,8 @@ import datetime from django.db import models +from ietf.utils.models import ForeignKey, OneToOneField + class TelechatAgendaItem(models.Model): TYPE_CHOICES = ( (1, "Any Other Business (WG News, New Proposals, etc.)"), diff --git a/ietf/ipr/models.py b/ietf/ipr/models.py index c46b48a0b..2b8ac76e7 100644 --- a/ietf/ipr/models.py +++ b/ietf/ipr/models.py @@ -10,16 +10,17 @@ from ietf.doc.models import DocAlias from ietf.name.models import DocRelationshipName,IprDisclosureStateName,IprLicenseTypeName,IprEventTypeName from ietf.person.models import Person from ietf.message.models import Message +from ietf.utils.models import ForeignKey, OneToOneField class IprDisclosureBase(models.Model): - by = models.ForeignKey(Person) # who was logged in, or System if nobody was logged in + by = ForeignKey(Person) # who was logged in, or System if nobody was logged in compliant = models.BooleanField("Complies to RFC3979", default=True) docs = models.ManyToManyField(DocAlias, through='IprDocRel') holder_legal_name = models.CharField(max_length=255) notes = models.TextField("Additional notes", blank=True) other_designations = models.CharField("Designations for other contributions", blank=True, max_length=255) rel = models.ManyToManyField('self', through='RelatedIpr', symmetrical=False) - state = models.ForeignKey(IprDisclosureStateName) + state = ForeignKey(IprDisclosureStateName) submitter_name = models.CharField(max_length=255,blank=True) submitter_email = models.EmailField(blank=True) time = models.DateTimeField(auto_now_add=True) @@ -118,7 +119,7 @@ class HolderIprDisclosure(IprDisclosureBase): holder_contact_email = models.EmailField() holder_contact_name = models.CharField(max_length=255) holder_contact_info = models.TextField(blank=True, help_text="Address, phone, etc.") - licensing = models.ForeignKey(IprLicenseTypeName) + licensing = ForeignKey(IprLicenseTypeName) licensing_comments = models.TextField(blank=True) submitter_claims_all_terms_disclosed = models.BooleanField(default=False) @@ -145,8 +146,8 @@ class GenericIprDisclosure(IprDisclosureBase): statement = models.TextField() # includes licensing info class IprDocRel(models.Model): - disclosure = models.ForeignKey(IprDisclosureBase) - document = models.ForeignKey(DocAlias) + disclosure = ForeignKey(IprDisclosureBase) + document = ForeignKey(DocAlias) sections = models.TextField(blank=True) revisions = models.CharField(max_length=16,blank=True) # allows strings like 01-07 @@ -175,21 +176,21 @@ class IprDocRel(models.Model): return u"%s which applies to %s" % (self.disclosure, self.document.name) class RelatedIpr(models.Model): - source = models.ForeignKey(IprDisclosureBase,related_name='relatedipr_source_set') - target = models.ForeignKey(IprDisclosureBase,related_name='relatedipr_target_set') - relationship = models.ForeignKey(DocRelationshipName) # Re-use; change to a dedicated RelName if needed + source = ForeignKey(IprDisclosureBase,related_name='relatedipr_source_set') + target = ForeignKey(IprDisclosureBase,related_name='relatedipr_target_set') + relationship = ForeignKey(DocRelationshipName) # Re-use; change to a dedicated RelName if needed def __unicode__(self): return u"%s %s %s" % (self.source.title, self.relationship.name.lower(), self.target.title) class IprEvent(models.Model): time = models.DateTimeField(auto_now_add=True) - type = models.ForeignKey(IprEventTypeName) - by = models.ForeignKey(Person) - disclosure = models.ForeignKey(IprDisclosureBase) + type = ForeignKey(IprEventTypeName) + by = ForeignKey(Person) + disclosure = ForeignKey(IprDisclosureBase) desc = models.TextField() - message = models.ForeignKey(Message, null=True, blank=True,related_name='msgevents') - in_reply_to = models.ForeignKey(Message, null=True, blank=True,related_name='irtoevents') + message = ForeignKey(Message, null=True, blank=True,related_name='msgevents') + in_reply_to = ForeignKey(Message, null=True, blank=True,related_name='irtoevents') response_due= models.DateTimeField(blank=True,null=True) def __unicode__(self): diff --git a/ietf/liaisons/forms.py b/ietf/liaisons/forms.py index 7d055de07..c24396c9d 100644 --- a/ietf/liaisons/forms.py +++ b/ietf/liaisons/forms.py @@ -10,7 +10,7 @@ from django.core.exceptions import ObjectDoesNotExist from django.db.models.query import QuerySet from django.forms.utils import ErrorList from django.db.models import Q -from django.forms.widgets import RadioFieldRenderer +#from django.forms.widgets import RadioFieldRenderer from django.core.validators import validate_email, ValidationError from django.utils.html import format_html from django.utils.encoding import force_text @@ -122,18 +122,18 @@ class AddCommentForm(forms.Form): comment = forms.CharField(required=True, widget=forms.Textarea, strip=False) private = forms.BooleanField(label="Private comment", required=False,help_text="If this box is checked the comment will not appear in the statement's public history view.") -class RadioRenderer(RadioFieldRenderer): - def render(self): - output = [] - for widget in self: - output.append(format_html(force_text(widget))) - return mark_safe('\n'.join(output)) +# class RadioRenderer(RadioFieldRenderer): +# def render(self): +# output = [] +# for widget in self: +# output.append(format_html(force_text(widget))) +# return mark_safe('\n'.join(output)) class SearchLiaisonForm(forms.Form): '''Expects initial keyword argument queryset which then gets filtered based on form data''' text = forms.CharField(required=False) - scope = forms.ChoiceField(choices=(("all", "All text fields"), ("title", "Title field")), required=False, initial='title', widget=forms.RadioSelect(renderer=RadioRenderer)) +# scope = forms.ChoiceField(choices=(("all", "All text fields"), ("title", "Title field")), required=False, initial='title') source = forms.CharField(required=False) destination = forms.CharField(required=False) start_date = DatepickerDateField(date_format="yyyy-mm-dd", picker_settings={"autoclose": "1" }, label='Start date', required=False) diff --git a/ietf/liaisons/models.py b/ietf/liaisons/models.py index 4633bc419..1e9a0845f 100644 --- a/ietf/liaisons/models.py +++ b/ietf/liaisons/models.py @@ -11,6 +11,7 @@ from ietf.name.models import (LiaisonStatementPurposeName, LiaisonStatementState DocRelationshipName) from ietf.doc.models import Document from ietf.group.models import Group +from ietf.utils.models import ForeignKey, OneToOneField # maps (previous state id, new state id) to event type id STATE_EVENT_MAPPING = { @@ -26,7 +27,7 @@ STATE_EVENT_MAPPING = { class LiaisonStatement(models.Model): title = models.CharField(max_length=255) from_groups = models.ManyToManyField(Group, blank=True, related_name='liaisonstatement_from_set') - from_contact = models.ForeignKey(Email, blank=True, null=True) + from_contact = ForeignKey(Email, blank=True, null=True) to_groups = models.ManyToManyField(Group, blank=True, related_name='liaisonstatement_to_set') to_contacts = models.CharField(max_length=2000, help_text="Contacts at recipient group") @@ -35,14 +36,14 @@ class LiaisonStatement(models.Model): action_holder_contacts = models.CharField(blank=True, max_length=255, help_text="Who makes sure action is completed") # incoming only? cc_contacts = models.TextField(blank=True) - purpose = models.ForeignKey(LiaisonStatementPurposeName) + purpose = ForeignKey(LiaisonStatementPurposeName) deadline = models.DateField(null=True, blank=True) other_identifiers = models.TextField(blank=True, null=True) # Identifiers from other bodies body = models.TextField(blank=True) tags = models.ManyToManyField(LiaisonStatementTagName, blank=True) attachments = models.ManyToManyField(Document, through='LiaisonStatementAttachment', blank=True) - state = models.ForeignKey(LiaisonStatementState, default='pending') + state = ForeignKey(LiaisonStatementState, default='pending') def __unicode__(self): return self.title or u"" @@ -194,8 +195,8 @@ class LiaisonStatement(models.Model): return list(set([ r.email.address for r in approval_set ])) class LiaisonStatementAttachment(models.Model): - statement = models.ForeignKey(LiaisonStatement) - document = models.ForeignKey(Document) + statement = ForeignKey(LiaisonStatement) + document = ForeignKey(Document) removed = models.BooleanField(default=False) def __unicode__(self): @@ -203,16 +204,16 @@ class LiaisonStatementAttachment(models.Model): class RelatedLiaisonStatement(models.Model): - source = models.ForeignKey(LiaisonStatement, related_name='source_of_set') - target = models.ForeignKey(LiaisonStatement, related_name='target_of_set') - relationship = models.ForeignKey(DocRelationshipName) + source = ForeignKey(LiaisonStatement, related_name='source_of_set') + target = ForeignKey(LiaisonStatement, related_name='target_of_set') + relationship = ForeignKey(DocRelationshipName) def __unicode__(self): return u"%s %s %s" % (self.source.title, self.relationship.name.lower(), self.target.title) class LiaisonStatementGroupContacts(models.Model): - group = models.ForeignKey(Group, unique=True, null=True) + group = ForeignKey(Group, unique=True, null=True) contacts = models.CharField(max_length=255,blank=True) cc_contacts = models.CharField(max_length=255,blank=True) @@ -222,9 +223,9 @@ class LiaisonStatementGroupContacts(models.Model): class LiaisonStatementEvent(models.Model): time = models.DateTimeField(auto_now_add=True) - type = models.ForeignKey(LiaisonStatementEventTypeName) - by = models.ForeignKey(Person) - statement = models.ForeignKey(LiaisonStatement) + type = ForeignKey(LiaisonStatementEventTypeName) + by = ForeignKey(Person) + statement = ForeignKey(LiaisonStatement) desc = models.TextField() def __unicode__(self): diff --git a/ietf/mailinglists/models.py b/ietf/mailinglists/models.py index c12afded0..7ccc37c01 100644 --- a/ietf/mailinglists/models.py +++ b/ietf/mailinglists/models.py @@ -6,6 +6,7 @@ from django.core.validators import validate_email from django.db import models from ietf.person.models import Person +from ietf.utils.models import ForeignKey, OneToOneField class List(models.Model): name = models.CharField(max_length=32) @@ -28,7 +29,7 @@ class Subscribed(models.Model): class Whitelisted(models.Model): time = models.DateTimeField(auto_now_add=True) email = models.CharField("Email address", max_length=64, validators=[validate_email]) - by = models.ForeignKey(Person) + by = ForeignKey(Person) def __unicode__(self): return "" % (self.email, self.time) class Meta: diff --git a/ietf/mailtrigger/models.py b/ietf/mailtrigger/models.py index 3b5c7b6e9..06dbee523 100644 --- a/ietf/mailtrigger/models.py +++ b/ietf/mailtrigger/models.py @@ -10,6 +10,7 @@ from ietf.person.models import Email import debug # pyflakes:ignore from ietf.group.models import Role +from ietf.utils.models import ForeignKey, OneToOneField def clean_duplicates(addrlist): address_info = {} diff --git a/ietf/meeting/models.py b/ietf/meeting/models.py index d293b8441..5b5611a5b 100644 --- a/ietf/meeting/models.py +++ b/ietf/meeting/models.py @@ -27,6 +27,7 @@ from ietf.person.models import Person from ietf.utils.storage import NoLocationMigrationFileSystemStorage from ietf.utils.text import xslugify from ietf.utils.timezone import date2datetime +from ietf.utils.models import ForeignKey, OneToOneField countries = pytz.country_names.items() countries.sort(lambda x,y: cmp(x[1], y[1])) @@ -49,7 +50,7 @@ class Meeting(models.Model): # number is either the number for IETF meetings, or some other # identifier for interim meetings/IESG retreats/liaison summits/... number = models.CharField(unique=True, max_length=64) - type = models.ForeignKey(MeetingTypeName) + type = ForeignKey(MeetingTypeName) # Date is useful when generating a set of timeslot for this meeting, but # is not used to determine date for timeslot instances thereafter, as # they have their own datetime field. @@ -88,11 +89,11 @@ class Meeting(models.Model): break_area = models.CharField(blank=True, max_length=255) reg_area = models.CharField(blank=True, max_length=255) agenda_note = models.TextField(blank=True, help_text="Text in this field will be placed at the top of the html agenda page for the meeting. HTML can be used, but will not be validated.") - agenda = models.ForeignKey('Schedule',null=True,blank=True, related_name='+') + agenda = ForeignKey('Schedule',null=True,blank=True, related_name='+') session_request_lock_message = models.CharField(blank=True,max_length=255) # locked if not empty proceedings_final = models.BooleanField(default=False, help_text=u"Are the proceedings for this meeting complete?") acknowledgements = models.TextField(blank=True, help_text="Acknowledgements for use in meeting proceedings. Use ReStructuredText markup.") - overview = models.ForeignKey(DBTemplate, related_name='overview', null=True, editable=False) + overview = ForeignKey(DBTemplate, related_name='overview', null=True, editable=False) show_important_dates = models.BooleanField(default=False) def __unicode__(self): @@ -284,7 +285,7 @@ class Meeting(models.Model): # === Rooms, Resources, Floorplans ============================================= class ResourceAssociation(models.Model): - name = models.ForeignKey(RoomResourceName) + name = ForeignKey(RoomResourceName) icon = models.CharField(max_length=64) # icon to be found in /static/img desc = models.CharField(max_length=256) @@ -300,7 +301,7 @@ class ResourceAssociation(models.Model): return res1 class Room(models.Model): - meeting = models.ForeignKey(Meeting) + meeting = ForeignKey(Meeting) time = models.DateTimeField(default=datetime.datetime.now) name = models.CharField(max_length=255) functional_name = models.CharField(max_length=255, blank = True) @@ -308,7 +309,7 @@ class Room(models.Model): resources = models.ManyToManyField(ResourceAssociation, blank = True) session_types = models.ManyToManyField(TimeSlotTypeName, blank = True) # floorplan-related properties - floorplan = models.ForeignKey('FloorPlan', null=True, blank=True, default=None) + floorplan = ForeignKey('FloorPlan', null=True, blank=True, default=None) # floorplan: room pixel position : (0,0) is top left of image, (xd, yd) # is room width, height. x1 = models.SmallIntegerField(null=True, blank=True, default=None) @@ -380,8 +381,8 @@ class Room(models.Model): class UrlResource(models.Model): "For things like audio stream urls, meetecho stream urls" - name = models.ForeignKey(RoomResourceName) - room = models.ForeignKey(Room) + name = ForeignKey(RoomResourceName) + room = ForeignKey(Room) url = models.URLField(null=True, blank=True) def floorplan_path(instance, filename): @@ -392,7 +393,7 @@ class FloorPlan(models.Model): name = models.CharField(max_length=255) short = models.CharField(max_length=2, default='') time = models.DateTimeField(default=datetime.datetime.now) - meeting = models.ForeignKey(Meeting) + meeting = ForeignKey(Meeting) order = models.SmallIntegerField() image = models.ImageField(storage=NoLocationMigrationFileSystemStorage(), upload_to=floorplan_path, blank=True, default=None) # @@ -407,12 +408,12 @@ class TimeSlot(models.Model): mapped to a time slot, including breaks. Sessions are connected to TimeSlots during scheduling. """ - meeting = models.ForeignKey(Meeting) - type = models.ForeignKey(TimeSlotTypeName) + meeting = ForeignKey(Meeting) + type = ForeignKey(TimeSlotTypeName) name = models.CharField(max_length=255) time = models.DateTimeField() duration = models.DurationField(default=datetime.timedelta(0)) - location = models.ForeignKey(Room, blank=True, null=True) + location = ForeignKey(Room, blank=True, null=True) show_location = models.BooleanField(default=True, help_text="Show location in agenda.") sessions = models.ManyToManyField('Session', related_name='slots', through='SchedTimeSessAssignment', blank=True, help_text=u"Scheduled session, if any.") modified = models.DateTimeField(auto_now=True) @@ -578,13 +579,13 @@ class Schedule(models.Model): Secretariat to IESG members for review. Only the owner may edit the agenda, others may copy it """ - meeting = models.ForeignKey(Meeting, null=True) + meeting = ForeignKey(Meeting, null=True) name = models.CharField(max_length=16, blank=False) - owner = models.ForeignKey(Person) + owner = ForeignKey(Person) visible = models.BooleanField(default=True, help_text=u"Make this agenda available to those who know about it.") public = models.BooleanField(default=True, help_text=u"Make this agenda publically available.") badness = models.IntegerField(null=True, blank=True) - # considering copiedFrom = models.ForeignKey('Schedule', blank=True, null=True) + # considering copiedFrom = ForeignKey('Schedule', blank=True, null=True) def __unicode__(self): return u"%s:%s(%s)" % (self.meeting, self.name, self.owner) @@ -683,10 +684,10 @@ class SchedTimeSessAssignment(models.Model): Each relationship is attached to the named agenda, which is owned by a specific person/user. """ - timeslot = models.ForeignKey('TimeSlot', null=False, blank=False, related_name='sessionassignments') - session = models.ForeignKey('Session', null=True, default=None, related_name='timeslotassignments', help_text=u"Scheduled session.") - schedule = models.ForeignKey('Schedule', null=False, blank=False, related_name='assignments') - extendedfrom = models.ForeignKey('self', null=True, default=None, help_text=u"Timeslot this session is an extension of.") + timeslot = ForeignKey('TimeSlot', null=False, blank=False, related_name='sessionassignments') + session = ForeignKey('Session', null=True, default=None, related_name='timeslotassignments', help_text=u"Scheduled session.") + schedule = ForeignKey('Schedule', null=False, blank=False, related_name='assignments') + extendedfrom = ForeignKey('self', null=True, default=None, help_text=u"Timeslot this session is an extension of.") modified = models.DateTimeField(auto_now=True) notes = models.TextField(blank=True) badness = models.IntegerField(default=0, blank=True, null=True) @@ -789,12 +790,12 @@ class Constraint(models.Model): A third type (name=avoidday) of constraint is between source WG and a particular day of the week, specified in day. """ - meeting = models.ForeignKey(Meeting) - source = models.ForeignKey(Group, related_name="constraint_source_set") - target = models.ForeignKey(Group, related_name="constraint_target_set", null=True) - person = models.ForeignKey(Person, null=True, blank=True) + meeting = ForeignKey(Meeting) + source = ForeignKey(Group, related_name="constraint_source_set") + target = ForeignKey(Group, related_name="constraint_target_set", null=True) + person = ForeignKey(Person, null=True, blank=True) day = models.DateTimeField(null=True, blank=True) - name = models.ForeignKey(ConstraintName) + name = ForeignKey(ConstraintName) active_status = None @@ -828,8 +829,8 @@ class Constraint(models.Model): class SessionPresentation(models.Model): - session = models.ForeignKey('Session') - document = models.ForeignKey(Document) + session = ForeignKey('Session') + document = ForeignKey(Document) rev = models.CharField(verbose_name="revision", max_length=16, null=True, blank=True) order = models.PositiveSmallIntegerField(default=0) @@ -849,18 +850,18 @@ class Session(models.Model): timeslots are needed, multiple sessions will have to be created. Training sessions and similar are modeled by filling in a responsible group (e.g. Edu team) and filling in the name.""" - meeting = models.ForeignKey(Meeting) + meeting = ForeignKey(Meeting) name = models.CharField(blank=True, max_length=255, help_text="Name of session, in case the session has a purpose rather than just being a group meeting.") short = models.CharField(blank=True, max_length=32, help_text="Short version of 'name' above, for use in filenames.") - type = models.ForeignKey(TimeSlotTypeName) - group = models.ForeignKey(Group) # The group type historically determined the session type. BOFs also need to be added as a group. Note that not all meeting requests have a natural group to associate with. + type = ForeignKey(TimeSlotTypeName) + group = ForeignKey(Group) # The group type historically determined the session type. BOFs also need to be added as a group. Note that not all meeting requests have a natural group to associate with. attendees = models.IntegerField(null=True, blank=True) agenda_note = models.CharField(blank=True, max_length=255) requested = models.DateTimeField(default=datetime.datetime.now) - requested_by = models.ForeignKey(Person) + requested_by = ForeignKey(Person) requested_duration = models.DurationField(default=datetime.timedelta(0)) comments = models.TextField(blank=True) - status = models.ForeignKey(SessionStatusName) + status = ForeignKey(SessionStatusName) scheduled = models.DateTimeField(null=True, blank=True) modified = models.DateTimeField(auto_now=True) remote_instructions = models.CharField(blank=True,max_length=1024) @@ -1111,8 +1112,8 @@ class Session(models.Model): return self._agenda_file class ImportantDate(models.Model): - meeting = models.ForeignKey(Meeting) + meeting = ForeignKey(Meeting) date = models.DateField() - name = models.ForeignKey(ImportantDateName) + name = ForeignKey(ImportantDateName) class Meta: ordering = ["-meeting","date", ] diff --git a/ietf/message/models.py b/ietf/message/models.py index c92323655..68a0d103f 100644 --- a/ietf/message/models.py +++ b/ietf/message/models.py @@ -9,10 +9,11 @@ from ietf.person.models import Person from ietf.group.models import Group from ietf.doc.models import Document from ietf.name.models import RoleName +from ietf.utils.models import ForeignKey, OneToOneField class Message(models.Model): time = models.DateTimeField(default=datetime.datetime.now) - by = models.ForeignKey(Person) + by = ForeignKey(Person) subject = models.CharField(max_length=255) frm = models.CharField(max_length=255) @@ -35,7 +36,7 @@ class Message(models.Model): class MessageAttachment(models.Model): - message = models.ForeignKey(Message) + message = ForeignKey(Message) filename = models.CharField(max_length=255, db_index=True, blank=True) content_type = models.CharField(max_length=255, blank=True) encoding = models.CharField(max_length=255, blank=True) @@ -48,9 +49,9 @@ class MessageAttachment(models.Model): class SendQueue(models.Model): time = models.DateTimeField(default=datetime.datetime.now) - by = models.ForeignKey(Person) + by = ForeignKey(Person) - message = models.ForeignKey(Message) + message = ForeignKey(Message) send_at = models.DateTimeField(blank=True, null=True) sent_at = models.DateTimeField(blank=True, null=True) @@ -65,8 +66,8 @@ class SendQueue(models.Model): class AnnouncementFrom(models.Model): - name = models.ForeignKey(RoleName) - group = models.ForeignKey(Group) + name = ForeignKey(RoleName) + group = ForeignKey(Group) address = models.CharField(max_length=255) def __unicode__(self): diff --git a/ietf/name/models.py b/ietf/name/models.py index cb6990024..d1ccb69af 100644 --- a/ietf/name/models.py +++ b/ietf/name/models.py @@ -2,6 +2,8 @@ from django.db import models +from ietf.utils.models import ForeignKey, OneToOneField + class NameModel(models.Model): slug = models.CharField(max_length=32, primary_key=True) name = models.CharField(max_length=255) @@ -105,7 +107,7 @@ class ContinentName(NameModel): "Africa, Antarctica, Asia, ..." class CountryName(NameModel): "Afghanistan, Aaland Islands, Albania, ..." - continent = models.ForeignKey(ContinentName) + continent = ForeignKey(ContinentName) in_eu = models.BooleanField(verbose_name="In EU", default=False) class ImportantDateName(NameModel): "Registration Opens, Scheduling Opens, ID Cutoff, ..." diff --git a/ietf/nomcom/models.py b/ietf/nomcom/models.py index 026f188af..eec4dcdf0 100644 --- a/ietf/nomcom/models.py +++ b/ietf/nomcom/models.py @@ -23,7 +23,7 @@ from ietf.nomcom.utils import (initialize_templates_for_group, initialize_requirements_for_position, initialize_description_for_topic, delete_nomcom_templates) - +from ietf.utils.models import ForeignKey, OneToOneField from ietf.utils.storage import NoLocationMigrationFileSystemStorage @@ -33,14 +33,14 @@ def upload_path_handler(instance, filename): class ReminderDates(models.Model): date = models.DateField() - nomcom = models.ForeignKey('NomCom') + nomcom = ForeignKey('NomCom') class NomCom(models.Model): public_key = models.FileField(storage=NoLocationMigrationFileSystemStorage(location=settings.NOMCOM_PUBLIC_KEYS_DIR), upload_to=upload_path_handler, blank=True, null=True) - group = models.ForeignKey(Group) + group = ForeignKey(Group) send_questionnaire = models.BooleanField(verbose_name='Send questionnaires automatically', default=False, help_text='If you check this box, questionnaires are sent automatically after nominations.') reminder_interval = models.PositiveIntegerField(help_text='If the nomcom user sets the interval field then a cron command will ' @@ -83,14 +83,14 @@ post_delete.connect(delete_nomcom, sender=NomCom) class Nomination(models.Model): - position = models.ForeignKey('Position') + position = ForeignKey('Position') candidate_name = models.CharField(verbose_name='Candidate name', max_length=255) candidate_email = models.EmailField(verbose_name='Candidate email', max_length=255) candidate_phone = models.CharField(verbose_name='Candidate phone', blank=True, max_length=255) - nominee = models.ForeignKey('Nominee') - comments = models.ForeignKey('Feedback') + nominee = ForeignKey('Nominee') + comments = ForeignKey('Feedback') nominator_email = models.EmailField(verbose_name='Nominator Email', blank=True) - user = models.ForeignKey(User, editable=False) + user = ForeignKey(User, editable=False) time = models.DateTimeField(auto_now_add=True) share_nominator = models.BooleanField(verbose_name='Share nominator name with candidate', default=False, help_text='Check this box to allow the NomCom to let the ' @@ -108,11 +108,11 @@ class Nomination(models.Model): class Nominee(models.Model): - email = models.ForeignKey(Email) - person = models.ForeignKey(Person, blank=True, null=True) + email = ForeignKey(Email) + person = ForeignKey(Person, blank=True, null=True) nominee_position = models.ManyToManyField('Position', through='NomineePosition') - duplicated = models.ForeignKey('Nominee', blank=True, null=True) - nomcom = models.ForeignKey('NomCom') + duplicated = ForeignKey('Nominee', blank=True, null=True) + nomcom = ForeignKey('NomCom') objects = NomineeManager() @@ -136,9 +136,9 @@ class Nominee(models.Model): class NomineePosition(models.Model): - position = models.ForeignKey('Position') - nominee = models.ForeignKey('Nominee') - state = models.ForeignKey(NomineePositionStateName) + position = ForeignKey('Position') + nominee = ForeignKey('Nominee') + state = ForeignKey(NomineePositionStateName) time = models.DateTimeField(auto_now_add=True) objects = NomineePositionManager() @@ -164,10 +164,10 @@ class NomineePosition(models.Model): class Position(models.Model): - nomcom = models.ForeignKey('NomCom') + nomcom = ForeignKey('NomCom') name = models.CharField(verbose_name='Name', max_length=255, help_text='This short description will appear on the Nomination and Feedback pages. Be as descriptive as necessary. Past examples: "Transport AD", "IAB Member"') - requirement = models.ForeignKey(DBTemplate, related_name='requirement', null=True, editable=False) - questionnaire = models.ForeignKey(DBTemplate, related_name='questionnaire', null=True, editable=False) + requirement = ForeignKey(DBTemplate, related_name='requirement', null=True, editable=False) + questionnaire = ForeignKey(DBTemplate, related_name='questionnaire', null=True, editable=False) is_open = models.BooleanField(verbose_name='Is open', default=False, help_text="Set is_open when the nomcom is working on a position. Clear it when an appointment is confirmed.") accepting_nominations = models.BooleanField(verbose_name='Is accepting nominations', default=False) accepting_feedback = models.BooleanField(verbose_name='Is accepting feedback', default=False) @@ -210,11 +210,11 @@ class Position(models.Model): return rendered class Topic(models.Model): - nomcom = models.ForeignKey('NomCom') + nomcom = ForeignKey('NomCom') subject = models.CharField(verbose_name='Name', max_length=255, help_text='This short description will appear on the Feedback pages.') - description = models.ForeignKey(DBTemplate, related_name='description', null=True, editable=False) + description = ForeignKey(DBTemplate, related_name='description', null=True, editable=False) accepting_feedback = models.BooleanField(verbose_name='Is accepting feedback', default=False) - audience = models.ForeignKey(TopicAudienceName) + audience = ForeignKey(TopicAudienceName) class Meta: verbose_name_plural = 'Topics' @@ -239,15 +239,15 @@ class Topic(models.Model): return rendered class Feedback(models.Model): - nomcom = models.ForeignKey('NomCom') + nomcom = ForeignKey('NomCom') author = models.EmailField(verbose_name='Author', blank=True) positions = models.ManyToManyField('Position', blank=True) nominees = models.ManyToManyField('Nominee', blank=True) topics = models.ManyToManyField('Topic', blank=True) subject = models.TextField(verbose_name='Subject', blank=True) comments = EncryptedTextField(verbose_name='Comments') - type = models.ForeignKey(FeedbackTypeName, blank=True, null=True) - user = models.ForeignKey(User, editable=False, blank=True, null=True) + type = ForeignKey(FeedbackTypeName, blank=True, null=True) + user = ForeignKey(User, editable=False, blank=True, null=True) time = models.DateTimeField(auto_now_add=True) objects = FeedbackManager() @@ -259,12 +259,12 @@ class Feedback(models.Model): ordering = ['time'] class FeedbackLastSeen(models.Model): - reviewer = models.ForeignKey(Person) - nominee = models.ForeignKey(Nominee) + reviewer = ForeignKey(Person) + nominee = ForeignKey(Nominee) time = models.DateTimeField(auto_now=True) class TopicFeedbackLastSeen(models.Model): - reviewer = models.ForeignKey(Person) - topic = models.ForeignKey(Topic) + reviewer = ForeignKey(Person) + topic = ForeignKey(Topic) time = models.DateTimeField(auto_now=True) diff --git a/ietf/person/models.py b/ietf/person/models.py index 64cf5884d..281b024cb 100644 --- a/ietf/person/models.py +++ b/ietf/person/models.py @@ -24,6 +24,7 @@ from ietf.utils.mail import send_mail_preformatted from ietf.utils.storage import NoLocationMigrationFileSystemStorage from ietf.utils.mail import formataddr from ietf.person.name import unidecode_name +from ietf.utils.models import ForeignKey, OneToOneField class PersonInfo(models.Model): @@ -157,7 +158,7 @@ class PersonInfo(models.Model): abstract = True class Person(PersonInfo): - user = models.OneToOneField(User, blank=True, null=True) + user = OneToOneField(User, blank=True, null=True) def save(self, *args, **kwargs): created = not self.pk @@ -197,8 +198,8 @@ class Person(PersonInfo): return ct1 class PersonHistory(PersonInfo): - person = models.ForeignKey(Person, related_name="history_set") - user = models.ForeignKey(User, blank=True, null=True) + person = ForeignKey(Person, related_name="history_set") + user = ForeignKey(User, blank=True, null=True) class Alias(models.Model): """This is used for alternative forms of a name. This is the @@ -206,7 +207,7 @@ class Alias(models.Model): unicode form (and ascii form, if different) of a name which is recorded in the Person record. """ - person = models.ForeignKey(Person) + person = ForeignKey(Person) name = models.CharField(max_length=255, db_index=True) def save(self, *args, **kwargs): @@ -229,7 +230,7 @@ class Alias(models.Model): class Email(models.Model): address = models.CharField(max_length=64, primary_key=True, validators=[validate_email]) - person = models.ForeignKey(Person, null=True) + person = ForeignKey(Person, null=True) time = models.DateTimeField(auto_now_add=True) primary = models.BooleanField(default=False) active = models.BooleanField(default=True) # Old email addresses are *not* purged, as history @@ -290,7 +291,7 @@ PERSON_API_KEY_ENDPOINTS = [ ] class PersonalApiKey(models.Model): - person = models.ForeignKey(Person, related_name='apikeys') + person = ForeignKey(Person, related_name='apikeys') endpoint = models.CharField(max_length=128, null=False, blank=False, choices=PERSON_API_KEY_ENDPOINTS) created = models.DateTimeField(default=datetime.datetime.now, null=False) valid = models.BooleanField(default=True) @@ -331,7 +332,7 @@ PERSON_EVENT_CHOICES = [ ] class PersonEvent(models.Model): - person = models.ForeignKey(Person) + person = ForeignKey(Person) time = models.DateTimeField(default=datetime.datetime.now, help_text="When the event happened") type = models.CharField(max_length=50, choices=PERSON_EVENT_CHOICES) desc = models.TextField() @@ -343,5 +344,5 @@ class PersonEvent(models.Model): ordering = ['-time', '-id'] class PersonApiKeyEvent(PersonEvent): - key = models.ForeignKey(PersonalApiKey) + key = ForeignKey(PersonalApiKey) diff --git a/ietf/redirects/models.py b/ietf/redirects/models.py index be27b5776..72529eaac 100644 --- a/ietf/redirects/models.py +++ b/ietf/redirects/models.py @@ -2,6 +2,8 @@ from django.db import models +from ietf.utils.models import ForeignKey, OneToOneField + class Redirect(models.Model): """Mapping of CGI script to url. The "rest" is a sprintf-style string with %(param)s entries to insert @@ -42,8 +44,8 @@ class Command(models.Model): """ command = models.CharField(max_length=50) url = models.CharField(max_length=50, blank=True) - script = models.ForeignKey(Redirect, related_name='commands', editable=False) - suffix = models.ForeignKey(Suffix, null=True, blank=True) + script = ForeignKey(Redirect, related_name='commands', editable=False) + suffix = ForeignKey(Suffix, null=True, blank=True) def __str__(self): ret = "%s?command=%s" % (self.script.cgi, self.command) if self.suffix_id: diff --git a/ietf/review/models.py b/ietf/review/models.py index d124b6e97..f52a94e30 100644 --- a/ietf/review/models.py +++ b/ietf/review/models.py @@ -7,11 +7,12 @@ from ietf.group.models import Group from ietf.person.models import Person, Email from ietf.name.models import ReviewTypeName, ReviewRequestStateName, ReviewResultName from ietf.utils.validators import validate_regular_expression_string +from ietf.utils.models import ForeignKey, OneToOneField class ReviewerSettings(models.Model): """Keeps track of admin data associated with a reviewer in a team.""" - team = models.ForeignKey(Group, limit_choices_to=~models.Q(reviewteamsettings=None)) - person = models.ForeignKey(Person) + team = ForeignKey(Group, limit_choices_to=~models.Q(reviewteamsettings=None)) + person = ForeignKey(Person) INTERVALS = [ (7, "Once per week"), (14, "Once per fortnight"), @@ -35,8 +36,8 @@ class ReviewerSettings(models.Model): class ReviewSecretarySettings(models.Model): """Keeps track of admin data associated with a secretary in a team.""" - team = models.ForeignKey(Group, limit_choices_to=~models.Q(reviewteamsettings=None)) - person = models.ForeignKey(Person) + team = ForeignKey(Group, limit_choices_to=~models.Q(reviewteamsettings=None)) + person = ForeignKey(Person) remind_days_before_deadline = models.IntegerField(null=True, blank=True, help_text="To get an email reminder in case a reviewer forgets to do an assigned review, enter the number of days before review deadline you want to receive it. Clear the field if you don't want a reminder.") def __unicode__(self): @@ -46,8 +47,8 @@ class ReviewSecretarySettings(models.Model): verbose_name_plural = "review secretary settings" class UnavailablePeriod(models.Model): - team = models.ForeignKey(Group, limit_choices_to=~models.Q(reviewteamsettings=None)) - person = models.ForeignKey(Person) + team = ForeignKey(Group, limit_choices_to=~models.Q(reviewteamsettings=None)) + person = ForeignKey(Person) start_date = models.DateField(default=datetime.date.today, null=True, help_text="Choose the start date so that you can still do a review if it's assigned just before the start date - this usually means you should mark yourself unavailable for assignment some time before you are actually away.") end_date = models.DateField(blank=True, null=True, help_text="Leaving the end date blank means that the period continues indefinitely. You can end it later.") AVAILABILITY_CHOICES = [ @@ -77,9 +78,9 @@ class UnavailablePeriod(models.Model): class ReviewWish(models.Model): """Reviewer wishes to review a document when it becomes available for review.""" time = models.DateTimeField(default=datetime.datetime.now) - team = models.ForeignKey(Group, limit_choices_to=~models.Q(reviewteamsettings=None)) - person = models.ForeignKey(Person) - doc = models.ForeignKey(Document) + team = ForeignKey(Group, limit_choices_to=~models.Q(reviewteamsettings=None)) + person = ForeignKey(Person) + doc = ForeignKey(Document) def __unicode__(self): return u"{} wishes to review {} in {}".format(self.person, self.doc.name, self.team.acronym) @@ -89,8 +90,8 @@ class ReviewWish(models.Model): class NextReviewerInTeam(models.Model): - team = models.ForeignKey(Group, limit_choices_to=~models.Q(reviewteamsettings=None)) - next_reviewer = models.ForeignKey(Person) + team = ForeignKey(Group, limit_choices_to=~models.Q(reviewteamsettings=None)) + next_reviewer = ForeignKey(Person) def __unicode__(self): return u"{} next in {}".format(self.next_reviewer, self.team) @@ -103,18 +104,18 @@ class ReviewRequest(models.Model): """Represents a request for a review and the process it goes through. There should be one ReviewRequest entered for each combination of document, rev, and reviewer.""" - state = models.ForeignKey(ReviewRequestStateName) + state = ForeignKey(ReviewRequestStateName) old_id = models.IntegerField(blank=True, null=True, help_text="ID in previous review system") # FIXME: remove this when everything has been migrated # Fields filled in on the initial record creation - these # constitute the request part. time = models.DateTimeField(default=datetime.datetime.now) - type = models.ForeignKey(ReviewTypeName) - doc = models.ForeignKey(Document, related_name='reviewrequest_set') - team = models.ForeignKey(Group, limit_choices_to=~models.Q(reviewteamsettings=None)) + type = ForeignKey(ReviewTypeName) + doc = ForeignKey(Document, related_name='reviewrequest_set') + team = ForeignKey(Group, limit_choices_to=~models.Q(reviewteamsettings=None)) deadline = models.DateField() - requested_by = models.ForeignKey(Person) + requested_by = ForeignKey(Person) requested_rev = models.CharField(verbose_name="requested revision", max_length=16, blank=True, help_text="Fill in if a specific revision is to be reviewed, e.g. 02") comment = models.TextField(verbose_name="Requester's comments and instructions", max_length=2048, blank=True, help_text="Provide any additional information to show to the review team secretary and reviewer", default='') @@ -123,11 +124,11 @@ class ReviewRequest(models.Model): # requested/assigned, any changes to the assignment happens by # closing down the current request and making a new one, copying # the request-part fields above. - reviewer = models.ForeignKey(Email, blank=True, null=True) + reviewer = ForeignKey(Email, blank=True, null=True) - review = models.OneToOneField(Document, blank=True, null=True) + review = OneToOneField(Document, blank=True, null=True) reviewed_rev = models.CharField(verbose_name="reviewed revision", max_length=16, blank=True) - result = models.ForeignKey(ReviewResultName, blank=True, null=True) + result = ForeignKey(ReviewResultName, blank=True, null=True) def __unicode__(self): return u"%s review on %s by %s %s" % (self.type, self.doc, self.team, self.state) @@ -155,7 +156,7 @@ def get_default_review_results(): class ReviewTeamSettings(models.Model): """Holds configuration specific to groups that are review teams""" - group = models.OneToOneField(Group) + group = OneToOneField(Group) autosuggest = models.BooleanField(default=True, verbose_name="Automatically suggest possible review requests") review_types = models.ManyToManyField(ReviewTypeName, default=get_default_review_types) review_results = models.ManyToManyField(ReviewResultName, default=get_default_review_results) diff --git a/ietf/secr/meetings/models.py b/ietf/secr/meetings/models.py index 40489d329..4be573202 100644 --- a/ietf/secr/meetings/models.py +++ b/ietf/secr/meetings/models.py @@ -11,7 +11,7 @@ class GeneralInfo(models.Model): db_table = u'general_info' class MeetingVenue(models.Model): - meeting_num = models.ForeignKey(Meeting, db_column='meeting_num', unique=True, editable=False) + meeting_num = ForeignKey(Meeting, db_column='meeting_num', unique=True, editable=False) break_area_name = models.CharField(max_length=255) reg_area_name = models.CharField(max_length=255) def __str__(self): @@ -32,8 +32,8 @@ class NonSessionRef(models.Model): class NonSession(models.Model): non_session_id = models.AutoField(primary_key=True, editable=False) day_id = models.IntegerField(blank=True, null=True, editable=False) - non_session_ref = models.ForeignKey(NonSessionRef, editable=False) - meeting = models.ForeignKey(Meeting, db_column='meeting_num', editable=False) + non_session_ref = ForeignKey(NonSessionRef, editable=False) + meeting = ForeignKey(Meeting, db_column='meeting_num', editable=False) time_desc = models.CharField(blank=True, max_length=75, default='0') show_break_location = models.BooleanField(editable=False, default=True) def __str__(self): @@ -50,4 +50,4 @@ class NonSession(models.Model): db_table = 'non_session' verbose_name = "Meeting non-session slot" -""" \ No newline at end of file +""" diff --git a/ietf/secr/proceedings/models.py b/ietf/secr/proceedings/models.py index 7ddf6d6fe..6b50ff5ed 100644 --- a/ietf/secr/proceedings/models.py +++ b/ietf/secr/proceedings/models.py @@ -4,6 +4,7 @@ from django.conf import settings from django.db import models from ietf.meeting.models import Meeting +from ietf.utils.models import ForeignKey, OneToOneField class InterimManager(models.Manager): diff --git a/ietf/stats/models.py b/ietf/stats/models.py index 441d7e0cf..6ff904b38 100644 --- a/ietf/stats/models.py +++ b/ietf/stats/models.py @@ -1,7 +1,13 @@ +# Copyright The IETF Trust 2017, All Rights Reserved + from django.db import models + +import debug # pyflakes:ignore + from ietf.meeting.models import Meeting from ietf.name.models import CountryName from ietf.person.models import Person +from ietf.utils.models import ForeignKey, OneToOneField class AffiliationAlias(models.Model): @@ -34,7 +40,7 @@ class CountryAlias(models.Model): purposes.""" alias = models.CharField(max_length=255, help_text="Note that lower-case aliases are matched case-insensitive while aliases with at least one uppercase letter is matched case-sensitive. So 'United States' is best entered as 'united states' so it both matches 'United States' and 'United states' and 'UNITED STATES', whereas 'US' is best entered as 'US' so it doesn't accidentally match an ordinary word like 'us'.") - country = models.ForeignKey(CountryName, max_length=255) + country = ForeignKey(CountryName, max_length=255) def __unicode__(self): return u"{} -> {}".format(self.alias, self.country.name) @@ -44,12 +50,12 @@ class CountryAlias(models.Model): class MeetingRegistration(models.Model): """Registration attendee records from the IETF registration system""" - meeting = models.ForeignKey(Meeting) + meeting = ForeignKey(Meeting) first_name = models.CharField(max_length=255) last_name = models.CharField(max_length=255) affiliation = models.CharField(blank=True, max_length=255) country_code = models.CharField(max_length=2) # ISO 3166 - person = models.ForeignKey(Person, blank=True, null=True) + person = ForeignKey(Person, blank=True, null=True) email = models.EmailField(blank=True, null=True) def __unicode__(self): diff --git a/ietf/submit/models.py b/ietf/submit/models.py index 4ee8f336a..8cb5a8da7 100644 --- a/ietf/submit/models.py +++ b/ietf/submit/models.py @@ -12,6 +12,7 @@ from ietf.group.models import Group from ietf.message.models import Message from ietf.name.models import DraftSubmissionStateName, FormalLanguageName from ietf.utils.accesstoken import generate_random_key, generate_access_token +from ietf.utils.models import ForeignKey, OneToOneField def parse_email_line(line): @@ -23,7 +24,7 @@ def parse_email_line(line): return dict(name=name, email=addr) class Submission(models.Model): - state = models.ForeignKey(DraftSubmissionStateName) + state = ForeignKey(DraftSubmissionStateName) remote_ip = models.CharField(max_length=100, blank=True) access_key = models.CharField(max_length=255, default=generate_random_key) @@ -31,7 +32,7 @@ class Submission(models.Model): # draft metadata name = models.CharField(max_length=255, db_index=True) - group = models.ForeignKey(Group, null=True, blank=True) + group = ForeignKey(Group, null=True, blank=True) title = models.CharField(max_length=255, blank=True) abstract = models.TextField(blank=True) rev = models.CharField(max_length=3, blank=True) @@ -51,7 +52,7 @@ class Submission(models.Model): submitter = models.CharField(max_length=255, blank=True, help_text="Name and email of submitter, e.g. \"John Doe <john@example.org>\".") - draft = models.ForeignKey(Document, null=True, blank=True) + draft = ForeignKey(Document, null=True, blank=True) def __unicode__(self): return u"%s-%s" % (self.name, self.rev) @@ -71,7 +72,7 @@ class Submission(models.Model): class SubmissionCheck(models.Model): time = models.DateTimeField(default=datetime.datetime.now) - submission = models.ForeignKey(Submission, related_name='checks') + submission = ForeignKey(Submission, related_name='checks') checker = models.CharField(max_length=256, blank=True) passed = models.NullBooleanField(default=False) message = models.TextField(null=True, blank=True) @@ -88,9 +89,9 @@ class SubmissionCheck(models.Model): return self.errors != '[]' class SubmissionEvent(models.Model): - submission = models.ForeignKey(Submission) + submission = ForeignKey(Submission) time = models.DateTimeField(default=datetime.datetime.now) - by = models.ForeignKey(Person, null=True, blank=True) + by = ForeignKey(Person, null=True, blank=True) desc = models.TextField() def __unicode__(self): @@ -103,16 +104,16 @@ class SubmissionEvent(models.Model): class Preapproval(models.Model): """Pre-approved draft submission name.""" name = models.CharField(max_length=255, db_index=True) - by = models.ForeignKey(Person) + by = ForeignKey(Person) time = models.DateTimeField(default=datetime.datetime.now) def __unicode__(self): return self.name class SubmissionEmailEvent(SubmissionEvent): - message = models.ForeignKey(Message, null=True, blank=True,related_name='manualevents') + message = ForeignKey(Message, null=True, blank=True,related_name='manualevents') msgtype = models.CharField(max_length=25) - in_reply_to = models.ForeignKey(Message, null=True, blank=True,related_name='irtomanual') + in_reply_to = ForeignKey(Message, null=True, blank=True,related_name='irtomanual') def __unicode__(self): return u"%s %s by %s at %s" % (self.submission.name, self.desc, self.by.plain_name() if self.by else "(unknown)", self.time) diff --git a/ietf/urls.py b/ietf/urls.py index 1bdbedbd7..67b474437 100644 --- a/ietf/urls.py +++ b/ietf/urls.py @@ -37,7 +37,7 @@ sitemaps = { urlpatterns = [ url(r'^$', views_search.frontpage), url(r'^accounts/', include('ietf.ietfauth.urls')), - url(r'^admin/', include(admin.site.urls)), + url(r'^admin/', admin.site.urls), url(r'^admin/docs/', include('django.contrib.admindocs.urls')), url(r'^ann/', include('ietf.nomcom.redirect_ann_urls')), url(r'^api/', include('ietf.api.urls')), diff --git a/ietf/utils/html.py b/ietf/utils/html.py index 0aa8bd10f..1afc77626 100644 --- a/ietf/utils/html.py +++ b/ietf/utils/html.py @@ -5,7 +5,7 @@ import html5lib import bleach from html5lib import sanitizer, serializer, tokenizer, treebuilders, treewalkers -from django.utils.functional import allow_lazy +from django.utils.functional import keep_lazy from django.utils import six acceptable_elements = ('a', 'abbr', 'acronym', 'address', 'b', 'big', @@ -67,7 +67,7 @@ def remove_tags(html, tags): """Returns the given HTML sanitized, and with the given tags removed.""" allowed = set(acceptable_elements) - set([ t.lower() for t in tags ]) return bleach.clean(html, tags=allowed) -remove_tags = allow_lazy(remove_tags, six.text_type) +remove_tags = keep_lazy(remove_tags, six.text_type) def clean_html(html): return bleach.clean(html) diff --git a/ietf/utils/text.py b/ietf/utils/text.py index c93bb55de..c929843c5 100644 --- a/ietf/utils/text.py +++ b/ietf/utils/text.py @@ -5,7 +5,7 @@ import textwrap import types import unicodedata -from django.utils.functional import allow_lazy +from django.utils.functional import keep_lazy from django.utils import six from django.utils.safestring import mark_safe @@ -21,7 +21,7 @@ def xslugify(value): value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore').decode('ascii') value = re.sub('[^\w\s/-]', '', value).strip().lower() return mark_safe(re.sub('[-\s/]+', '-', value)) -xslugify = allow_lazy(xslugify, six.text_type) +xslugify = keep_lazy(xslugify, six.text_type) def strip_prefix(text, prefix): if text.startswith(prefix): diff --git a/patch/fix-django-unicode-comparison-bug.patch b/patch/fix-django-unicode-comparison-bug.patch index 32ee103d5..c48e41659 100644 --- a/patch/fix-django-unicode-comparison-bug.patch +++ b/patch/fix-django-unicode-comparison-bug.patch @@ -1,6 +1,6 @@ --- django/db/models/fields/__init__.py.old 2017-06-14 08:43:21.665812000 -0700 +++ django/db/models/fields/__init__.py 2017-12-17 14:34:03.023976702 -0800 -@@ -2323,7 +2323,7 @@ +@@ -2344,7 +2344,7 @@ if self.has_default() and not callable(self.default): return self.default default = super(BinaryField, self).get_default()