how to initialise a peewee.Model object? __init__() doesn't work - python

I am not able to initialise the fields of a "peewee.Model" descendant object with the usual init() method. How can I initialise alternatively?
import peewee
peewee_database = peewee.SqliteDatabase('example.db')
class Config():
def __init__(self, seats, cylinders):
self.seats = seats
self.cylinders = cylinders
class Car(peewee.Model):
magic_number = peewee.IntegerField()
color = peewee.TextField()
class Meta:
database = peewee_database
def __init__(self, config):
self.magic_number = config.seats / config.cylinders
self.color = None
peewee_database.connect()
peewee_database.create_tables([Car])
config = Config(7, 6)
car = Car(config)
car.color = "blue"
car.save()
produces this error in Python3:
File "test.py", line 27, in <module>
car = Car(config)
File "test.py", line 20, in __init__
self.magic_number = config.seats / config.cylinders
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/peewee.py", line 3764, in __set__
instance.__data__[self.name] = value
TypeError: 'NoneType' object does not support item assignment
help! :)

the Peewee author was so kind to answer himself. I think using a factory method is the cleanest solution, to avoid conflicting with the way peewee uses __init()__
You can still put it in __init__() with the caveat that __init__() is
going to be called not just when instantiating objects yourself, but
also every time a Car instance is read from a database cursor. I think
you probably could make a classmethod on your Car object and use that
as a factory for complex logic?
Refer to this.

what you doing is kinda wrong.
u can separate class Car that peewee use for database management and use other class like "class ACar():" to create your object car and after that u can save your data in database by calling Car.get_or_create(magic_number=car.magic_number , color=car.color).
see peewee documentation about creating record. because the way you are using is wrong.
you are saving car that is and object of Car and not the module that peewee suppose to return it to you after using Car.get_or_none(...).
even if you will use save, u need to use it in record that already exist in database. if u want to create new record use create(), and it's a class methode ( mean, Car.create()).
hope this gives you and idea about how to re-write your code.
even if you want one class Car, use Car.create(...) to create your record and not the object, if you already have a record, the object car = Car() it's not right, the right way it car = Car.get_or_none('your parameters').
Car.get_or_create(...) will create a record if not exist, see documentation

Related

Cross-classes manipulations of objects in Python

I am trying to make a simple library OOP program in Python.Here is the structure:
class Books(object) with attributes
class Books(object):
book_id=""
book_title=""
Books=[book_id,book_title]
def __init__(self,book_id,book_title):
self.book_id = book_id
self.book_title = book_title
#Books=[book_id,book_title]
book2= Books('1504231','Murders')
print(book1.__str__())
class BookList(Books) with objects of created by class Books
class BookList(Books):
def __init__(self):
self.listbook = []
book_list= BookList()
book_list.add_book_object(book2)
book_list.show_books()
(Operations in this scope works for me good)
class Users(object) with attributes (Similar def and init as for Books)
user1= Users ('adfelko','Adam')
print(user1.__str__())
class UserList(Users) with objects of created by class Users (Similar def and init as for BookList)
user_list= UserList()
user_list.add_user_object(user1)
user_list.show_users()
(Operations in this scope works for me good)
Now, I am trying to create actual Lease class, which will hold dictionary of objects(each object=each lease, each leases = [users object, books object])
This is my try:
#Definition of class Leases
class Leases(Users,Books):
#Set constructor
def __init__(self,user,book):
self.leases = [user,book]
#Create a lease
def borrow_book_to_user(self,u_name,t_book):
user=u_name
book=t_book
lease = [user,book]
self.leases.append(lease)
#Show lease
def __str__(self):
print(self)
Maybe I have a bad concept of using it, not sure, but I should probably not go through lists- BookList and UserList ?
Or how I should I get it connected and be able to call functions of the previous classes?
The thing for now works:
lease= Leases(user1,book2)
lease.__str__()
But the output looks something like this:
[<__main__.Users object at 0x0000010E69BFE280>, <__main__.Books object at 0x0000010E69BFE1F0>]
I would like to get direct out put like:
[ ['adfelko','Adam'],['1504231','Murders'] ]
With possibility to get access and change the attributes of this Users or Books object from Leases class, is someone able to help here please ?
Thanks
Best Regards
UPDATE:
#guimoute Thank you for your comment! It did not help to resolve, but helped me to understand more in depth.
I had to rethink my usage of Leases class(other stuff stay same):
#Definition of class leases
class Leases():
#Set constructor
def __init__(self):
self.leases = []
#Create lease object
def add_lease_object(self,user,book):
lease = { user : book}
self.leases.append(lease)
#Create lease object
def del_lease_object(self,user,book):
lease = { user : book}
self.leases.remove(lease)
#Show lease
def __str__(self):
return(self.leases)
#Show leases
def show_leases(self):
for l in self.leases:
#print(vars(l))
#json.dump(l,str)
print(l.__str__())
And I am executing:
lease= Leases()
lease.add_lease_object(user1,book2)
#print(lease.__str__())
print("*************************")
lease.show_leases()
print("*************************")
lease.add_lease_object(user2,book3)
print("*************************")
lease.show_leases()
print("*************************")
lease.del_lease_object(user2,book3)
print("*************************")
lease.show_leases()
Which seems to be working right, but again it is not showing output of nested objects as a string values:
{<main.Users object at 0x000001F9BD98E250>: <main.Books object at 0x000001F9BD8F2EB0>}
{<main.Users object at 0x000001F9BD98E250>: <main.Books object at 0x000001F9BD8F2EB0>} {<main.Users object at 0x000001F9BD98ED90>: <main.Books object at 0x000001F9BD98E1F0>}
{<main.Users object at 0x000001F9BD98E250>: <main.Books object at 0x000001F9BD8F2EB0>}
As you can see above I have tried even:
#print(vars(l))
#json.dump(l,str)
But similar result when trying to access nested object of different class. Do you have any better idea please ? Thank you
The ouptut you see:
{<main.Users object at 0x000001F9BD98E250>: <main.Books object at 0x000001F9BD8F2EB0>} {<main.Users object at 0x000001F9BD98ED90>: <main.Books object at 0x000001F9BD98E1F0>}
Is the default text representation of your instances of Users and Books. If you want it to display differently, you just have to override the __str__ method in both of these classes:
class Books(object):
[...]
def __str__(self) -> str:
return "{}, {}".format(self.book_id, self.book_title)
Now, when you directly (like with str(book1)) or indirectly call for a textual reprensentation of your Book and similarly User objects, your __str__ methods will be used instead of the default one.

FactoryBoy is accessing normal DB instead of TEST DB

I'm trying to create some objects in setUp method of Django test case. I use FactoryBoy that helps me with creating the objects. But it seems that FactoryBoy can't find any objects in the database.
factories.py
class ProductFactory(DjangoModelFactory):
...
market_category = factory.fuzzy.FuzzyChoice(list(MarketplaceCategory.objects.all()))
class Meta:
model = Product
tests.py
from django.test import TestCase
from marketplaces.models import MarketplaceCategory
class MyTestCase(TestCase):
def setUp(self) -> None:
...
self.marketplace_category = MarketplaceCategoryFactory.create()
print(MarketplaceCategory.objects.first().pk) # prints 1
self.product = ProductFactory(created_by=self.user)
As you can see, ProductFactory tries to populate Product.market_category by random MarketCategory object.
The problem is that it seems like it does not exist even when I've created it before and made sure it is in the db (it has pk).
EDIT: It chose a MarketCategory object with pk=25 but there is only one such objects in the test db with pk=1. I think it accesses Django development DB instead of testing one.
The error:
psycopg2.errors.ForeignKeyViolation: insert or update on table "products_product" violates foreign key constraint "products_product_market_category_id_2d634517_fk"
DETAIL: Key (market_category_id)=(25) is not present in table "marketplaces_marketplacecategory".
Do you have any idea why it behaves this way? It looks like the Factory is accessing the real DB instead of testdb for some reason.
Defining the "market_category" field like that is going to cause issues, the queryset that populates the choices is going to be executed at some random time whenever the module is imported and the instances returned may no longer exist. You should use a SubFactory
class ProductFactory(DjangoModelFactory):
market_category = factory.SubFactory(MarketplaceCategoryFactory)
class Meta:
model = Product
Pass the queryset directly to FuzzyChoice to get a random existing value, don't convert it to a list
class ProductFactory(DjangoModelFactory):
market_category = factory.fuzzy.FuzzyChoice(MarketplaceCategory.objects.all())
class Meta:
model = Product
This will then create an instance whenever you create a product but you can pass "market_category" to the factory to override it
class MyTestCase(TestCase):
def setUp(self) -> None:
self.marketplace_category = MarketplaceCategoryFactory.create()
self.product = ProductFactory(created_by=self.user, market_category =self.marketplace_category)

Python - Accessing subclasses' variables from parent class while calling classmethods

i'm trying to build sort of a "mini django model" for working with Django and MongoDB without using the norel Django's dist (i don't need ORM access for these...).
So, what i'm trying to do is to mimic the standart behavior or "implementation" of default models of django... that's what i've got so far:
File "models.py" (the base)
from django.conf import settings
import pymongo
class Model(object):
#classmethod
def db(cls):
db = pymongo.Connection(settings.MONGODB_CONF['host'], settings.MONGODB_CONF['port'])
#classmethod
class objects(object):
#classmethod
def all(cls):
db = Model.db() #Not using yet... not even sure if that's the best way to do it
print Model.collection
File "mongomodels.py" (the implementation)
from mongodb import models
class ModelTest1(models.Model):
database = 'mymongodb'
collection = 'mymongocollection1'
class ModelTest2(models.Model):
database = 'mymongodb'
collection = 'mymongocollection2'
File "views.py" (the view)
from mongomodels import ModelTest1, ModelTest2
print ModelTest1.objects.all() #Should print 'mymongocollection1'
print ModelTest2.objects.all() #Should print 'mymongocollection2'
The problem is that it's not accessing the variables from ModelTest1, but from the original Model... what's wrong??
You must give objects some sort of link to class that contains it. Currently, you are just hard-coding it to use Model()s atttributes. Because you are not instantiating these classes, you will either have to use either a decorator or a metaclass to create the object class for you in each subclass of Model().

Python pass instance of itself as an argument to another function

I have a UserModel class that will essentially do everything like login and update things.
I'm trying to pass the instance of itself (the full class) as an argument to another function of another class.
For example: (obviously not the code, but you get the idea)
from Car import CarFactory
class UserModel:
def __init__(self,username):
self.username = username
def settings(self,colour,age,height):
return {'colour':colour,'age':age,'height':height}
def updateCar(self,car_id):
c = CarFactory(car_id, <<this UserModel instance>>)
So, as you can see from the very last line above I would like to pass an instance of UserModel to the CarData class, so when within the CarData class I can access the UserModel.settings(), however, I am unsure of the syntax. I could of course just do:
c = CarFactory(car_id,self.settings)
Any help would be grateful appreciated.
Thanks
c = CarFactory(car_id, self)
doesnt work?
on a side note it would be self.settings() not self.settings ... unless you define settings to be a property

'NoneType' object has no attribute 'get' error using SQLAlchemy

I've been trying to map an object to a database using SQLAlchemy but have run into a snag.
Edit: Basically changed a whole bunch of stuff.
Version info if handy: [OS: Mac OSX 10.5.8 | Python: 2.6.4 | SQLAlchemy: 0.5.8]
The class I'm going to map:
class Student(object):
def __init__(self, id, name):
self.id = id
self.name = name
def __repr__(self):
return str(self)
def __str__(self):
return "%s %s" %(self.id, self.name)
Background:
Now, I've got a function that reads in the necessary information from a text database into these objects. The function more or less works and I can easily access the information from the objects.
Before the SQLAlchemy code runs, the function will read in the necessary info and store it into the Class. There is a dictionary called students which stores this as such:
students = {}
students[id] = Student(<all the info from the various "reader" functions>)
Afterwards, there is an "allocation" algorithm that will allocate projects to student. It does that well enough. The allocated_project remains as None if a student is unsuccessful in getting a project.
SQLAlchemy bit:
So after all this happens, I'd like to map my object to a database table.
from sqlalchemy import *
from sqlalchemy.orm import *
engine = create_engine('sqlite:///:memory:', echo=False)
metadata = MetaData()
students_table = Table('studs', metadata,
Column('id', Integer, primary_key=True),
Column('name', String)
)
metadata.create_all(engine)
mapper(Student, students_table)
Now after that, I was curious to see if I could print out all the students from my students dictionary.
for student in students.itervalues():
print student
What do I get but an error. This error only takes place if try to print as I am, after calling the mapper:
Traceback (most recent call last):
File "~/FYP_Tests/FYP_Tests.py", line 140, in <module>
print student
File "~/FYP_Tests/Parties.py", line 30, in __str__
return "%s %s" %(self.id, self.name)
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/SQLAlchemy-0.5.8-py2.6.egg/sqlalchemy/orm/attributes.py", line 158, in __get__
return self.impl.get(instance_state(instance), instance_dict(instance))
AttributeError: 'NoneType' object has no attribute 'get'
I'm at a loss as to how to resolve this issue, if it is an issue. If more information is required, please ask and I will provide it.
Questions:
Does the SQLAlchemy mapper change anything about the original Class/dictionary?
Does this have anything specific to way the get works with dictionaries?
You are creating Student instances before mapping class which modifies class to SQLAlchemy needs. So your instance is not properly initialized. Just put the lines creating Student instances after calling mapper(Student, students_table) and everything will work as expected.
It looks like you might have a name shadowing conflict where Column('id'...) hides Student.id. Changing Student.__init__.id to Student._init__.sid would be a quick test to confirm or refute this conjecture.
There is mention of this connection in the third code block of the SQLAlchemy tutorial on mappings.
For example, replacing your first code snippet with this fragement:
class Student(object):
def __init__(self, name, id):
self.sid = id
self.name = name
# and so on
Obviously other references to Student.id would have to change as well.

Categories

Resources