예제 #1
0
class AbstractTimeSeriesDataModel( models.Model ):

    #============================================================================
    # constants-ish
    #============================================================================

    DEBUG_FLAG = False

    # time period types
    TIME_PERIOD_HOURLY = "hourly"

    #============================================================================
    # Django model fields
    #============================================================================
    
    start_date = models.DateTimeField( null = True, blank = True )
    end_date = models.DateTimeField( null = True, blank = True )
    time_period = models.ForeignKey( Time_Period, null = True, blank = True )
    time_period_type = models.CharField( max_length = 255, null = True, blank = True ) # - hourly, by minute, etc.
    time_period_index = models.IntegerField( null = True, blank = True )
    time_period_category = models.CharField( max_length = 255, null = True, blank = True )
    time_period_label = models.CharField( max_length = 255, null = True, blank = True ) # could give each hour, etc. a separate identifier "start+1", "start+2", etc. - not naming _id to start, so you leave room for this to be a separate table.
    aggregate_index = models.IntegerField( null = True, blank = True ) # a separate index you can use to keep track of overall order within a time-series that you separate out into multiple types - "before" and "after", for example - time_period_index can be counter within before or after, aggregate index can be unique through both before and after.
    original_id = models.CharField( max_length = 255, null = True, blank = True )
    original_name = models.CharField( max_length = 255, null = True, blank = True )
    filter_type = models.CharField( max_length = 255, null = True, blank = True ) # - place to keep track of different filter types, if you want.  Example: "text_contains"
    filter_value = models.CharField( max_length = 255, null = True, blank = True )
    match_value = models.CharField( max_length = 255, null = True, blank = True )
    match_count = models.IntegerField( null = True, blank = True, default = 0 )
    filter_1 = models.BooleanField( default = False )
    match_count_1 = models.IntegerField( null = True, blank = True, default = 0 )
    filter_2 = models.BooleanField( default = False )
    match_count_2 = models.IntegerField( null = True, blank = True, default = 0 )
    filter_3 = models.BooleanField( default = False )
    match_count_3 = models.IntegerField( null = True, blank = True, default = 0 )
    filter_4 = models.BooleanField( default = False )
    match_count_4 = models.IntegerField( null = True, blank = True, default = 0 )
    filter_5 = models.BooleanField( default = False )
    match_count_5 = models.IntegerField( null = True, blank = True, default = 0 )
    filter_6 = models.BooleanField( default = False )
    match_count_6 = models.IntegerField( null = True, blank = True, default = 0 )
    filter_7 = models.BooleanField( default = False )
    match_count_7 = models.IntegerField( null = True, blank = True, default = 0 )
    filter_8 = models.BooleanField( default = False )
    match_count_8 = models.IntegerField( null = True, blank = True, default = 0 )
    filter_9 = models.BooleanField( default = False )
    match_count_9 = models.IntegerField( null = True, blank = True, default = 0 )
    filter_10 = models.BooleanField( default = False )
    match_count_10 = models.IntegerField( null = True, blank = True, default = 0 )
    create_date = models.DateTimeField( auto_now_add = True )
    last_update = models.DateTimeField( auto_now = True )

    #============================================================================
    # Instance variables
    #============================================================================
    
    
    m_exception_helper = ExceptionHelper()
    
    
    #============================================================================
    # meta class
    #============================================================================

    # meta class so we know this is an abstract class.
    class Meta:
        abstract = True

    # add string output method.
    

    #============================================================================
    # class methods
    #============================================================================


    @classmethod
    def get_instance( cls,
                      original_name_IN = "",
                      original_id_IN = "",
                      start_dt_IN = None,
                      end_dt_IN = None,
                      time_period_type_IN = "",
                      time_period_category_IN = "",
                      time_period_index_IN = -1,
                      update_existing_IN = True,
                      *args,
                      **kwargs ):

        '''
        Accepts a subreddit full ID; start and end datetime; time period
           type, category and index; and flag telling whether we are updating
           existing.  If not updating existing, returns new instance.  If
           updating, uses values to filter time-series records to find existing
           record for a given subreddit in a given set.  If you are working with
           existing time-series records created with make_data, to make it more
           likely you'll get matches, pass the same values to these parameters
           that you did when you created the data (so same time period type, time
           period category, start and end date of the period, and index within
           category).  If it finds none or more than one, returns None.
                    
        Parameters:
        - original_name_IN - name of row we are trying to find time-series record(s) for.
        - original_id_IN - original ID of row we are trying to find time-series record(s) for.
        - start_dt_IN - datetime.datetime instance of date and time on which you want to start deriving time-series data.
        - end_dt_IN - datetime.datetime instance of date and time on which you want to stop deriving time-series data.
        - time_period_type_IN - (optional) time period type value you want stored in each time-series record.  Defaults to empty string.
        - time_period_category_IN - (optional) category used in labeling.  If set, this was stored in time_period_category, appended to the front of an integer counter that counts up each time period, which was then stored in time_period_label.
        '''
        
        # return reference
        instance_OUT = None
        
        # declare variables
        me = "get_instance"
        update_existing = False
        row_match_rs = None
        debug_flag = cls.DEBUG_FLAG
        
        # updating existing?
        update_existing = update_existing_IN

        # Are we updating?
        if ( ( update_existing ) and ( update_existing != None ) and ( update_existing == True ) ):

            if ( debug_flag == True ):
                print( "In " + me + " - updating, looking up existing record" )
            #-- END DEBUG --#

            # first, see if we can find a match for this row.  Can filter on
            #    start date, end date, original name, original ID, category,
            #    type, and/or index.
            row_match_rs = cls.lookup_records( original_name_IN = original_name_IN,
                                               original_id_IN = original_id_IN,
                                               start_dt_IN = start_dt_IN,
                                               end_dt_IN = end_dt_IN,
                                               time_period_type_IN = time_period_type_IN,
                                               time_period_category_IN = time_period_category_IN,
                                               time_period_index_IN = time_period_index_IN )
            
            # check to see if we got anything back.
            if ( row_match_rs.count() == 1 ):
            
                # found one - update it.
                instance_OUT = row_match_rs[ 0 ]

                if ( debug_flag == True ):
                    print( "==> Found 1 ( id = " + str( instance_OUT.pk ) + " )." )
                #-- END DEBUG --#
            
            elif ( row_match_rs.count() > 1 ):
            
                # error - what to do?
                instance_OUT = None

                if ( debug_flag == True ):
                    print( "==> More than one match found ( " + str( row_match_rs.count() ) + " )" )
                #-- END DEBUG --#
            
            else:
            
                # no existing row - create new instance of this class.
                instance_OUT = cls()

                if ( debug_flag == True ):
                    print( "==> Found 0." )
                #-- END DEBUG --#
                
            #-- END check to see if we have an existing row to update. --#
            
        else:
        
            # not updating - create new row.
            instance_OUT = cls()

            if ( debug_flag == True ):
                print( "In " + me + " - Not updating." )
            #-- END DEBUG --#
        
        #-- END check to see if updating existing --#
        
        return instance_OUT
        
    #-- END method get_instance() --#


    @classmethod
    def lookup_records( cls,
                        original_name_IN = "",
                        original_id_IN = "",
                        start_dt_IN = None,
                        end_dt_IN = None,
                        time_period_type_IN = "",
                        time_period_category_IN = "",
                        time_period_index_IN = -1,
                        *args,
                        **kwargs ):

        '''
        Accepts an original name, origianl ID, start and end datetime, time
           period type, and time period label.  Uses these values to filter
           time-series records.  If you are working with existing time-series
           records created with make_data, to make it more likely you'll get
           correct matches, pass the same values to these parameters that you did
           when you created the data (so same time period type, time period
           category, time period index, start and end date of the period, and
           original ID).
                    
        Parameters:
        - original_name_IN - name of subreddit we are trying to find time-series record(s) for.
        - original_id_IN - name of subreddit we are trying to find time-series record(s) for.
        - start_dt_IN - datetime.datetime instance of date and time on which you want to start deriving time-series data.
        - end_dt_IN - datetime.datetime instance of date and time on which you want to stop deriving time-series data.
        - time_period_type_IN - (optional) time period type value you want stored in each time-series record.  Defaults to empty string.
        - time_period_category_IN - (optional) label to use in labeling.  If set, this is appended to the front of an integer counter that counts up each time period, is stored in time_period_label.  If not set, the integer time period counter is the only thing stored in time period label.
        - time_period_index_IN - (optional) index to keep track of time periods within a category.  Generated values are non-zero, so only included in filter if value is greater than 0.
        '''
        
        # return reference
        rs_OUT = None
        
        # declare variables.
        
        # start out lookup by getting all objects.
        rs_OUT = cls.objects.all()
        
        # for each parameter, check for a non-empty value, if present, filter.
        
        # original name
        if ( ( original_name_IN ) and ( original_name_IN != "" ) ):
        
            rs_OUT = rs_OUT.filter( original_name__iexact = original_name_IN )
        
        #-- END check for subreddit name --#
        
        # original ID
        if ( ( original_id_IN ) and ( original_id_IN != "" ) ):
        
            rs_OUT = rs_OUT.filter( original_id__iexact = original_id_IN )
        
        #-- END check for subreddit reddit ID name --#
        
        # start date
        if ( ( start_dt_IN ) and ( start_dt_IN != None ) ):
        
            rs_OUT = rs_OUT.filter( start_date = start_dt_IN )
        
        #-- END check for start date --#
        
        # end date
        if ( ( end_dt_IN ) and ( end_dt_IN != "" ) ):
        
            rs_OUT = rs_OUT.filter( end_date = end_dt_IN )
        
        #-- END check for end date --#
        
        # time period type
        if ( ( time_period_type_IN ) and ( time_period_type_IN != "" ) ):
        
            rs_OUT = rs_OUT.filter( time_period_type__iexact = time_period_type_IN )
        
        #-- END check for time period type value --#
        
        # time period category
        if ( ( time_period_category_IN ) and ( time_period_category_IN != "" ) ):
        
            rs_OUT = rs_OUT.filter( time_period_category__iexact = time_period_category_IN )
        
        #-- END check for time period category value --#
        
        # time period index
        if ( ( time_period_index_IN ) and ( time_period_index_IN > 0 ) ):
        
            rs_OUT = rs_OUT.filter( time_period_index = time_period_index_IN )
        
        #-- END check for time period index value --#
        
        return rs_OUT

    #-- END class method lookup_records --#
    

    @classmethod
    def process_exception( cls, exception_IN = None, message_IN = "", print_details_IN = True, *args, **kwargs ):
    
        # return reference
        status_OUT = ""
    
        # declare variables
        exception_helper = None
        exception_message = ""
        exception_status = ""

        # Get exception helper class.
        exception_helper = cls.m_exception_handler
                                
        # process the exception
        exception_message = message_IN
        exception_status = exception_helper.process_exception( exception_IN = exception_IN, message_IN = exception_message, print_details_IN = print_details_IN )
        
        # set status to description of exception
        status_OUT = exception_helper.last_exception_details
        
        return status_OUT
        
    #-- END method process_exception() --#
        
        
    #============================================================================
    # instance methods
    #============================================================================


    def __str__(self):
        
        # return reference
        string_OUT = ""
        
        # id?
        if ( ( self.id ) and ( self.id != None ) and ( self.id > 0 ) ):
        
            string_OUT += str( self.id )
        
        #-- END check to see if id --#
        
        # start date?
        if( self.start_date ):
        
            string_OUT += " - " + str( self.start_date )
        
        #-- END check to see if start_date --#

        # end date?
        if( self.end_date ):
        
            string_OUT += " --> " + str( self.end_date )
        
        #-- END check to see if end_date --#
        
        # label.
        if ( self.time_period_label ):
        
            string_OUT += " - " + self.time_period_label
        
        #-- END check to see if time_period_label --#

        # original ID.
        if ( self.original_id ):
        
            string_OUT += " - ID: " + self.original_id
        
        #-- END check to see if original_id --#

        # original name.
        if ( self.original_name ):
        
            string_OUT += " - Name: " + self.original_name
        
        #-- END check to see if original_name --#

        return string_OUT