import csv
from collections import defaultdict

from django.db.models import Prefetch
from django.utils.datetime_safe import datetime


class Property(models.Model):
    # id = ...           # primary key in model
    pass
    
    
class SubProperty(models.Model):
    # id = ...           # primary key in model
    # property = Property()
    ## property_id = Property.id
    pass
    
    
class GetDataAsCSV(object):
    # defined values
    _prop_pk_field = 'id'             # the primary_key_field_name in property model ; ie Property.pk is 'id'
                                      # the SubProperty.pk in property model should be _prop_pk_field; SubProperty.pk = 'id'
    _prop_field_name = 'property'     # the property field name in sub-property model
    _file_name = None

    # required vars
    _fields = []
    _generated_data = None

    @staticmethod
    def get_property_ids():
        return Property.objects.all().filter(
            # if you have any global filter such as user specific properties or datetime or anything.
        ).values_list('id', flat=True)

    def get_properties(self, fields):
        return Property.objects.all().filter(
            # if you have any global filter such as user specific properties or datetime or anything.
        ).values(self._prop_pk_field, *fields)

    def get_sub_properties(self, property_id_set, fields):

        filter_for_selected_props = {
            self._prop_field_name: property_id_set
        }

        return SubProperty.objects.all().filter(
            # if you have any global filter such as user specific properties or datetime or anything,
        ).filter(**filter_for_selected_props).values(self._sub_prop_pk_field, self._prop_field_name, *fields)

    @property
    def file_name(self):
        if self._file_name:
            return self._file_name
        now = datetime.now()
        return "PropertyData_{day}_{month}_{year}_{timestamp}.csv".format(day=now.day, month=now.month, year=now.year, timestamp=now.timestamp())

    def __init__(self, fields=None, file_name=None, prop_field_name=None):
        self.properties_dataset = None
        self.intermediate_data_form = None
        self._fields = fields or []
        self._prop_field_name = prop_field_name or self._prop_field_name
        self.generate_data()

    def generate_data(self):
        if not self._fields: return
        property_ids = self.get_property_ids()      # as values_list with flat=True
        sub_properties_qs = self.get_sub_properties(property_ids, self._fields)

        intermediate_data_form = defaultdict(list)
        for sub_prop in sub_properties_qs:
            prop_id = sub_prop[self._prop_field_name]
            intermediate_data_form[prop_id].append(sub_prop)

        self.intermediate_data_form = intermediate_data_form
        self.properties_dataset = list(self.get_properties(fields=self._fields))
        for prop in self.properties_dataset:
            prop[self._prop_field_name] = ''
	self.write_to_csv()
    
    def write_to_csv(self):
        outfile = self.file_name
        ordered_fieldnames = [
            self._prop_field_name,
            *self._fields
        ]
        ordered_data = []
        for prop in self.properties_dataset:
            ordered_data.append(prop)
            prop_id = prop['id']
            if prop_id in self.intermediate_data_form:
                ordered_data.extend(self.intermediate_data_form[prop_id])

        with open(outfile, 'wb') as fou:
            dw = csv.DictWriter(fou, delimiter=',', fieldnames=ordered_fieldnames)
            dw.writeheader()
            dw.writerows(ordered_data)



if __name__ == "__main__":
    GetDataAsCSV(fields=('field_01', 'field_02', 'field_03', 'field_04', ))