Filling ChoiceBlock with snippet data - python-3.x

I have a snippet for countrycodes and I want to define localized country names on the root pages for each localized site.
The snippet looks like this:
#register_snippet
class Country(models.Model):
iso_code = models.CharField(max_length=2, unique=True)
panels = [
FieldPanel('iso_code'),
]
def get_iso_codes():
try:
countries = Country.objects.all()
result = []
for country in countries:
result.append((country.iso_code,country.iso_code))
return result
except Country.DoesNotExist:
return []
Now I want to call the function get_iso_codes when creating a choiceblock and fill the choices from the snippet.
The block looks like this
class CountryLocalizedBlock(blocks.StructBlock):
iso_code = blocks.ChoiceBlock(choices=Country.get_iso_codes(), unique=True)
localized_name = blocks.CharBlock(required=True)
However, when calling manage.py makemigrations I get the following error:
psycopg2.ProgrammingError: relation "home_country" does not exist
LINE 1: ..."."iso_code", "home_country"."sample_number" FROM "home_coun...
I can bypass this by commenting out 'Country.objects.all()' and then running makemigrations and later readding the line again to the code, however I would prefer a solution that does not require this workaround (also it fails when I run 'manage.py collectstatic' when building before deployment and I don't know how to work around this and am stuck)

I found a solution based on Wagtail, how do I populate the choices in a ChoiceBlock from a different model?
The country class remains untouched (except that the get_iso_codes method is now superflous). I've just extended Chooserblock and use Country as my target_model:
class CountryChooserBlock(blocks.ChooserBlock):
target_model = Country
widget = forms.Select
def value_for_form(self, value):
if isinstance(value, self.target_model):
return value.pk
else:
return value
And used the CountryChooserBlock instead of the ChoiceBlock:
class CountryLocalizedBlock(blocks.StructBlock):
iso_code = CountryChooserBlock(unique=True)
localized_name = blocks.CharBlock(required=True)

Related

Load inconsistent data in pymongo

I am working with pymongo and am wanting to ensure that data saved can be loaded even if additional data elements have been added to the schema.
I have used this for classes that don't need to have the information processed before assigning it to class attributes:
class MyClass(object):
def __init__(self, instance_id):
#set default values
self.database_id = instance_id
self.myvar = 0
#load values from database
self.__load()
def __load(self):
data_dict = Collection.find_one({"_id":self.database_id})
for key, attribute in data_dict.items():
self.__setattr__(key,attribute)
However, in classes that I have to process the data from the database this doesn't work:
class Example(object):
def __init__(self, name):
self.name = name
self.database_id = None
self.member_dict = {}
self.load()
def load(self):
data_dict = Collection.find_one({"name":self.name})
self.database_id = data_dict["_id"]
for element in data_dict["element_list"]:
self.process_element(element)
for member_name, member_info in data_dict["member_class_dict"].items():
self.member_dict[member_name] = MemberClass(member_info)
def process_element(self, element):
print("Do Stuff")
Two example use cases I have are:
1) List of strings the are used to set flags, this is done by calling a function with the string as the argument. (def process_element above)
2) A dictionary of dictionaries which are used to create a list of instances of a class. (MemberClass(member_info) above)
I tried creating properties to handle this but found that __setattr__ doesn't look for properties.
I know I could redefine __setattr__ to look for specific names but it is my understanding that this would slow down all set interactions with the class and I would prefer to avoid that.
I also know I could use a bunch of try/excepts to catch the errors but this would end up making the code very bulky.
I don't mind the load function being slowed down a bit for this but very much want to avoid anything that will slow down the class outside of loading.
So the solution that I came up with is to use the idea of changing the __setattr__ method but instead to handle the exceptions in the load function instead of the __setattr__.
def load(self):
data_dict = Collection.find_one({"name":self.name})
for key, attribute in world_data.items():
if key == "_id":
self.database_id = attribute
elif key == "element_list":
for element in attribute:
self.process_element(element)
elif key == "member_class_dict":
for member_name, member_info in attribute.items():
self.member_dict[member_name] = MemberClass(member_info)
else:
self.__setattr__(key,attribute)
This provides all of the functionality of overriding the __setattr__ method without slowing down any future calls to __setattr__ outside of loading the class.

Trouble working with and updating dictionary using a class and function in Python 3 [Newbie]

I am somewhat new to coding. I have been self teaching myself for the past year or so. I am trying to build a more solid foundation and am trying to create very simple programs. I created a class and am trying to add 'pets' to a dictionary that can hold multiple 'pets'. I have tried changing up the code so many different ways, but nothing is working. Here is what I have so far.
# Created class
class Animal:
# Class Attribute
classes = 'mammal'
breed = 'breed'
# Initializer/Instance Attribrutes
def __init__ (self, species, name, breed):
self.species = species
self.name = name
self.breed = breed
# To get different/multiple user input
#classmethod
def from_input(cls):
return cls(
input('Species: '),
input('Name: '),
input('Breed: ')
)
# Dictionary
pets = {}
# Function to add pet to dictionary
def createpet():
for _ in range(10):
pets.update = Animal.from_input()
if pets.name in pets:
raise ValueError('duplicate ID')
# Calling the function
createpet()
I have tried to change it to a list and use the 'append' tool and that didn't work. I am sure there is a lot wrong with this code, but I am not even sure what to do anymore. I have looked into the 'collections' module, but couldn't understand it well enough to know if that would help or not. What I am looking for is where I can run the 'createpet()' function and each time add in a new pet with the species, name, and breed. I have looked into the sqlite3 and wonder if that might be a better option. If it would be, where would I go to learn and better understand the module (aka good beginner tutorials). Any help would be appreciated. Thanks!
(First of all, you have to check for a duplicate before you add it to the dictionary.)
The way you add items to a dictionary x is
x[y] = z
This sets the value with the key y equal to z or, if there is no key with that name, creates a new key y with the value z.
Updated code:
(I defined this as a classmethod because the from_input method is one as well and from what I understand of this, this will keep things working when it comes to inheriting classes, for further information you might want to look at this)
#classmethod
def createpet(cls):
pet = cls.from_input()
if pet.name in cls.pets:
raise ValueError("duplicate ID")
else:
cls.pets[pet.name] = pet

csv file process in Python

I work with a csv data as follow:
ticker,exchange_country,company_name,price,exchange_rate,shares_outstanding,net_income
1,HK,CK HUTCHISON HOLDINGS LTD,1.404816984,7.757949829,3859.677979,31633
2,HK,CLP HOLDINGS LTD,1.312602194,7.757949829,2526.450928,16319
3,HK,HONG KONG & CHINA GAS CO LTD,0.234939214,7.757949829,12717.04199,7546.200195
11,HK,HANG SENG BANK LTD,2.198193203,7.757949829,1911.843018,15451
I have a StockStatRecord class:
class StockStatRecord:
def __init__(self, stock_load):
self.name = stock_load[0]
self.company_name = stock_load[2]
self.exchange_country = stock_load[1]
self.price = stock_load[3]
self.exchange_rate = stock_load[4]
self.shares_outstanding = stock_load[5]
self.net_income = stock_load[6]
How am I supposed to create another class to extract the data from that CSV, parse it, create new record and return the record created? In this class, it also needs to validate the rows when reading. Validation will fail for any row that is missing any piece of information, or if the name (symbol or player name) is empty, or if any of the numbers(int or float) cannot be parsed ( watch out of the division by zero).
There are several ways of doing this, either rolling out the code yourself, or using a Python module that is made for veryfing data-schemas, like Colander, or the extended CSV reader in Pandas (as Zwinck posted in the comment above).
What is not usually needed is a separate class to check values- you can do that on the same class - or usually, have a base class that implements the data-validation mechanisms, and then just have extra information on each field for the actual data classes. And finally, if you need to process data and spill an object back, there is no need for a class because in Python you can have functions independents of classes - there is no need to try to hammer down every piece of code to a class.
One simple thing to there is to (1) use Python's csv.DictReader instead of csv.Reader to read the rows - that way you have each piece of data bound to the column name already, as a dict, instead of a list where you have to manually track the column numbers, then set a property for each of the columns you need validation, so that the fields can be validated on setting - and a __init__ method that simply assigns all fields to their respectiv attributes:
class SockStatRecord:
def __init__(self, row):
for key, value in row.items():
setattr(self, key, value)
#property
def name(self):
return self._name
#name.setter
def name(self, value):
if not name: # example verification for empty name
raise ValueError
self._name = name
# continue for other fields
import csv
reader = csv.Dictreader(open("mydatafile.csv"))
all_records = []
for row in reader:
try:
all_records.append(StockDataRecord(row))
except ValueError:
print("Some error at record: {}".format(row))

How to get Id from Object in Odoo 10?

This is my structure:
class Imprint_Location(models.Model):
_name = 'imprint.location'
name = fields.Char()
product_id = fields.Many2one('product.template')
class Imprint_Charges(models.Model):
_name = 'imprint.charge'
_rec_name = 'location_id'
product_id_c = fields.Many2one('product.template', required=True)
location_id = fields.Many2one('imprint.location', required=True)
#api.multi
#api.onchange('product_id_c', 'location_id')
def product_filter(self):
res = {}
print '\n\n-------\n\n', self, self.product_id_c, '\n\n-------\n\n'
if self.product_id_c:
res['domain'] = {'location_id': [('product_id', '=', self.product_id_c.id)]}
print res
return res
class Product_Template(models.Model):
_inherit = 'product.template'
imprint_location_ids = fields.One2many('imprint.location', 'product_id')
sale_imprint_charge_ids = fields.One2many('imprint.charge', 'product_id_c')
Now i have defined a page in product.template and inside the page is sale_imprint_charge_ids which is in <tree editable="bottom"> and i am not selecting the product_id_c field[also this field doesn't show up in the tree defined].
Now my problem here is that when i select this from the form view which i defined for imprint.charge the method product_filter works fine, but when i enter from the product.template then i get a error saying
TypeError: <odoo.models.NewId object at 0x7fbb8bc21b90> is not JSON serializable
Because from product.template if passes the object <odoo.models.NewId object at 0x7fbb8bc21b90> , so if print self.product_id_c then it prints product.template(<odoo.models.NewId object at 0x7fbb8bc21b90>) so this is not serializable. i have tried doing self.product_id_c.ids which give output empty list [].
So how do get the product.template id from the object or pass the id itself overriding some method.
You should improve couple of following points.
res['domain'] = {'location_id': [('product_id', '=', self.product_id_c.id)]}
return res
study some search() method of ORM
Try with following code:
#api.multi
#api.onchange('product_id_c', 'location_id')
def product_filter(self):
res = {}
if self.product_id_c:
self.location_id = False
#search product_template in imprint.locationwith table and limit we will get only record if related record found
location_id = self.env['imprint.location'].search([('product_id', '=', self.product_id_c.id)], limit=1)
if location_id:
#location_id.ids will give you something like [2] so we need to set value as 2
self.location_id = location_id.ids[0]
EDIT:
As per your first comment, you need a list of related location then we should following trick.
Remove product_filter() method
Add domain in imprint.charge object view file
For example:
<field name="location_id" domain="[('product_id', '=', product_id_c)]"/>
Afterwards, Restart Odoo server and upgrade your custom module.
When creating a brand new record Odoo creates that wierd <odoo.models.NewId object at 0x7fbb8bc21b90> object. After you have written the record this id gets turned into the normal ids that you are used to (an integer). In this situation you have a function which (not unreasonably) expects a real id value at a point when no such value really exists. You need to provide a fallback, such as evaluating if the id is an integer and providing an alternate value in that circumstance. Although your function seems to return an object which I dont quite know what you are expecting to happen. If you wish to modify the value of one of your fields I would modify the values of the self object rather that returning an object.

Mongoengine Link to Existing Collection

I'm working with Flask/Mongoengine-MongoDB for my latest web application.
I'm familiar with Pymongo, but I'm new to object-document mappers like Mongoengine.
I have a database and collection set up already, and I basically just want to query it and return the corresponding object. Here's a look at my models.py...
from app import db
# ----------------------------------------
# Taking steps towards a working backend.
# ----------------------------------------
class Property(db.Document):
# Document variables.
total_annual_rates = db.IntField()
land_value = db.IntField()
land_area = db.IntField()
assessment_number = db.StringField(max_length=255, required=True)
address = db.StringField(max_length=255, required=True)
current_capital_value = db.IntField
valuation_as_at_date = db.StringField(max_length=255, required=True)
legal_description = db.StringField(max_length=255, required=True)
capital_value = db.IntField()
annual_value = db.StringField(max_length=255, required=True)
certificate_of_title_number = db.StringField(max_length=255, required=True)
def __repr__(self):
return address
def get_property_from_db(self, query_string):
if not query_string:
raise ValueError()
# Ultra-simple search for the moment.
properties_found = Property.objects(address=query_string)
return properties_found[0]
The error I get is as follows: IndexError: no such item for Cursor instance
This makes complete sense, since the object isn't pointing at any collection. Despite trolling through the docs for a while, I still have no idea how to do this.
Do any of you know how I could appropriately link up my Property class to my already extant database and collection?
The way to link a class to an existing collection can be accomplished as such, using meta:
class Person(db.DynamicDocument):
# Meta variables.
meta = {
'collection': 'properties'
}
# Document variables.
name = db.StringField()
age = db.IntField()
Then, when using the class object, one can actually make use of this functionality as might be expected with MongoEngine:
desired_documents = Person.objects(name="John Smith")
john = desired_documents[0]
Or something similar :) Hope this helps!
I was googling this same question and i noticed the answer has changed since the previous answer:
According to the latest Mongoengine guide:
If you need to change the name of the collection (e.g. to use MongoEngine with an existing
database), then create a class dictionary attribute called meta on your document, and set collection to the
name of the collection that you want your document class to use:
class Page(Document):
meta = {'collection': 'cmsPage'}
The code on the grey did the trick and i could use my data instantly.

Resources