I would like to make use of object-oriented programming style when coding with Peewee. Unfortunately, docs give hints only with kinda global variables handling DB connection. When I try to take adventage of Model and Controller objects (View isn't important at this moment), I'm getting error, probably because of cross-referencing each other:
ImportError: cannot import name 'Application' from 'Application'
(C:\ [... src ...] )
Peewee requires to put database handler in abstract class definition, like this:
class BaseModel(Model):
class Meta:
database = SqliteDatabase('../res/db.db', pragmas={'foreign_keys': 1})
Well, the problem is, I cannot keep the DB handler like that. I'm preparing my app for kinda standalone Windows application with service module. For this reason, I guess I need to store absolute path for db file in config file. Consequently, before the model starts loading database, I need to load configuration files from controller.
What I did was pushing the DB handler to the static field in controller:
from Application import Application
from peewee import *
class BaseModel(Model):
class Meta:
database = Application.database
As you see, DB handler is taken from Application abstract controller. Application is a base controller, from which derives GuiApp and ServiceApp. Both descendands use the same DB, so keeping handler as a static field looks convenient for me.
Now, please do take a look at my Application class:
import logging.handlers
from peewee import SqliteDatabase
import datetime
import threading
from Windows import *
class Application:
database = SqliteDatabase(None)
def __init__(self, appname):
# (...)
from Entities import RouterSettings, BalanceEntry
Application.database.init(
conig_app_src + 'db.db',
pragmas={'foreign_keys': 1})
Application.database.connect()
# !!!
from Entities import RouterSettings, BalanceEntry
# !!!
Application.database.create_tables([RouterSettings, BalanceEntry], safe=True)
The problem is, when I put Peewee Entities import right before the place I start using them, I mean, inside __init__ method, I'm somehow losing accessability from another parts of my app. It forces me to put this import statements in every controller method in order to get proper access to Entity models.
On the other hand, when I put Entity import on top of controller module, I'm getting error from cross referencing. Error message I put above.
To sum up, I'm looking for OOP way to manage app with peewee models. Do you know any way to do that? Or do I have to use global database variable in the app init?
Thanks to #coleifer, I decided to make one another class for database handling:
class DbHandler:
database = SqliteDatabase(None)
#staticmethod
def start(dbSrc):
DbHandler.database.init(
dbSrc + '\\res\\SIMail.db',
pragmas={'foreign_keys': 1})
DbHandler.database.connect()
DbHandler.database.create_tables([RouterSettings, BalanceEntry],
safe=True)
Well, eventually it looks quite similar to global variables, but I think this solution fits my needs. What is the most important, I managed to get out of cross-referencing.
Related
I have a Python (3.7) process to access a cache 2017.xx instance. I want to look at the properties of the existing databases for the instance. I can not seem to find the proper syntax. This is code snippet:
import codecs
import os
import sys
import intersys.pythonbind3 as pyb
url = "localhost[1972]:%SYS"
user= "xxxx"
password="zzzz"
conn = pyb.connection()
conn.connect_now(url,user,password,None)
db = pyb.database(conn)
qry = pyb.query(db)
obj = pyb.object(db)
# I get general database information with:
qry.prepare_class("SYS.Database",'CompactLocalList')
As I loop through the list of databases I want to get the property "MaxSize". The docs I have read mention creating connection to the current database (openId ?) and then accessing properties something like .get()
That is a rational approach but I can not figure out the proper syntax to to get a file handle If that is the proper term) to the current database
After days of research I figured out the logic to get a handle to each of the cache databases. The method to use is the
_db = db.openid([class], directory,-1,-1)
In my case I am using the class = 'SYS.Database'
The directory is the dir for the current database (i.e. 'c:\intersystems\mgr\db')
From this I use the object getters/setters to get the property value:
maxSize = _db.get("MaxSize")
The getter can be used to get the value of any of the properties detailed in the 'SYS.Database' documentation. ( or any other cache class).
I've a implemented a BaseScanner inside common/base/scanner.py that is subclasses by Scanner inside stash/scanner.py, jira/scanner.py, etc.
Now, the problem is that BaseScanner needs to access the ORM models in e.g. stash/db/models.py, depending on where it's subclasses (in stash, jira, etc.):
# common package
common/base/scanner.py
# stash package
stash/scanner.py
stash/db/models.py
# jira package
jira/scanner.py
jira/db/models.py
...
Is it an anti-pattern to provide a module as an argument to a class when instantiating it, like I do here in main.py?
import stash, jira
...
if args.command == 'stash':
import stash.db.models as models
scanner = jira.Scanner(args, models, ...)
scanner.run()
and then to access the different ORM models from inside BaseScanner, like self.models.Scan, self.models.Match, etc.?
If it's an anti-pattern, what could an alternative solution be?
I have two apps say app1 and app2 and I have models in it.
from app2.models import SecondModel
class FirstModel(models.Model):
first_field = models.ManyToManyField(SecondModel, blank=True)# or Foreign Key
from app1.models import FirstModel
class SecondModel(models.Model):
second_field = models.ForeignKey(FirstModel)
When I do this I get import error.
Could not import name 'FirstModel'
Why is this happening ?
The error is because you have a circular import. It's not possible to for both modules to import from each other.
In this case, you don't need to import the models into each app. Remove the imports, and use a string app_label.ModelName instead.
# app1.models.py
class FirstModel(models.Model):
first_field = models.ManyToManyField('app2.SecondModel')
# app2.models.py
class SecondModel(models.Model):
second_field = models.ForeignKey('app1.FirstModel')
there is a name conflict here .. you defined the FirstModel in your models.py and then defined FirstModel, from the code above, this could be the possible problem. Also, the import error generally mean, there is no FirstModel defined from where you are importing it.
However, a more generic way of doing FKs without import is generally
class FkModel(models.Model):
relationship = models.ManyToManyField('appName.modelName')
where appName is the app from where you are trying to import the model from, and modelName is the model to which you are trying to create the relationship. This helps where you are trying to do something like this.
Lets say your app name is 'app' and you are trying to create a many to many relationship from 1st model to a 2nd model for which the class is declared after the 1st model e.g.
class Model1(models.Model):
first_field = models.ManyToManyField('app.Model1')
class Model2(models.Model):
name = models.CharField(maxlength=256)
that is just put your appname.modelName inside strings :)
also, you have a flaw in your ManyToManyField() declaration i.e. you don't need to define blank in Many to Many. The way db's work under the hood is, they create a 3rd database table just to store many to many relationships.
hope it helps
//mouse.
Is it possible to include libraries/packages in only one location?
class Sample( db.Model ):
randomText = db.StringProperty( multiline = True )
--
from google.appengine.ext import db
from project.models import Sample
class SampleHandler( ):
def get( self ):
xamp = Sample.all( )
Since the handler already imports db from the google.appengine.ext library/package, and then imports the model i'd assume you don't have to include it again in the model itself. However, it looks like I have to, any way?
Anyone care to explain?
You need to import modules where they are used.
If your models module uses the google.appengine.ext.db module, you need to import it there, not in your handler module.
Importing things creates a reference to that 'thing' in your module namespace, so that the code there can find it when using it. db is the local name by which you get to use the object defined in google.appengine.ext.
If your handler uses the same object, it needs to import that still. If by importing models all names used by models suddenly where available in your handler module too, you'd end up with name conflicts and hard-to-debug errors all over the place.
Vice versa, if only importing google.appengine.ext.db in your handler module and not in your models module were to work, you'd need to import all the dependencies of given module together with the module itself. This quickly becomes unworkable, as you'd need to document all the things your models module requires just to be able to use it.
I'm working on some signal listeners, which creates records from a model. And in django docs it is said listeners should be registered in models.py. Because the listeners are quite big in lines, I would like to separate their logics from the file of models.py. Seems like it's already causing cyclic importing problems in my case. What's the best way of avoiding this problem while keeping the codes separated?
currently it's like this:
models.py
class foo(models.Model):
#model definition
import listeners
listeners.py
import models
def fun(sender,**kwargs):
bar=models.foo()
#listener logics....
from AnotherApp.models import AnotherModel
post_save.connect(fun,sender=AnotherModel)
Here is a funny hack:
from django.db.models import get_model
import models
def fun(sender,**kwargs):
# still better than doing the import in the function isn't it ...
if sender != get_model('anotherapp', 'anothermodel'):
return
bar=models.foo()
#listener logics....
post_save.connect(fun)
And this might even work but i can't say:
post_save.connect(fun, sender=get_model('anotherapp', 'anothermodel'))
BTW, there are better names than listeners: reciever is the Django-ish name, and slot is the common name.
Anyhow, I can't be more helpful because I cannot reproduce your issue with the code you pasted. Please, make sure that you pasted code that is able to reproduce your issue.