class ExerciseOutputSchema(BaseSchema): exercise_id = StringType(required=False, serialized_name='exerciseId') name = StringType(required=True, max_length=100, min_length=0) description = StringType(required=True, max_length=500, min_length=0) video_url = StringType(required=True, serialized_name='videoUrl', max_length=1000, min_length=0) equipment_number = NumberType(required=True, serialized_name='equipmentNumber') files = ListType(field=ModelType(model_spec=ExerciseFileOutputSchema, required=False), required=False)
class BaseMongoModel(Model): """ Provides generic methods to work with model. Why use `MyModel.find_one` instead of `db.collection.find_one` ? 1. Collection name is declared inside the model, so it is not needed to provide it all the time 2. This `MyModel.find_one` will return MyModel instance, whereas `db.collection.find_one` will return dictionary Example with directly access: db_result = yield db.collection_name.find_one({"i": 3}) obj = MyModel(db_result) Same example, but using MyModel.find_one: obj = yield MyModel.find_one(db, {"i": 3}) ######################################### Using motor with schematics simulate ORM. Like this: from schematics.types import StringType class NewsModel(BaseModel): title = StringType() content = StringType() author = StringType() MONGO_COLLECTION = 'news' the api motor.Op is deprecated. # Old style: document = yield motor.Op(collection.find_one, {'_id': my_id}) # New style: document = yield collection.find_one({'_id': my_id}) """ _id = NumberType(number_class=ObjectId, number_type="ObjectId") def __init__(self, *args, **kwargs): """ db settings 虽然这边有db的属性,但是在handler里面写逻辑,有时候引用这个db不太方便, 所以在handler里面加了db属性,直接在那边调用. 注意各个方法,有的db是默认参数,有的db需要手动带入,使用时要注意别弄错了。 """ default_db = context['dbconn'].test self.set_db(kwargs.pop('db', default_db)) super(BaseMongoModel, self).__init__(*args, **kwargs) @property def db(self): return getattr(self, '_db', None) def set_db(self, db): self._db = db @classmethod def process_query(cls, query): """ query can be modified here before actual providing to database. """ return dict(query) @property def pk(self): return self._id @classmethod def get_model_name(cls): return cls.MONGO_COLLECTION @classmethod def get_collection(cls): return getattr(cls, 'MONGO_COLLECTION', None) @classmethod def check_collection(cls, collection): return collection or cls.get_collection() @classmethod def find_list_len(cls): return getattr(cls, 'FIND_LIST_LEN', MAX_FIND_LIST_LEN) @classmethod @gen.coroutine def find_one(cls, db, query, collection=None, model=True): result = None c = cls.check_collection(collection) query = cls.process_query(query) for i in cls.reconnect_amount(): try: result = yield db[c].find_one(query) except ConnectionFailure as e: exceed = yield cls.check_reconnect_tries_and_wait( i, 'find_one') if exceed: raise e else: if model and result: result = cls.make_model(result, "find_one", db=db) raise gen.Return(result) @classmethod @gen.coroutine def remove_entries(cls, db, query, collection=None): """ Removes documents by given query. Example: obj = yield ExampleModel.remove_entries( self.db, {"first_name": "Hello"}) """ c = cls.check_collection(collection) query = cls.process_query(query) for i in cls.reconnect_amount(): try: yield db[c].remove(query) except ConnectionFailure as e: exceed = yield cls.check_reconnect_tries_and_wait( i, 'remove_entries') if exceed: raise e else: return @gen.coroutine def remove(self, db, collection=None): """ Removes current instance from database. Example: obj = yield ExampleModel.find_one(self.db, {"last_name": "Sara"}) yield obj.remove(self.db) """ _id = self.to_primitive()['_id'] yield self.remove_entries(db, {"_id": _id}, collection) @gen.coroutine def save(self, db=None, collection=None, ser=None): """ If object has _id, then object will be created or fully rewritten. If not, object will be inserted and _id will be assigned. Example: obj = ExampleModel({"first_name": "Vasya"}) yield obj.save(self.db) """ db = db or self.db c = self.check_collection(collection) data = self.get_data_for_save(ser) result = None for i in self.reconnect_amount(): try: result = yield db[c].save(data) except ConnectionFailure as e: exceed = yield self.check_reconnect_tries_and_wait(i, 'save') if exceed: raise e else: if result: self._id = result return @gen.coroutine def insert(self, db=None, collection=None, ser=None, **kwargs): """ If object has _id, then object will be inserted with given _id. If object with such _id is already in database, then pymongo.errors.DuplicateKeyError will be raised. If object has no _id, then object will be inserted and _id will be assigned. Example: obj = ExampleModel({"first_name": "Vasya"}) yield obj.insert() """ db = db or self.db c = self.check_collection(collection) data = self.get_data_for_save(ser) for i in self.reconnect_amount(): try: result = yield db[c].insert(data, **kwargs) except ConnectionFailure as e: exceed = yield self.check_reconnect_tries_and_wait(i, 'insert') if exceed: raise e else: if result: self._id = result return @gen.coroutine def update(self, db=None, query=None, collection=None, update=None, ser=None, upsert=False, multi=False): """ Updates the object. If object has _id, then try to update the object. If object with given _id is not found in database, or object doesn't have _id field, then save it and assign generated _id. Difference from save: Suppose such object in database: {"_id": 1, "foo": "egg1", "bar": "egg2"} We want to save following data: {"_id": 1, "foo": "egg3"} If we'll run save, then in database will be following data: {"_id": 1, "foo": "egg3"} # "bar": "egg2" is removed But if we'll run update, then existing fields will be kept: {"_id": 1, "foo": "egg3", "bar": "egg2"} Example: obj = yield ExampleModel.find_one(self.db, {"first_name": "Foo"}) obj.last_name = "Bar" yield obj.update(self.db) """ db = db or self.db # TODO: refactor, update and ser arguments are very similar, left only one c = self.check_collection(collection) if update is None: data = self.get_data_for_save(ser) else: data = update if not query: _id = self.pk or data.pop("_id") query = {"_id": _id} if update is None: data = {"$set": data} for i in self.reconnect_amount(): try: result = yield db[c].update(query, data, upsert=upsert, multi=multi) except ConnectionFailure as e: exceed = yield self.check_reconnect_tries_and_wait(i, 'update') if exceed: raise e else: l.debug("Update result: {0}".format(result)) raise gen.Return(result) @classmethod def get_cursor(cls, db, query, collection=None, fields={}): c = cls.check_collection(collection) query = cls.process_query(query) return db[c].find(query, fields) if fields else db[c].find(query) @classmethod @gen.coroutine def find(cls, cursor, model=True, list_len=None): """ Returns a list of found documents. :arg cursor: motor cursor for find :arg model: if True, then construct model instance for each document. Otherwise, just leave them as list of dicts. :arg list_len: list of documents to be returned. Example: cursor = ExampleModel.get_cursor(self.db, {"first_name": "Hello"}) objects = yield ExampleModel.find(cursor) """ result = None list_len = list_len or cls.find_list_len() or MAX_FIND_LIST_LEN for i in cls.reconnect_amount(): try: result = yield cursor.to_list(list_len) except ConnectionFailure as e: exceed = yield cls.check_reconnect_tries_and_wait(i, 'find') if exceed: raise e else: if model: field_names_set = set(cls._fields.keys()) for i in xrange(len(result)): result[i] = cls.make_model(result[i], "find", field_names_set) raise gen.Return(result) @classmethod @gen.coroutine def aggregate(cls, db, pipe_list, collection=None): c = cls.check_collection(collection) for i in cls.reconnect_amount(): try: result = yield db[c].aggregate(pipe_list) except ConnectionFailure as e: exceed = yield cls.check_reconnect_tries_and_wait( i, 'aggregate') if exceed: raise e else: raise gen.Return(result) @staticmethod def reconnect_amount(): return xrange(MONGO_RECONNECT_TRIES + 1) @classmethod @gen.coroutine def check_reconnect_tries_and_wait(cls, reconnect_number, func_name): if reconnect_number >= MONGO_RECONNECT_TRIES: raise gen.Return(True) else: timeout = MONGO_RECONNECT_TIMEOUT l.warning("ConnectionFailure #{0} in {1}.{2}. Waiting {3} seconds". format(reconnect_number + 1, cls.__name__, func_name, timeout)) io_loop = ioloop.IOLoop.instance() yield gen.Task(io_loop.add_timeout, timedelta(seconds=timeout)) def get_data_for_save(self, ser): data = ser or self.to_primitive() if '_id' in data and data['_id'] is None: del data['_id'] return data @classmethod def make_model(cls, data, method_name, field_names_set=None, db=None): """ Create model instance from data (dict). """ if field_names_set is None: field_names_set = set(cls._fields.keys()) else: if not isinstance(field_names_set, set): field_names_set = set(field_names_set) new_keys = set(data.keys()) - field_names_set if new_keys: l.warning("'{0}' has unhandled fields in DB: " "'{1}'. {2} returned data: '{3}'".format( cls.__name__, new_keys, data, method_name)) for new_key in new_keys: del data[new_key] return cls(raw_data=data, db=db)
class BillingProfile( Model): # belongs to VmScaleSet >> VirtualMachineScaleSetVMProfile max_price = NumberType(serialize_when_none=False)
class BaseModel(Model): _id = NumberType(number_class=ObjectId, number_type="ObjectId") def __init__(self, *args, **kwargs): self.errors = [] self.set_db(kwargs.pop('db', None)) if args and args[0].get("errors"): self.errors.append(args[0]['errors']) try: super(BaseModel, self).__init__(*args, **kwargs) except ModelConversionError as error: self.errors.append(error.messages) args_dict = args[0] # print("errors = ", error.messages.keys()) # print("dict = ", args[0]) for key in error.messages.keys(): del args_dict[key] super(BaseModel, self).__init__(args_dict, *args[1:], **kwargs) @property def db(self): return getattr(self, '_db', None) def set_db(self, db): self._db = db @classmethod def process_query(cls, query): """ query can be modified here before actual providing to database. """ return dict(query) @classmethod def get_collection(cls): return getattr(cls, 'MONGO_COLLECTION', None) @classmethod def check_collection(cls, collection): return collection or cls.get_collection() def get_data_for_save(self, ser): data = ser or self.to_primitive() if '_id' in data and data['_id'] is None: del data['_id'] return data @gen.coroutine def save(self, db=None, collection=None, ser=None): """ Сохраняет объект в db """ try: self.validate() except ModelValidationError as error: self.errors.append(error.messages) if self.errors: return # save Obj to DB db = db or self.db c = self.check_collection(collection) data = self.get_data_for_save(ser) # result = None for i in self.reconnect_amount(): try: result = yield motor.Op(db[c].save, data) except ConnectionFailure as e: exceed = yield self.check_reconnect_tries_and_wait(i, 'save') if exceed: raise e else: if result: self._id = result return @classmethod @gen.coroutine def find_one(cls, db, query, collection=None, model=True): # result = None query = cls.process_query(query) for i in cls.reconnect_amount(): try: result = yield motor.Op( db[cls.check_collection(collection)].find_one, query) except ConnectionFailure as e: exceed = yield cls.check_reconnect_tries_and_wait( i, 'find_one') if exceed: raise e else: print('result = ', result) if model and result: result = cls.make_model(result, "find_one", db=db) raise gen.Return(result or []) @staticmethod def reconnect_amount(): return range(MONGO_DB['reconnect_tries'] + 1) @classmethod @gen.coroutine def check_reconnect_tries_and_wait(cls, reconnect_number, func_name): if reconnect_number >= MONGO_DB['reconnect_tries']: raise gen.Return(True) else: timeout = MONGO_DB['reconnect_timeout'] l.warning("ConnectionFailure #{0} in {1}.{2}. Waiting {3} seconds". format(reconnect_number + 1, cls.__name__, func_name, timeout)) io_loop = ioloop.IOLoop.instance() yield gen.Task(io_loop.add_timeout, timedelta(seconds=timeout)) @classmethod def make_model(cls, data, method_name, field_names_set=None, db=None): """ Create model instance from data (dict). """ if field_names_set is None: field_names_set = set(cls._fields.keys()) else: if not isinstance(field_names_set, set): field_names_set = set(field_names_set) new_keys = set(data.keys()) - field_names_set if new_keys: l.warning("'{0}' has unhandled fields in DB: " "'{1}'. {2} returned data: '{3}'".format( cls.__name__, new_keys, data, method_name)) for new_key in new_keys: del data[new_key] return cls(raw_data=data, db=db)
class ProductGDSN(Model): # Col_A = StringType(default='', serialize_when_none=False) Label_Description = StringType(max_length=200, required=False, default='None') Trade_Item_GTIN = StringType(regex="\d(539|501|509|0\d\d)\d{10}", required=True) Product_Description = StringType(max_length=200, required=True) Information_Provider_GLN = StringType(regex="\d{13}", required=True) Information_Provider_Name = StringType(max_length=100, required=False, default='GS1 Ireland') Company_Name = StringType(max_length=100, required=True) Target_Market = StringType(choices=[tm[0] for tm in TM], required=False, default='372') Trade_Item_Country_Of_Origin = StringType(choices=[tm[0] for tm in TM], required=False, default='372') Use_Language_Code_List = StringType(choices=[lng[0] for lng in LANGUAGES], default='en') # 58 Classification_Category_Code = StringType(required=True) Base_Unit_Indicator = MyBooleanType(required=True) Consumer_Unit_Indicator = MyBooleanType(required=True) Variable_Weight_Trade_Item = MyBooleanType(required=True) Ordering_Unit_Indicator = MyBooleanType(required=True) Dispatch_Unit_Indicator = MyBooleanType(required=True) Invoice_Unit_Indicator = MyBooleanType(required=True) Trade_Item_Unit_Descriptor = StringType( choices=[d[1] for d in PACKAGE_LEVELS], required=True) Functional_Name = StringType(max_length=75, required=True) Brand_Name = StringType(max_length=75, required=True) Height = DecimalType(required=False) Width = DecimalType(required=False) Depth = DecimalType(required=False) Height_UOM = StringType(choices=[uom[0] for uom in UOMS], required=False) Width_UOM = StringType(choices=[uom[0] for uom in UOMS], required=False) Depth_UOM = StringType(choices=[uom[0] for uom in UOMS], required=False) Gross_Weight = DecimalType(required=False) Gross_Weight_UOM = StringType(choices=[uom[0] for uom in UOMS], required=False) Net_Content = StringType(max_length=10, required=False) Net_Content_UOM = StringType(choices=[uom[0] for uom in UOMS], required=False) Packaging_Type_Code = StringType(choices=[pt[0] for pt in PACKAGE_TYPES], required=False) Trade_Item_Last_Change_Date = DateTimeType( required=False, serialized_format="%Y-%m-%dT%H:%M:%S%zZ") Discontinued_Date = DateTimeType(required=False, serialized_format="%Y-%m-%dT%H:%M:%S%zZ") Col_AM = StringType(default='', serialize_when_none=False) Sub_Brand = StringType(max_length=75, required=False) Variant_Description = StringType(max_length=75, required=False) Net_Weight = DecimalType(required=False) Net_Weight_UOM = StringType(choices=[uom[0] for uom in UOMS], required=False) Manufacturer_GLN = StringType(required=False) Manufacturer_Name = StringType(max_length=100, required=False) Additional_Trade_Item_Identification_Type = StringType(max_length=50, required=False) Additional_Trade_Item_Identification_Value = StringType(max_length=50, required=False) Type_Of_Information = StringType(max_length=100, required=False) Uniform_Resource_Identifier = StringType(max_length=100, required=False) Packaging_Marked_Returnable = MyBooleanType() Is_Price_On_Pack = MyBooleanType() GTIN_Of_Next_Lower_Item = StringType(required=False) Amount_Of_Next_Lower_Level_Items = StringType(required=False) Quantity_Of_Children = NumberType(int, 'Integer', min_value=1, required=False) Total_Quantity_Of_Next_Lower_Level_Trade_Item = StringType(required=False) Start_Availability_Date_Time = DateTimeType( required=False, serialized_format="%Y-%m-%dT%H:%M:%S%zZ") End_Availability_Date_Time = DateTimeType( required=False, serialized_format="%Y-%m-%dT%H:%M:%S%zZ") Trade_Item_Status = StringType(max_length=25, required=False, default='ADD') Brand_Owner_GLN = StringType(required=False) Brand_Owner_Name = StringType(max_length=100, required=False) Col_AN = StringType(default='', serialize_when_none=False) Col_AO = StringType(default='', serialize_when_none=False) Col_AP = StringType(default='', serialize_when_none=False) Publication_Date = DateTimeType( required=False, serialized_format="%Y-%m-%dT%H:%M:%S%zZ") # pub_date Effective_Date = DateTimeType( required=False, serialized_format="%Y-%m-%dT%H:%M:%S%zZ") # eff_date Col_AZ = StringType(default='', serialize_when_none=False) Col_BA = StringType(default='', serialize_when_none=False) Col_BB = StringType(default='', serialize_when_none=False) Col_BC = StringType(default='', serialize_when_none=False) Col_BD = StringType(default='', serialize_when_none=False) Col_BE = StringType(default='', serialize_when_none=False) Col_BF = StringType(default='', serialize_when_none=False) Col_BG = StringType(default='', serialize_when_none=False) Col_BH = StringType(default='', serialize_when_none=False) Col_BI = StringType(default='', serialize_when_none=False) Col_BJ = StringType(default='', serialize_when_none=False) Col_BK = StringType(default='', serialize_when_none=False) Col_BL = StringType(default='', serialize_when_none=False) Barcode_Type = StringType(choices=[bt[0] for bt in BARCODE_TYPES], required=False) Col_BO = StringType(default='', serialize_when_none=False) Col_BP = StringType(default='', serialize_when_none=False) Col_BQ = StringType(default='', serialize_when_none=False) Col_BV = StringType(default='', serialize_when_none=False) Col_BW = StringType(default='', serialize_when_none=False) Col_BX = StringType(default='', serialize_when_none=False) Col_BY = StringType(default='', serialize_when_none=False) Col_BZ = StringType(default='', serialize_when_none=False) Col_CA = StringType(default='', serialize_when_none=False) Col_CB = StringType(default='', serialize_when_none=False) Col_CC = StringType(default='', serialize_when_none=False) Col_CD = StringType(default='', serialize_when_none=False) Col_CE = StringType(default='', serialize_when_none=False) Col_CG = StringType(default='', serialize_when_none=False) Col_CH = StringType(default='', serialize_when_none=False) Col_CI = StringType(default='', serialize_when_none=False) Col_CJ = StringType(default='', serialize_when_none=False) Col_CK = StringType(default='', serialize_when_none=False) Col_CL = StringType(default='', serialize_when_none=False) Col_CM = StringType(default='', serialize_when_none=False) Col_CN = StringType(default='', serialize_when_none=False) Col_CO = StringType(default='', serialize_when_none=False) Col_CP = StringType(default='', serialize_when_none=False) Col_CQ = StringType(default='', serialize_when_none=False) Col_CR = StringType(default='', serialize_when_none=False) Col_CS = StringType(default='', serialize_when_none=False) Col_CT = StringType(default='', serialize_when_none=False) Col_CU = StringType(default='', serialize_when_none=False) Col_CV = StringType(default='', serialize_when_none=False) Col_CW = StringType(default='', serialize_when_none=False) Col_CX = StringType(default='', serialize_when_none=False) Col_CY = StringType(default='', serialize_when_none=False) Col_CZ = StringType(default='', serialize_when_none=False) Col_DA = StringType(default='', serialize_when_none=False) Col_DB = StringType(default='', serialize_when_none=False) Col_DC = StringType(default='', serialize_when_none=False) Col_DE = StringType(default='', serialize_when_none=False) GS1CloudStatus = StringType(choices=['ACTIVE', 'INACTIVE'], required=False) ''' # def validate_Additional_Trade_Item_Identification_Value(self, data, value): # if not value: # raise ValidationError("This field is required") def validate_Label_Description(self, data, value): if data['Trade_Item_Unit_Descriptor'] == 'BASE_UNIT_OR_EACH': if not value: raise ValidationError("This field is required for base units") def validate_Classification_Category_Code(self, data, value): cs = CategoriesService() if self.Classification_Category_Code.required and not value: raise ValidationError("Classification Category Code is required") if value and not cs.first(code=value): raise ValidationError( "Classification Category Code is not valid, please consult https://www.gs1.org/gpc/browser") def validate_Manufacturer_GLN(self, data, value): if value and not re.match("\d{13}", value): raise ValidationError("Manufacturer GLN is not valid") if value and not data['Manufacturer_Name']: raise ValidationError("If Manufacturer GLN is present, Manufacturer Name should be present") def validate_Manufacturer_Name(self, data, value): if value and not data['Manufacturer_GLN']: raise ValidationError("If Manufacturer Name is present, Manufacturer GLN should be present") # def validate_Brand_Owner_GLN(self, data, value): # if value and not re.match("\d{13}", value): # raise ValidationError("Brand Owner GLN is not valid") def validate_Trade_Item_GTIN(self, data, value): if not isValid(value): raise ValidationError("GTIN not valid") def validate_Net_Content(self, data, value): if value: if not data.get('Net_Content_UOM'): raise ValidationError("Net Content is given without Net Content UOM") def validate_Net_Content_UOM(self, data, value): if value: if not data.get('Net_Content'): raise ValidationError("Net Content UOM is given without Net Content value") def validate_Net_Weight(self, data, value): if value: if not data.get('Net_Weight_UOM'): raise ValidationError("Net Weight is given without Net Weight UOM") def validate_Net_Weight_UOM(self, data, value): if value: if not data.get('Net_Weight'): raise ValidationError("Net Weight UOM is given without Net Weight value") def validate_Height_UOM(self, data, value): if data['Height'] and not value: raise ValidationError("Height UOM is required when Height is given") def validate_Width_UOM(self, data, value): if data['Width'] and not value: raise ValidationError("Width UOM is required when Width is given") def validate_Depth_UOM(self, data, value): if data['Depth'] and not value: raise ValidationError("Depth UOM is required when Depth is given") def validate_Gross_Weight_UOM(self, data, value): if data['Gross_Weight'] and not value: raise ValidationError("Gross_Weight UOM is required when Gross_Weight is given") def validate_Quantity_Of_Children(self, data, value): if data['Trade_Item_Unit_Descriptor'] != BASE_PACKAGE_LEVEL: if not value: raise ValidationError( "Quantity Of Children is required when Trade Item Unit Descriptor is not BASE UNIT OR EACH") def validate_Quantity_Of_Next_Lower_Level_Item(self, data, value): if data['GTIN_Of_Next_Lower_Item']: if not value: raise ValidationError( "Quantity Of Next Lower Level Item is required when GTIN Of Next Lower Item is given") if len(data['Quantity_Of_Next_Lower_Level_Item'].split(',')) != int(data['Quantity_Of_Children']): raise ValidationError("Length of Quantity Of Next Lower Level Item must equal the Quantity Of Children") def validate_GTIN_Of_Next_Lower_Item(self, data, value): if data['Trade_Item_Unit_Descriptor'] != BASE_PACKAGE_LEVEL: if not value: raise ValidationError( "GTIN Of Next Lower Item is required when Trade Item Unit Descriptor is not BASE UNIT OR EACH") try: int(data['Quantity_Of_Children']) except Exception as e: raise ValidationError("Quantity_Of_Children must be given") if len(data['GTIN_Of_Next_Lower_Item'].split(',')) != int(data['Quantity_Of_Children']): raise ValidationError("Length of GTIN_Of_Next_Lower_Item must equal the Quantity Of Children") # def validate_fileFormatCode(self, data, value): # pass # def validate_Uniform_Resource_Identifier(self, data, value): # if value: # if not value.startswith('http://') or not value.statswith('https://'): # raise ValidationError('Uniform_Resource_Identifier should start with http: or https:') ''' @classmethod def get_fieldnames(cls): return [ # 'Col_A', 'Label_Description', 'Trade_Item_GTIN', 'Information_Provider_GLN', 'Information_Provider_Name', 'Target_Market', 'Base_Unit_Indicator', 'Consumer_Unit_Indicator', 'Variable_Weight_Trade_Item', 'Ordering_Unit_Indicator', 'Dispatch_Unit_Indicator', 'Invoice_Unit_Indicator', 'Start_Availability_Date_Time', 'Classification_Category_Code', 'Trade_Item_Unit_Descriptor', 'Functional_Name', 'Brand_Name', 'Packaging_Marked_Returnable', 'Height', 'Height_UOM', 'Width', 'Width_UOM', 'Depth', 'Depth_UOM', 'Gross_Weight', 'Gross_Weight_UOM', 'End_Availability_Date_Time', 'Sub_Brand', 'Brand_Owner_GLN', 'Brand_Owner_Name', 'Product_Description', 'Variant_Description', 'Net_Content', 'Net_Content_UOM', 'Net_Weight', 'Net_Weight_UOM', 'Packaging_Type_Code', 'Trade_Item_Last_Change_Date', 'Discontinued_Date', 'Col_AM', # Display_Unit_Indicator 'Col_AN', # Platform_Type_Code 'Col_AO', # Packaging_Weight 'Col_AP', # Packaging_Weight_UoM 'Publication_Date', 'Effective_Date', 'GTIN_Of_Next_Lower_Item', 'Amount_Of_Next_Lower_Level_Items', 'Quantity_Of_Children', 'Total_Quantity_Of_Next_Lower_Level_Trade_Item', 'Trade_Item_Country_Of_Origin', 'Manufacturer_GLN', 'Manufacturer_Name', 'Col_AZ', 'Col_BA', 'Col_BB', 'Col_BC', 'Col_BD', 'Col_BE', 'Col_BF', 'Col_BG', 'Col_BH', 'Col_BI', 'Col_BJ', 'Col_BK', 'Col_BL', 'Is_Price_On_Pack', 'Barcode_Type', 'Col_BO', 'Col_BP', 'Col_BQ', 'Additional_Trade_Item_Identification_Type', 'Additional_Trade_Item_Identification_Value', 'Type_Of_Information', 'Uniform_Resource_Identifier', 'Col_BV', 'Col_BW', 'Col_BX', 'Col_BY', 'Col_BZ', 'Col_CA', 'Col_CB', 'Col_CC', 'Col_CD', 'Col_CE', 'Trade_Item_Status', 'Col_CG', 'Col_CH', 'Col_CI', 'Col_CJ', 'Col_CK', 'Col_CL', 'Col_CM', 'Col_CN', 'Col_CO', 'Col_CP', 'Col_CQ', 'Col_CR', 'Col_CS', 'Col_CT', 'Col_CU', 'Col_CV', 'Col_CW', 'Col_CX', 'Col_CY', 'Col_CZ', 'Col_DA', 'Col_DB', 'Col_DC', 'Use_Language_Code_List', 'Col_DE', 'GS1CloudStatus', 'Company_Name' ] @classmethod def export(cls, products, user): errors = [] content = [] tm = ProductTemplate.objects.filter(name="gs1se-base").first() keys = set(x.path.split(".")[-1] for x in tm.attributes.all()) serialized_products = serializers.serialize('json', products, fields=keys) products_data = json.loads(serialized_products) xls_keys = language_mapping(tm, user) for product in products_data: try: res = { xls_keys[key]: get_translated_values(value, user) for key, value in product.get("fields").items() } except ModelConversionError as e: errors.append({ product.gtin: dict([(k, v[0]) for k, v in e.messages.items()]) }) continue except Exception as e: errors.append({product.gtin: {'Exception': str(e)}}) continue content.append(res) return content, errors
class Product(Model): year = NumberType(min_value=2018, max_value=2021, strict=False) # year = IntType() name = StringType(required=True) link = URLType(required=True)