Giter Club home page Giter Club logo

aldjemy's Introduction

Aldjemy

Aldjemy Logo

Downloads License Continuous Integration results Code Coverage Downloads Code style: black

Aldjemy integrates SQLAlchemy into an existing Django project, to help you build complex queries that are difficult for the Django ORM.

While other libraries use SQLAlchemy reflection to generate SQLAlchemy models, Aldjemy generates the SQLAlchemy models by introspecting the Django models. This allows you to better control what properties in a table are being accessed.

Installation

Add aldjemy to your INSTALLED_APPS. Aldjemy will automatically add an sa attribute to all models, which is an SQLAlchemy Model.

Example:

User.sa.query().filter(User.sa.username=='Brubeck')
User.sa.query().join(User.sa.groups).filter(Group.sa.name=="GROUP_NAME")

Explicit joins are part of the SQLAlchemy philosophy, so don't expect Aldjemy to be a Django ORM drop-in replacement. Instead, you should use Aldjemy to help with special situations.

Settings

You can add your own field types to map django types to sqlalchemy ones with ALDJEMY_DATA_TYPES settings parameter. Parameter must be a dict, key is result of field.get_internal_type(), value must be a one arg function. You can get idea from aldjemy.table.

Also it is possible to extend/override list of supported SQLALCHEMY engines using ALDJEMY_ENGINES settings parameter. Parameter should be a dict, key is substring after last dot from Django database engine setting (e.g. sqlite3 from django.db.backends.sqlite3), value is SQLAlchemy driver which will be used for connection (e.g. sqlite, sqlite+pysqlite). It could be helpful if you want to use django-postgrespool.

Mixins

Often django models have helper function and properties that helps to represent the model's data (__str__), or represent some model based logic.

To integrate it with aldjemy models you can put these methods into a separate mixin:

class TaskMixin:
    def __str__(self):
        return self.code

class Task(TaskMixin, models.Model):
    aldjemy_mixin = TaskMixin
    code = models.CharField(_('code'), max_length=32, unique=True)

Voilà! You can use __str__ on aldjemy classes, because this mixin will be mixed into generated aldjemy model.

If you want to expose all methods and properties without creating a separate mixin class, you can use the aldjemy.meta.AldjemyMeta metaclass:

class Task(models.Model, metaclass=AldjemyMeta):
    code = models.CharField(_('code'), max_length=32, unique=True)

    def __str__(self):
        return self.code

The result is same as with the example above, only you didn't need to create the mixin class at all.

Release Process


  1. Make a Pull Request with updated changelog and bumped version of the project

    hatch version (major|minor|patch) # choose which version to bump
  2. Once the pull request is merged, create a github release with the same version, on the web console or with github cli.

    gh release create
  3. Enjoy!

aldjemy's People

Contributors

adamserafini avatar akheron avatar blag avatar cediddi avatar chrisjsewell avatar cyril-roques avatar danielbradburn avatar dbowring avatar deepwalker avatar dependabot[bot] avatar erikcw avatar falgore88 avatar ildus avatar kipanshi avatar ltalirz avatar lucian1900 avatar maxperreault avatar mitya57 avatar mogost avatar nvlbud avatar pnaga avatar rooterkyberian avatar ryanhiebert avatar spookylukey avatar thnee avatar ticosax avatar tim-connolly avatar vadim-pavlov avatar vmarkovtsev avatar vpotter avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

aldjemy's Issues

Scoping SQ sessions to Django requests

I'm not sure if this is the case already, but it would be good as it also would tie the SQ transaction to the request which is what seems logical to me at least.

That would also allow for logging of all SQL queries on errors with some work.

It seems like there's some support in SA for Scoped_sessions to integrate with other libraries, http://docs.sqlalchemy.org/en/rel_1_1/orm/session_basics.html http://docs.sqlalchemy.org/en/rel_1_1/orm/contextual.html#unitofwork-contextual

Support for virtual fields

Hello

Thank you for the library. It is fantastic. Django ORM is trash

One question. Is it possible to support virtual fields from this model translation library https://github.com/zostera/django-modeltrans ? This library support: Translate Django model fields in a PostgreSQL JSONField

I have this model

class SiteConfiguration(SingletonModel):

    msg = models.CharField(max_length=240,
        blank=True, default='', verbose_name='Help text',
        help_text='Help text {}')
    i18n = TranslationField(fields=("msg",))

    def __str__(self):
        return "Настройки сайта"

    class Meta:
        verbose_name = "Настройки сайта"
        verbose_name_plural = "Настройки сайта"

Currently, columns "msg" for the model isn't visible inside variable metadata.tables when calling _extract_model_attrs function inside apps\aldjemy\orm.py

The problem inside this part

    for f in model._meta.fields:
        if not isinstance(f, (ForeignKey, OneToOneField)):
            if f.model != model or f.column not in table.c:
                print(tables)
                continue  # Fields from parent model are not supported
            attrs[f.name] = orm.column_property(table.c[f.column])

I also added this one

ALDJEMY_DATA_TYPES = {
    'TranslationField':  simple(types.JSON),
}

ValueError: Couldn't parse datetime string

All I did was add aldjemy to my installed apps and then try MyModel.query().all()

Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/home/ruben/v3env/lib/python3.4/site-packages/sqlalchemy/orm/query.py", line 2399, in all
    return list(self)
  File "/home/ruben/v3env/lib/python3.4/site-packages/sqlalchemy/orm/loading.py", line 86, in instances
    util.raise_from_cause(err)
  File "/home/ruben/v3env/lib/python3.4/site-packages/sqlalchemy/util/compat.py", line 188, in raise_from_cause
    reraise(type(exception), exception, tb=exc_tb, cause=exc_value)
  File "/home/ruben/v3env/lib/python3.4/site-packages/sqlalchemy/util/compat.py", line 182, in reraise
    raise value
  File "/home/ruben/v3env/lib/python3.4/site-packages/sqlalchemy/orm/loading.py", line 71, in instances
    rows = [proc(row) for row in fetch]
  File "/home/ruben/v3env/lib/python3.4/site-packages/sqlalchemy/orm/loading.py", line 71, in <listcomp>
    rows = [proc(row) for row in fetch]
  File "/home/ruben/v3env/lib/python3.4/site-packages/sqlalchemy/orm/loading.py", line 428, in _instance
    loaded_instance, populate_existing, populators)
  File "/home/ruben/v3env/lib/python3.4/site-packages/sqlalchemy/orm/loading.py", line 486, in _populate_full
    dict_[key] = getter(row)
ValueError: Couldn't parse datetime string 'b'2015-07-15 11:07:40.037679'' - value is not a string.

Django 1.5 get_user_model() breaks aldjemy.

If you use Django 1.5's get_user_model function instead of importing the User class, aldjemy won't add the sa attribute to any models in that module (or modules that are setup after it).

For example:

# Django 1.5 style doesn't work
from django.contrib.auth import get_user_model
User = get_user_model()

Results in:

In [1]: Campaign.sa
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-1-8cad6f5ea5c2> in <module>()
----> 1 Campaign.sa

AttributeError: type object 'Campaign' has no attribute 'sa'

instead of:

# Pre-Django 1.5 style does work.
from django.contrib.auth.models import User

This of course breaks Django 1.5's custom User model implementation. This effects you even if you aren't using a custom model, since many 3rd party apps are switching to get_user_model() for compatibility reasons.

get_tables()

not return JSON FIELDS in django == 2.0 :/ how I can do to add my json fields

AttributeError: 'ForeignKey' object has no attribute 'related' (using string for model reference)

aldjemy throws a traceback when any ForeignKey field references its related model using a string instead of the Class directly.

This is an important and useful feature for handling circular imports, and should be supported.

For example:

This works:

from zebra.models import Customer
class UserProfile(models.Model):
    ...
    stripe_customer = models.ForeignKey(Customer)

This does not:

class UserProfile(models.Model):
    ...
    stripe_customer = models.ForeignKey('zebra.models.Customer')

Here is the traceback:

Traceback (most recent call last):
  File "/Users/e/.virtualenvs/cc/lib/python2.7/site-packages/django/core/management/commands/runserver.py", line 91, in inner_run
    self.validate(display_num_errors=True)
  File "/Users/e/.virtualenvs/cc/lib/python2.7/site-packages/django/core/management/base.py", line 266, in validate
    num_errors = get_validation_errors(s, app)
  File "/Users/e/.virtualenvs/cc/lib/python2.7/site-packages/django/core/management/validation.py", line 30, in get_validation_errors
    for (app_name, error) in get_app_errors().items():
  File "/Users/e/.virtualenvs/cc/lib/python2.7/site-packages/django/db/models/loading.py", line 158, in get_app_errors
    self._populate()
  File "/Users/e/.virtualenvs/cc/lib/python2.7/site-packages/django/db/models/loading.py", line 64, in _populate
    self.load_app(app_name, True)
  File "/Users/e/.virtualenvs/cc/lib/python2.7/site-packages/django/db/models/loading.py", line 88, in load_app
    models = import_module('.models', app_name)
  File "/Users/e/.virtualenvs/cc/lib/python2.7/site-packages/django/utils/importlib.py", line 35, in import_module
    __import__(name)
  File "/Users/e/.virtualenvs/cc/lib/python2.7/site-packages/aldjemy/models.py", line 4, in <module>
    prepare_models()
  File "/Users/e/.virtualenvs/cc/lib/python2.7/site-packages/aldjemy/orm.py", line 75, in prepare_models
    tables = get_tables()
  File "/Users/e/.virtualenvs/cc/lib/python2.7/site-packages/aldjemy/core.py", line 60, in get_tables
    generate_tables(get_meta())
  File "/Users/e/.virtualenvs/cc/lib/python2.7/site-packages/aldjemy/table.py", line 65, in generate_tables
    typ = DATA_TYPES[field.get_internal_type()](field)
  File "/Users/e/.virtualenvs/cc/lib/python2.7/site-packages/aldjemy/types.py", line 15, in foreign_key
    target = field.related.parent_model._meta
AttributeError: 'ForeignKey' object has no attribute 'related'

Mapper could not assemble any primary key columns for mapped table

I have a model with one primary key (UUIDField) and I've also set 'unique_together' on four fields. The sqlalchemy mapper can't find the mapping, apparently. I'm using aldjemy v0.6.0.

sqlalchemy.exc.ArgumentError: Mapper Mapper|MyModel|model_db_table could not assemble any primary key columns for mapped table 'model_db_table'

Parser generator

Hey is this project kind of like sql parser generator?
like it parses the sql query and return an expression and does the code generation from it

i saw the python syntax, in the readme, how do i execute this project? Do i execute the test.sh file?

raise AttributeError like #15

'_ConnectionRecord' object has no attribute 'starttime'

some traceback maybe useful

sqlalchemy/engine/base.py in _execute_context
                        context)
        except Exception as e:
            self._handle_dbapi_exception(
                e,
                statement,
                parameters,
                cursor,
                context) ...
        if self._has_events or self.engine._has_events:
            self.dispatch.after_cursor_execute(self, cursor,
                                               statement,
                                               parameters,
                                               context,

dialect <sqlalchemy.dialects.mysql.mysqldb.MySQLDialect_mysqldb object at 0x3809e50>
e   InterfaceError(0, '')

InterfaceError is the deeper exception

AttributeError: type object `MODEL NAME` has no attribute 'sa'

Cant know what happened the project worked fine till Saturday(24-02-2018) then all the projects with sql alchemy gives me this error of saying no attribute 'sa'

code that i had used is
`
from user_profile.models import UserModel,UserSalary
from sqlalchemy.orm.session import sessionmaker
from sqlalchemy.orm import mapper, aliased
from sqlalchemy import and_,func ,cast,Date
from sqlalchemy.sql.expression import literal,union_all
import aldjemy

UserModelSA = UserModel.sa
UserSalarySA = UserSalary.sa
PayrollSA = Payroll.sa

`

Mapper error when db_column == attname on a Model subclass

sqlalchemy.exc.ArgumentError: WARNING: when configuring property 'subject' on mapped
class User->usersubjects, column 'subject' conflicts with property '<RelationshipProperty at 0x104453c48; subject>'.
To resolve this, map the column to the class under a different name in the 'properties' dictionary.
Or, to remove all awareness of the column entirely (including its availability as a foreign key),
use the 'include_properties' or 'exclude_properties' mapper arguments to control specifically
which table columns get mapped.

This was on a model (User) where the parent link field to the parent model Subject was declared as an attribute subject and instantiated with the argument db_column='subject'. Source example will follow.

Support for custom Query classes via query_cls and query_class

It would be nice with some built in support for this, to be able to better organize chunks of query parts.

It seems like it has to be specified on both the session, and on relations in models.
https://stackoverflow.com/a/15962062/399725

Flask-sqlalchemy has some nice inspiration too.
https://flask-sqlalchemy.palletsprojects.com/en/2.x/customizing/#query-class

Aldjemy could automate this by reading an aldjemy_query_class attribute from the Django model and apply it to the auto generated sa models. It could also traverse relationships during initialization to find out each target model's query class and apply it to relation fields.

What are your thoughts on this? Does it make sense? Did I miss anything obvious?

Configure custom sqlalchemy custom deserializer

#74
I'm using postgres array of json elements. The default deserializer in sqlalchemy is expecting serialized JSON. However, the sqlalchemy core is already parsing it to the dict object and hence the default deserializer is failing. Hence, we need the ability to provide custom deserializer to bypass this.

In the get_engine() api, the custom decode function can passed in through the kwargs passed to the create_engine. Also, the custom deserializer can be used in several occasions where the app developer will require parsing the JSON object to a different structure as per their requirements.

Please consider adding a license file

Hi, I am in the process of adding a recipe for aldjemy on conda forge and I have been asked by the conda forge maintainers to raise an issue here, asking whether it would be possible to add a license file and include it in the MANIFEST.in?

P.S. If you would like me to add your github handle to the list of maintainers of the conda recipe (which otherwise would be just me), please let me know.

JSONField supporting had broken in v0.9.0

Hi!
I'm using JSONField from django.contrib.postgres.fields and everything was OK in aldjemy 0.8.0 but in 0.9.0 i see next error:

  File "***/backend/manage.py", line 12, in <module>
    configurations.setup()
  File "***/backend/venv/lib/python3.6/site-packages/configurations/__init__.py", line 29, in setup
    _setup()
  File "***/backend/venv/lib/python3.6/site-packages/configurations/__init__.py", line 15, in _setup
    django.setup()
  File "***/backend/venv/lib/python3.6/site-packages/django/__init__.py", line 24, in setup
    apps.populate(settings.INSTALLED_APPS)
  File "***/backend/venv/lib/python3.6/site-packages/django/apps/registry.py", line 120, in populate
    app_config.ready()
  File "***/backend/venv/lib/python3.6/site-packages/aldjemy/apps.py", line 17, in ready
    prepare_models()
  File "***/backend/venv/lib/python3.6/site-packages/aldjemy/orm.py", line 129, in prepare_models
    Cache.sa_models = construct_models(metadata)
  File "***/backend/venv/lib/python3.6/site-packages/aldjemy/orm.py", line 174, in construct_models
    metadata, model, sa_models_by_django_models)
  File "***/backend/venv/lib/python3.6/site-packages/aldjemy/orm.py", line 54, in _extract_model_attrs
    attrs[f.name] = orm.column_property(table.c[f.column])
  File "***/backend/venv/lib/python3.6/site-packages/sqlalchemy/util/_collections.py", line 194, in __getitem__
    return self._data[key]
KeyError: 'trigger_data'

Where trigger_data = JSONField()

ArrayField of Postgres processed incorrectly

I've found that ArrayField of Postgres is processed incorrectly, which actually does not allow to fetch Array Fields not via ORM, nor SQL Expression Language.
Currently existing tests does not cover this case as they are not fetching not object, not list of values from the table

Tested with:
Python==3.7.5
Django==2.2.5
djangorestframework==3.10.3
aldjemy==0.10.1
sqlalchemy==1.3.16
psycopg2==2.8.3
Postgres==10.5

Looks like here (aldjemy/postgres.py line 16):

    # currently no support for multi-dimensional arrays
    if internal_type in data_types and internal_type != 'ArrayField':
        sub_type = data_types[internal_type](field)
        if not isinstance(sub_type, (list, tuple)):
            sub_type = [sub_type]
    else:
        raise RuntimeError('Unsupported array element type')

author of ArrayField processing copy-pasted similar process from the upper level (aldjemy/table.py line 102):

                if internal_type in DATA_TYPES and hasattr(field, 'column'):
                    typ = DATA_TYPES[internal_type](field)
                    if not isinstance(typ, (list, tuple)):
                        typ = [typ]
                    columns.append(Column(field.column,
                            *typ, primary_key=field.primary_key))

but there is no need to put single field in a list. It will not be unpacked anywhere.

I.e. there is no need in aldjemy/postgres.py to do the following:

        if not isinstance(sub_type, (list, tuple)):
            sub_type = [sub_type]    

Since it will produce not the SA Column instance, but python list in the attribute of SA Table instance.
Screenshot_1
Screenshot_2

This will lead to attempt to call method dialect_impl from list instance during fetching, when SQLAlchemy awaits here Column instance.

Internal Server Error: /api/aldjemy-test/
Traceback (most recent call last):
  File "/home/sosam/PycharmProjects/aldjemy-test/venv/lib/python3.7/site-packages/django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
  File "/home/sosam/PycharmProjects/aldjemy-test/venv/lib/python3.7/site-packages/django/core/handlers/base.py", line 115, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/home/sosam/PycharmProjects/aldjemy-test/venv/lib/python3.7/site-packages/django/core/handlers/base.py", line 113, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/sosam/PycharmProjects/aldjemy-test/venv/lib/python3.7/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)
  File "/home/sosam/PycharmProjects/aldjemy-test/venv/lib/python3.7/site-packages/django/views/generic/base.py", line 71, in view
    return self.dispatch(request, *args, **kwargs)
  File "/home/sosam/PycharmProjects/aldjemy-test/venv/lib/python3.7/site-packages/rest_framework/views.py", line 505, in dispatch
    response = self.handle_exception(exc)
  File "/home/sosam/PycharmProjects/aldjemy-test/venv/lib/python3.7/site-packages/rest_framework/views.py", line 465, in handle_exception
    self.raise_uncaught_exception(exc)
  File "/home/sosam/PycharmProjects/aldjemy-test/venv/lib/python3.7/site-packages/rest_framework/views.py", line 476, in raise_uncaught_exception
    raise exc
  File "/home/sosam/PycharmProjects/aldjemy-test/venv/lib/python3.7/site-packages/rest_framework/views.py", line 502, in dispatch
    response = handler(request, *args, **kwargs)
  File "/home/sosam/PycharmProjects/aldjemy-test/flow/views.py", line 2956, in get
    sa1 = AlchemyTest.sa.query().all()
  File "/home/sosam/PycharmProjects/aldjemy-test/venv/lib/python3.7/site-packages/sqlalchemy/orm/query.py", line 3246, in all
    return list(self)
  File "/home/sosam/PycharmProjects/aldjemy-test/venv/lib/python3.7/site-packages/sqlalchemy/orm/query.py", line 3405, in __iter__
    return self._execute_and_instances(context)
  File "/home/sosam/PycharmProjects/aldjemy-test/venv/lib/python3.7/site-packages/sqlalchemy/orm/query.py", line 3430, in _execute_and_instances
    result = conn.execute(querycontext.statement, self._params)
  File "/home/sosam/PycharmProjects/aldjemy-test/venv/lib/python3.7/site-packages/sqlalchemy/engine/base.py", line 984, in execute
    return meth(self, multiparams, params)
  File "/home/sosam/PycharmProjects/aldjemy-test/venv/lib/python3.7/site-packages/sqlalchemy/sql/elements.py", line 293, in _execute_on_connection
    return connection._execute_clauseelement(self, multiparams, params)
  File "/home/sosam/PycharmProjects/aldjemy-test/venv/lib/python3.7/site-packages/sqlalchemy/engine/base.py", line 1103, in _execute_clauseelement
    distilled_params,
  File "/home/sosam/PycharmProjects/aldjemy-test/venv/lib/python3.7/site-packages/sqlalchemy/engine/base.py", line 1288, in _execute_context
    e, statement, parameters, cursor, context
  File "/home/sosam/PycharmProjects/aldjemy-test/venv/lib/python3.7/site-packages/sqlalchemy/engine/base.py", line 1485, in _handle_dbapi_exception
    util.raise_(exc_info[1], with_traceback=exc_info[2])
  File "/home/sosam/PycharmProjects/aldjemy-test/venv/lib/python3.7/site-packages/sqlalchemy/util/compat.py", line 178, in raise_
    raise exception
  File "/home/sosam/PycharmProjects/aldjemy-test/venv/lib/python3.7/site-packages/sqlalchemy/engine/base.py", line 1267, in _execute_context
    result = context.get_result_proxy()
  File "/home/sosam/PycharmProjects/aldjemy-test/venv/lib/python3.7/site-packages/sqlalchemy/dialects/postgresql/psycopg2.py", line 585, in get_result_proxy
    return _result.ResultProxy(self)
  File "/home/sosam/PycharmProjects/aldjemy-test/venv/lib/python3.7/site-packages/sqlalchemy/engine/result.py", line 775, in __init__
    self._init_metadata()
  File "/home/sosam/PycharmProjects/aldjemy-test/venv/lib/python3.7/site-packages/sqlalchemy/engine/result.py", line 807, in _init_metadata
    self._metadata = ResultMetaData(self, cursor_description)
  File "/home/sosam/PycharmProjects/aldjemy-test/venv/lib/python3.7/site-packages/sqlalchemy/engine/result.py", line 296, in __init__
    textual_ordered,
  File "/home/sosam/PycharmProjects/aldjemy-test/venv/lib/python3.7/site-packages/sqlalchemy/engine/result.py", line 474, in _merge_cursor_description
    for idx, (key, name, obj, type_) in enumerate(result_columns)
  File "/home/sosam/PycharmProjects/aldjemy-test/venv/lib/python3.7/site-packages/sqlalchemy/engine/result.py", line 474, in <listcomp>
    for idx, (key, name, obj, type_) in enumerate(result_columns)
  File "/home/sosam/PycharmProjects/aldjemy-test/venv/lib/python3.7/site-packages/sqlalchemy/engine/default.py", line 1178, in get_result_processor
    return type_._cached_result_processor(self.dialect, coltype)
  File "/home/sosam/PycharmProjects/aldjemy-test/venv/lib/python3.7/site-packages/sqlalchemy/sql/type_api.py", line 512, in _cached_result_processor
    d[coltype] = rp = d["impl"].result_processor(dialect, coltype)
  File "/home/sosam/PycharmProjects/aldjemy-test/venv/lib/python3.7/site-packages/sqlalchemy/dialects/postgresql/array.py", line 333, in result_processor
    item_proc = self.item_type.dialect_impl(dialect).result_processor(
AttributeError: 'list' object has no attribute 'dialect_impl'

Removal of those two lines of code fixed the issue. I've checked it with ORM and SQL Expression Language.
Walked through with debugger and compared the resulting column type. It's the same as of Table build with declarative_base.

Resulting column data types are valid:
Screenshot_3
Screenshot_4

I can make it a PR with few additional tests.

Project Status

Hi
This project looks super useful. Before we dive in, is anyone using this in production ? Are their any limitations on the SQA side we should be aware of ?
Thanks

Can't cache/pickle aldjemy objects

When attempting to cache an aldjemy object, Django/tastypie throws the following traceback:

Traceback (most recent call last): 
  File "/app/.heroku/python/lib/python2.7/site-packages/tastypie/resources.py", line 202, in wrapper 
    response = callback(request, *args, **kwargs) 
  File "/app/.heroku/python/lib/python2.7/site-packages/tastypie/resources.py", line 449, in dispatch_detail 
    return self.dispatch('detail', request, **kwargs) 
  File "/app/api/resources.py", line 54, in dispatch 
    return super(BasePortalResource, self).dispatch(request_type, request, **kwargs) 
  File "/app/.heroku/python/lib/python2.7/site-packages/tastypie/resources.py", line 472, in dispatch 
    response = method(request, **kwargs) 
  File "/app/.heroku/python/lib/python2.7/site-packages/tastypie/resources.py", line 1303, in get_detail 
    obj = self.cached_obj_get(bundle=basic_bundle, **self.remove_api_resource_names(kwargs)) 
  File "/app/.heroku/python/lib/python2.7/site-packages/tastypie/resources.py", line 1122, in cached_obj_get 
    self._meta.cache.set(cache_key, cached_bundle) 
  File "/app/.heroku/python/lib/python2.7/site-packages/tastypie/cache.py", line 81, in set 
    cache.set(key, value, timeout) 
  File "/app/.heroku/python/lib/python2.7/site-packages/django_pylibmc/memcached.py", line 106, in set 
    MIN_COMPRESS) 
  File "/app/.heroku/python/lib/python2.7/site-packages/newrelic-1.11.0.55/newrelic/api/memcache_trace.py", line 73, in __call__ 
    return self._nr_next_object(*args, **kwargs) 
PicklingError: Can't pickle <class 'aldjemy.orm.Campaign'>: attribute lookup aldjemy.orm.Campaign failed

Django 1.5.1
Tastypie 0.9.14
Aldjemy 0.3.8

Jazzband

Dear maintainers, have you considered moving this project under the jazzband organization ?

https://jazzband.co/

I could, then, cut a release and maintain the project for tasks I feel comfortable with, like make it work along new django releases as they are published.

Automate deployment

I have an API token for PyPI that will work for uploading. I just need to get it automated. I'd like it to upload automatically when a new git tag is created.

Django TimeField gives 'datetime.time' object has no attribute 'microseconds' when querying its model's 'sa' attribute

Steps to reproduce

  1. Python 2.7.6, pip==9.0.1, Django==1.10.5, MySQL-python==1.2.5, aldjemy==0.6.0
  2. Create a model with TimeField
  3. Do necessary migrations
  4. Create an object of the models using django's "objects.create()". You can give either a string or a datetime.time or datetime.datetime instance for the field.
  5. Create a session using aldjemy.core.get_engine()
  6. session.query(<model name>.sa).all() or <model name>.sa.query().all() gives the error
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "~/.virtualenvs/test/local/lib/python2.7/site-packages/sqlalchemy/orm/query.py", line 2638, in all
    return list(self)
  File "~/.virtualenvs/test/local/lib/python2.7/site-packages/sqlalchemy/orm/loading.py", line 90, in instances
    util.raise_from_cause(err)
  File "~/.virtualenvs/test/local/lib/python2.7/site-packages/sqlalchemy/util/compat.py", line 203, in raise_from_cause
    reraise(type(exception), exception, tb=exc_tb, cause=cause)
  File "~/.virtualenvs/test/local/lib/python2.7/site-packages/sqlalchemy/orm/loading.py", line 75, in instances
    rows = [proc(row) for row in fetch]
  File "~/.virtualenvs/test/local/lib/python2.7/site-packages/sqlalchemy/orm/loading.py", line 437, in _instance
    loaded_instance, populate_existing, populators)
  File "~/.virtualenvs/test/local/lib/python2.7/site-packages/sqlalchemy/orm/loading.py", line 498, in _populate_full
    dict_[key] = getter(row)
  File "~/.virtualenvs/test/local/lib/python2.7/site-packages/sqlalchemy/dialects/mysql/types.py", line 413, in process
    microseconds = value.microseconds
AttributeError: 'datetime.time' object has no attribute 'microseconds'

Can't disable backref generation

Currently it is not possible to disable backref generation for SQLAlchemy model. It makes impossible to inherit model with two ForeignKey to same model.

Example:

class A(models.Model):
    ...

class B(models.Model):
    field1 = models.ForeignKey(A, related_name='+')
    field2 = models.ForeignKey(A, related_name='+')
    class Meta:
        abstract = True

class BA(B):
    ...

class BB(B):
    ...

It is not possible to make this models work in any way and will always result in:
InvalidRequestError: One or more mappers failed to initialize - can't proceed with initialization of other mappers. Original exception was: Error creating backref 'ba_set' on relationship 'BA.field1': property of that name exists on mapper 'Mapper|A|app_a'

If related_name is set to '+' aldjemy shouldn't generate backref as Django does.

tests on conda-forge failing with django 2.2

The tests for the aldjemy conda-forge feedstock are currently failing with django 2.2, error message:

django.db.utils.OperationalError: no such table: django_content_type

link to build log

For the moment, I limited the django version to <2.2 (as tested also in the CI of this repo), which fixes the tests.

Give that django 3 is already out, this is an important limitation that would be great to either fix or communicate somewhere in the README.

Connection closed exception

Traceback (most recent call last):
  File "/Users/erik/Dropbox/home/git/proj/api/tests/test_user.py", line 211, in test_post_list_bgt_validation
    resp = self.api_client.post(self.list_url, format='json', data=self.post_data, HTTP_AUTHORIZATION=self.get_credentials())
  File "/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/rest_framework/test.py", line 90, in post
    return self.generic('POST', path, data, content_type, **extra)
  File "/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/rest_framework/compat.py", line 150, in generic
    return self.request(**r)
  File "/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/rest_framework/test.py", line 157, in request
    return super(APIClient, self).request(**kwargs)
  File "/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/rest_framework/test.py", line 109, in request
    request = super(APIRequestFactory, self).request(**kwargs)
  File "/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/django/test/client.py", line 440, in request
    six.reraise(*exc_info)
  File "/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/django/core/handlers/base.py", line 111, in get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/django/views/decorators/csrf.py", line 57, in wrapped_view
    return view_func(*args, **kwargs)
  File "/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/rest_framework/viewsets.py", line 79, in view
    return self.dispatch(request, *args, **kwargs)
  File "/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/rest_framework/views.py", line 403, in dispatch
    response = self.handle_exception(exc)
  File "/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/rest_framework/views.py", line 400, in dispatch
    response = handler(request, *args, **kwargs)
  File "/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/rest_framework/mixins.py", line 52, in create
    if serializer.is_valid():
  File "/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/rest_framework/serializers.py", line 550, in is_valid
    return not self.errors
  File "/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/rest_framework/serializers.py", line 542, in errors
    ret = self.from_native(data, files)
  File "/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/rest_framework/serializers.py", line 1021, in from_native
    instance = super(ModelSerializer, self).from_native(data, files)
  File "/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/rest_framework/serializers.py", line 370, in from_native
    attrs = self.perform_validation(attrs)
  File "/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/rest_framework/serializers.py", line 303, in perform_validation
    attrs = validate_method(attrs, source)
  File "/Users/erik/Dropbox/home/git/proj/api/serializers.py", line 267, in validate_bgt
    portal.validators.validate_user_bgt(bgt, margin, attrs['user'], self.object)
  File "/Users/erik/Dropbox/home/git/proj/portal/validators.py", line 35, in validate_user_bgt
    net_expsr = LedgerAccount.objects.calculate_user_net_expsr(user, instance_pk_list, adjusted_new_bgt or decimal.Decimal('0'))
  File "/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/django/db/models/manager.py", line 92, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/Users/erik/Dropbox/home/git/proj/portal/managers.py", line 997, in calculate_user_net_expsr
    gross_expsr = gross_expsr.scalar() or decimal.Decimal(0)
  File "/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/sqlalchemy/orm/query.py", line 2429, in scalar
    ret = self.one()
  File "/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/sqlalchemy/orm/query.py", line 2398, in one
    ret = list(self)
  File "/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/sqlalchemy/orm/query.py", line 2441, in __iter__
    return self._execute_and_instances(context)
  File "/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/sqlalchemy/orm/query.py", line 2456, in _execute_and_instances
    result = conn.execute(querycontext.statement, self._params)
  File "/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 841, in execute
    return meth(self, multiparams, params)
  File "/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/sqlalchemy/sql/elements.py", line 322, in _execute_on_connection
    return connection._execute_clauseelement(self, multiparams, params)
  File "/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 938, in _execute_clauseelement
    compiled_sql, distilled_params
  File "/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1005, in _execute_context
    None, None)
  File "/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1271, in _handle_dbapi_exception
    exc_info
  File "/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/sqlalchemy/util/compat.py", line 199, in raise_from_cause
    reraise(type(exception), exception, tb=exc_tb)
  File "/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1001, in _execute_context
    context = constructor(dialect, self, conn, *args)
  File "/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/sqlalchemy/engine/default.py", line 561, in _init_compiled
    self.cursor = self.create_cursor()
  File "/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/sqlalchemy/dialects/postgresql/psycopg2.py", line 442, in create_cursor
    return self._dbapi_connection.cursor()
  File "/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/sqlalchemy/pool.py", line 770, in cursor
    return self.connection.cursor(*args, **kwargs)
  File "/Users/erik/Dropbox/home/git/aldjemy/aldjemy/wrapper.py", line 23, in __call__
    self.obj = self.obj(*a, **kw)
InterfaceError: (InterfaceError) connection already closed u'SELECT sum(portal_user.bgt - portal_user.bgt * (portal_user.margin / %(margin_1)s)) AS sum_1 \nFROM portal_user \nWHERE portal_user.status = %(status_1)s AND portal_user.user_id = %(user_id_1)s' [immutabledict({})]

----------------------------------------------------------------------
Ran 17 tests in 13.537s

FAILED (errors=1)

Django 1.7.8
aldjemy 0.4.1
sqlalchemy 0.9.9 (also tested 1.0.0 and 1.0.6).
psycopg2 2.6.1
Postgres 9.4

unicode issue?

Hi there! I think there's an issue with TextFields and unicode data.

Lets say i have a model

class M(models.Model):
    a = models.CharField(max_length="200")
    b = models.TextField()

and make a model instance:

>>> M.objects.create(a=u"aaaa", b=u"ń") # polish sign ("n" with a comma above)
>>> M.sa.query().all()

I get an error

Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "/home/slafs/.virtualenvs/venv/local/lib/python2.7/site-packages/sqlalchemy/orm/query.py", line 1983, in all
    return list(self)
  File "/home/slafs/.virtualenvs/venv/local/lib/python2.7/site-packages/sqlalchemy/orm/query.py", line 2214, in instances
    rows = [process[0](row, None) for row in fetch]
  File "/home/slafs/.virtualenvs/venv/local/lib/python2.7/site-packages/sqlalchemy/orm/mapper.py", line 2718, in _instance
    populate_state(state, dict_, row, isnew, only_load_props)
  File "/home/slafs/.virtualenvs/venv/local/lib/python2.7/site-packages/sqlalchemy/orm/mapper.py", line 2572, in populate_state
    populator(state, dict_, row)
  File "/home/slafs/.virtualenvs/venv/local/lib/python2.7/site-packages/sqlalchemy/orm/strategies.py", line 150, in fetch_col
    dict_[key] = row[col]
UnicodeEncodeError: 'ascii' codec can't encode character u'\u0144' in position 0: ordinal not in range(128)

Just starting with SQLAlchemy so don't have a clue what's the deal with this for now. Test it with postgres and sqlite

Issue with mapping when using UUID fields

I have a Django 1.9 model called Property (I know it clashes with the Python keyword property, but it doesn't effect the issue I'm having).

When I put aldjemy in Django's app list and tried to open up the Django shell, I got this stack trace:

$ ./bin/manage shell_plus
Traceback (most recent call last):
  File "/app/manage.py", line 10, in <module>
    execute_from_command_line(sys.argv)
  File "/usr/local/lib/python3.5/site-packages/django/core/management/__init__.py", line 353, in execute_from_command_line
    utility.execute()
  File "/usr/local/lib/python3.5/site-packages/django/core/management/__init__.py", line 327, in execute
    django.setup()
  File "/usr/local/lib/python3.5/site-packages/django/__init__.py", line 18, in setup
    apps.populate(settings.INSTALLED_APPS)
  File "/usr/local/lib/python3.5/site-packages/django/apps/registry.py", line 115, in populate
    app_config.ready()
  File "/usr/local/lib/python3.5/site-packages/aldjemy/apps.py", line 17, in ready
    prepare_models()
  File "/usr/local/lib/python3.5/site-packages/aldjemy/orm.py", line 114, in prepare_models
    orm.mapper(sa_models[name], table, attrs)
  File "<string>", line 2, in mapper
  File "/usr/local/lib/python3.5/site-packages/sqlalchemy/orm/mapper.py", line 629, in __init__
    self._configure_pks()
  File "/usr/local/lib/python3.5/site-packages/sqlalchemy/orm/mapper.py", line 1223, in _configure_pks
    (self, self.mapped_table.description))
sqlalchemy.exc.ArgumentError: Mapper Mapper|Property|core_property could not assemble any primary key columns for mapped table 'core_property'

core is our Django application name and core_property is the table of the model in question.

I believe this UUID field is causing the issue:

id = models.UUIDField(primary_key=True, default=uuid.uuid4)

Commenting this line allows the shell to load successfully.

So is there something about UUID fields or non-auto primary key fields that would make aldjemy error out this way?

Is there anything we can do besides not use a UUID primary key field?

Thanks!

UUID Primary keys

By default, Django's models have an AutoField primary key, which is an integer. For some of my models, I have overwritten the default primary key and made it a UUIDField. I'd like to use aldjemy, but it doesn't support this case yet.

I don't know when I'll get to fixing it, though I do expect it will happen some time, but I wanted to bring it up in case there is some discussion needed to be had around it, or in case I get lucky and someone just needed to know about the problem in order to have the time to fix it sooner ;-)

Accessing db.session from Django app

Hi, I am trying to query a subquery in Django, and in my Flask app I used to query like this:

db.session.query(some_subquery)

How can I access session instance or alternatively how can I do the same query from Model?

I have tried this:

some_subquery.sa.query()
and
some_subquery.query()

Both throwing an exception of attribute/method does not exist.

Please help.

Providing access to SQLAlchemy's create_engine creator parameter

Hi there,
i am using SQLAlchemy, Django and Aldjemy and would like to port some functionality across:

In my traditional application I call
engine = create_engine("[db1 url]", echo=False, creator=source_connect_helper)

where

def source_connect_helper():
    conn = sqlite.connect('[db1 path]')
    conn.execute("ATTACH DATABASE '[db2path]' AS source")
    return conn

This allows me to do cross database queries with sqlalchemy. How can I achieve the same thing with adjemy?

Maintainers

Hi @Deepwalker ! @Mogost and I are interested in helping maintain this package. What I'm thinking would be best, if you're amiable to the idea, would be to make a shared organization for the project. I've gone ahead and done that, and I've invited you to be a part of that organization. In return, I'm committing to shepherd the process to get things set up and smoothed out over at that new location, and watch the repository for feedback and issues.

If that sounds like a good approach to you, can you move this repository over to the aldjemy organization (so that we can keep the issues that are already here), and give me (ryanhiebert) permissions on the package at PyPI (so that I can make releases)?

If you would prefer not do that, and that is perfectly alright as far as I'm concerned, then @Mogost and I are likely to release a similar package under a different name, but using a shared organization like I've suggested here. We'd rather keep the aldjemy name going if we had our preference, but we understand if you prefer not.

Use poetry

I'd like to switch this project to use poetry, rather than setuptools.

DurationField not supported.

Django 1.8 added a new DurationField. I am about to create a pull request with the new data type in the DATA_TYPES dictionary.

DjangoPool raise Type Error:__init__() got multiple values for keyword argument 'alias'

__init__() got multiple values for keyword argument 'alias'

https://github.com/Deepwalker/aldjemy/blob/master/aldjemy%2Fcore.py#L86

code:

class DjangoPool(NullPool):
    def __init__(self, alias, *args, **kwargs):
        super(DjangoPool, self).__init__(*args, **kwargs)
        self.alias = alias

    def status(self):
        return "DjangoPool"

    def _create_connection(self):
        return _ConnectionRecord(self, self.alias)

    def recreate(self):
        self.logger.info("Pool recreating")

        return DjangoPool(self._creator,
            recycle=self._recycle,
            alias=self.alias,
            echo=self.echo,
            logging_name=self._orig_logging_name,
            use_threadlocal=self._use_threadlocal)

you write in init accept alias argument,and you send two alias argument in recreate func ,one is self._creator,other one is alias=self.alias

generate tables on custom metadata

I'm loving aldjemy, and I came up with a new interesting use case. I'm using PostgreSQL foreign data wrappers to copy loads of data from one django instance to another. To do this transfer, I need to copy between tables in different schemas. I can write these queries using SQLAlchemy, so that's what I want to do.

To that end, I want to make a custom schema, and then run aldjemy.core.prepare_models on it. Unfortunately, Aldjemy is pretty deeply tied to it's internal cache of the default, schema-free metadata.

I've figured out the changes needed for this, and I am using this code and it seems to be working. Since Django doesn't usually ever deal with schemas, a multiple-schema use-case, I wasn't sure if making Aldjemy internals more amenable to my use case would be something you'd be interested in having me contribute. If it would, I'd be happy to do just that. I've already got it working, I'd just need to work it into a pull request.

There are three functions that I've found need to be touched:

  • aldjemy.core.prepare_models needs to allow passing in a custom metadata instance, and using that to do the generation.
  • aldjemy.table.generate_tables needs to handle the case of the metadata having a schema when checking if the table exists.
  • aldjemy.orm._extract_model_attrs needs to support passing in a custom metadata, using that to get the tables, and use the metadata's schema when looking up the table.

All in all, pretty minor changes, but I'm not sure if cleaning things up to make that easy for me is something you think would be worthwhile to entertain a pull request for.

Django 1.10 Deprecation Warning: `get_fields_with_model`

env/lib/python3.5/site-packages/aldjemy/table.py:69: RemovedInDjango110Warning: 'get_fields_with_model is an unofficial API that has been deprecated. 
You may be able to replace it with 'get_fields()'
  for field, parent_model in model._meta.get_fields_with_model():

Поддержка multiple databases от django

Здравствуйте. В orm.py есть такой код:

def new_session(**kw):
    get_session()
signals.request_started.connect(new_session)

Не лучше будет ли его поменять на сигнал django.db.backends.signals.connection_created?

Это связано с тем что я хочу добавить поддержку алиасов для get_engine и get_session, но в обработчике request_started нельзя узнать текущее соединение.
Выглядеть будет как то так:

def get_session(alias='default'):
    connection = connections[alias]
    if not hasattr(connection, 'sa_session'):
        session = orm.create_session()
        session.bind = get_engine(alias)
        connection.sa_session = session
    return connection.sa_session


def new_session(sender, connection, **kw):
    get_session(alias=connection.alias)
connection_created.connect(new_session)

Exception when used with SQLAlchemy 0.9.4

I'm trying to use aldjemy with SQLAlchemy 0.9.4. When I try a simple query, I get this traceback:

from django.contrib.auth.models import User
User.sa.query(User.sa).count()

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-1-01a7a3ebfca2> in <module>()
----> 1 User.sa.query(User.sa).count()

/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/sqlalchemy/orm/query.pyc in count(self)
   2591         """
   2592         col = sql.func.count(sql.literal_column('*'))
-> 2593         return self.from_self(col).scalar()
   2594 
   2595     def delete(self, synchronize_session='evaluate'):

/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/sqlalchemy/orm/query.pyc in scalar(self)
   2390         """
   2391         try:
-> 2392             ret = self.one()
   2393             if not isinstance(ret, tuple):
   2394                 return ret

/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/sqlalchemy/orm/query.pyc in one(self)
   2359 
   2360         """
-> 2361         ret = list(self)
   2362 
   2363         l = len(ret)

/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/sqlalchemy/orm/loading.pyc in instances(query, cursor, context)
     63                 break
     64         else:
---> 65             fetch = cursor.fetchall()
     66 
     67         if custom_rows:

/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/sqlalchemy/engine/result.pyc in fetchall(self)
    786             self.connection._handle_dbapi_exception(
    787                                     e, None, None,
--> 788                                     self.cursor, self.context)
    789 
    790     def fetchmany(self, size=None):

/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/sqlalchemy/engine/base.pyc in _handle_dbapi_exception(self, e, statement, parameters, cursor, context)
   1109                                 )
   1110 
-> 1111             util.reraise(*exc_info)
   1112 
   1113         finally:

/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/sqlalchemy/engine/result.pyc in fetchall(self)
    781         try:
    782             l = self.process_rows(self._fetchall_impl())
--> 783             self.close()
    784             return l
    785         except Exception as e:

/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/sqlalchemy/engine/result.pyc in close(self, _autoclose_connection)
    541             if _autoclose_connection and \
    542                 self.connection.should_close_with_result:
--> 543                 self.connection.close()
    544             # allow consistent errors
    545             self.cursor = None

/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/sqlalchemy/engine/base.pyc in close(self)
    635         else:
    636             if not self.__branch:
--> 637                 conn.close()
    638             if conn._reset_agent is self.__transaction:
    639                 conn._reset_agent = None

/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/sqlalchemy/pool.pyc in close(self)
    781         self._counter -= 1
    782         if self._counter == 0:
--> 783             self._checkin()
    784 
    785 

/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/sqlalchemy/pool.pyc in _checkin(self)
    664     def _checkin(self):
    665         _finalize_fairy(self.connection, self._connection_record,
--> 666                             self._pool, None, self._echo, fairy=self)
    667         self.connection = None
    668         self._connection_record = None

/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/sqlalchemy/pool.pyc in _finalize_fairy(connection, connection_record, pool, ref, echo, fairy)
    564 
    565     if connection_record:
--> 566         connection_record.checkin()
    567 
    568 

/Users/erik/.virtualenvs/proj/lib/python2.7/site-packages/sqlalchemy/pool.pyc in checkin(self)
    455         connection = self.connection
    456         pool = self.__pool
--> 457         while self.finalize_callback:
    458             finalizer = self.finalize_callback.pop()
    459             finalizer(connection)

AttributeError: '_ConnectionRecord' object has no attribute 'finalize_callback'

Same exception regardless of the type of query I attempt. What is needed to make aldjemy compatible with the current release of SQLAlchemy?

New Release

According to PyPi there hasn't been a release since 2019-10-30 and there have been some commits since that address issues such as support for ArrayField.

Are there plans to release a new version? Currently I'm installing based on a github commit reference.

0.8 broken for me

Using an editable install to a local repository, and git bisect, I've determined that the error is caused by the commit from #59. I don't have the solution worked out yet, but I wanted to inform about the issue I'm seeing, and what I've been able to determine about it so far. I'm not sure how many other people might be seeing this issue, I've only tested it on my own private codebase.

Traceback (most recent call last):
  File "/home/ryan/.local/share/virtualenvs/aspiredu-sa7rbeeh/bin/django", line 11, in <module>
    sys.exit(main())
  File "/home/ryan/.local/share/virtualenvs/aspiredu-sa7rbeeh/lib/python3.6/site-packages/django_cmd.py", line 19, in main
    execute_from_command_line(sys.argv)
  File "/home/ryan/.local/share/virtualenvs/aspiredu-sa7rbeeh/lib/python3.6/site-packages/django/core/management/__init__.py", line 381, in execute_from_command_line
    utility.execute()
  File "/home/ryan/.local/share/virtualenvs/aspiredu-sa7rbeeh/lib/python3.6/site-packages/django/core/management/__init__.py", line 325, in execute
    settings.INSTALLED_APPS
  File "/home/ryan/.local/share/virtualenvs/aspiredu-sa7rbeeh/lib/python3.6/site-packages/django/conf/__init__.py", line 57, in __getattr__
    self._setup(name)
  File "/home/ryan/.local/share/virtualenvs/aspiredu-sa7rbeeh/lib/python3.6/site-packages/django/conf/__init__.py", line 44, in _setup
    self._wrapped = Settings(settings_module)
  File "/home/ryan/.local/share/virtualenvs/aspiredu-sa7rbeeh/lib/python3.6/site-packages/django/conf/__init__.py", line 107, in __init__
    mod = importlib.import_module(self.SETTINGS_MODULE)
  File "/home/ryan/.local/share/virtualenvs/aspiredu-sa7rbeeh/lib/python3.6/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 994, in _gcd_import
  File "<frozen importlib._bootstrap>", line 971, in _find_and_load
  File "<frozen importlib._bootstrap>", line 941, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "<frozen importlib._bootstrap>", line 994, in _gcd_import
  File "<frozen importlib._bootstrap>", line 971, in _find_and_load
  File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 678, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "/home/ryan/Code/aspiredu/aspiredu/aspiredu/project/__init__.py", line 1, in <module>
    from .celery import app
  File "/home/ryan/Code/aspiredu/aspiredu/aspiredu/project/celery.py", line 50, in <module>
    django.setup()
  File "/home/ryan/.local/share/virtualenvs/aspiredu-sa7rbeeh/lib/python3.6/site-packages/django/__init__.py", line 24, in setup
    apps.populate(settings.INSTALLED_APPS)
  File "/home/ryan/.local/share/virtualenvs/aspiredu-sa7rbeeh/lib/python3.6/site-packages/django/apps/registry.py", line 120, in populate
    app_config.ready()
  File "/home/ryan/Code/python/aldjemy/aldjemy/apps.py", line 17, in ready
    prepare_models()
  File "/home/ryan/Code/python/aldjemy/aldjemy/orm.py", line 145, in prepare_models
    attrs = _extract_model_attrs(model, sa_models_by_django_models)
  File "/home/ryan/Code/python/aldjemy/aldjemy/orm.py", line 53, in _extract_model_attrs
    attrs[f.name] = orm.column_property(table.c[f.column])
  File "/home/ryan/.local/share/virtualenvs/aspiredu-sa7rbeeh/lib/python3.6/site-packages/sqlalchemy/util/_collections.py", line 194, in __getitem__
    return self._data[key]
KeyError: 'data'

Metadata incorrect for nullable fields

The metadata that this library produces for the Django tables has all columns as being nullable, regardless of their specification in their origin classes

It's quite easy fix, just change the generate_tables method to pull the f.null attribute off each element in model.get_fields()

And then pass it into the Column constructor for sqlalchemy with keyword "nullable".

As for motivation, if someone was filthy enough to be wrapping existing django models into sqlalchemy metadata for use in Alembic as part of a migration process, then it might be useful to have this.

It also doesn't pick up indexes (and maybe lots of other things?), but that's a much harder problem to solve since indexes in django normally have horrible anonymous names that I don't know how to reverse engineer

Django 1.10 Deprecation Warning: `field.related`

env/lib/python3.5/site-packages/aldjemy/orm.py:44: RemovedInDjango110Warning: Usage of field.related has been deprecated. Use field.remote_field instead.
  parent_model = fk.related.model._meta

env/lib/python3.5/site-packages/aldjemy/orm.py:60: RemovedInDjango110Warning: Usage of field.related has been deprecated. Use field.remote_field instead.
  sec_table = tables[fk.related.field.m2m_db_table()]

Error creating backref -- name exists on mapper

Just upgraded from 0.6.0 to 0.7.0 (Django 1.10.7) and now I'm getting the following exception:

Traceback:

File "/Users/erik/.virtualenvs/cc/lib/python2.7/site-packages/django/core/handlers/exception.py" in inner
  42.             response = get_response(request)

File "/Users/erik/.virtualenvs/cc/lib/python2.7/site-packages/django/core/handlers/base.py" in _legacy_get_response
  249.             response = self._get_response(request)

File "/Users/erik/.virtualenvs/cc/lib/python2.7/site-packages/django/core/handlers/base.py" in _get_response
  187.                 response = self.process_exception_by_middleware(e, request)

File "/Users/erik/.virtualenvs/cc/lib/python2.7/site-packages/django/core/handlers/base.py" in _get_response
  185.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "/Users/erik/.virtualenvs/cc/lib/python2.7/site-packages/django/views/decorators/csrf.py" in wrapped_view
  58.         return view_func(*args, **kwargs)

File "/Users/erik/.virtualenvs/cc/lib/python2.7/site-packages/rest_framework/viewsets.py" in view
  83.             return self.dispatch(request, *args, **kwargs)

File "/Users/erik/.virtualenvs/cc/lib/python2.7/site-packages/rest_framework/views.py" in dispatch
  477.             response = self.handle_exception(exc)

File "/Users/erik/.virtualenvs/cc/lib/python2.7/site-packages/rest_framework/views.py" in handle_exception
  437.             self.raise_uncaught_exception(exc)

File "/Users/erik/.virtualenvs/cc/lib/python2.7/site-packages/rest_framework/views.py" in dispatch
  474.             response = handler(request, *args, **kwargs)

File "/Users/erik/Dropbox/home/git/cc/api/views.py" in list
  248.                                                                                       with_stats=request.GET.get('with_stats'))

File "/Users/erik/Dropbox/home/git/cc/portal/managers.py" in get_campaigns_for_reporting
  274.         query = portal_models.Campaign.sa.query(portal_models.Campaign.sa).\

File "/Users/erik/.virtualenvs/cc/lib/python2.7/site-packages/aldjemy/orm.py" in query
  137.             return get_session(alias).query(*a, **kw)

File "/Users/erik/.virtualenvs/cc/lib/python2.7/site-packages/sqlalchemy/orm/session.py" in query
  1330.         return self._query_cls(entities, self, **kwargs)

File "/Users/erik/.virtualenvs/cc/lib/python2.7/site-packages/sqlalchemy/orm/query.py" in __init__
  139.         self._set_entities(entities)

File "/Users/erik/.virtualenvs/cc/lib/python2.7/site-packages/sqlalchemy/orm/query.py" in _set_entities
  150.         self._set_entity_selectables(self._entities)

File "/Users/erik/.virtualenvs/cc/lib/python2.7/site-packages/sqlalchemy/orm/query.py" in _set_entity_selectables
  180.                 ent.setup_entity(*d[entity])

File "/Users/erik/.virtualenvs/cc/lib/python2.7/site-packages/sqlalchemy/orm/query.py" in setup_entity
  3585.         self._with_polymorphic = ext_info.with_polymorphic_mappers

File "/Users/erik/.virtualenvs/cc/lib/python2.7/site-packages/sqlalchemy/util/langhelpers.py" in __get__
  764.         obj.__dict__[self.__name__] = result = self.fget(obj)

File "/Users/erik/.virtualenvs/cc/lib/python2.7/site-packages/sqlalchemy/orm/mapper.py" in _with_polymorphic_mappers
  1948.             configure_mappers()

File "/Users/erik/.virtualenvs/cc/lib/python2.7/site-packages/sqlalchemy/orm/mapper.py" in configure_mappers
  2866.                         mapper._post_configure_properties()

File "/Users/erik/.virtualenvs/cc/lib/python2.7/site-packages/sqlalchemy/orm/mapper.py" in _post_configure_properties
  1765.                 prop.init()

File "/Users/erik/.virtualenvs/cc/lib/python2.7/site-packages/sqlalchemy/orm/interfaces.py" in init
  184.         self.do_init()

File "/Users/erik/.virtualenvs/cc/lib/python2.7/site-packages/sqlalchemy/orm/relationships.py" in do_init
  1656.         self._generate_backref()

File "/Users/erik/.virtualenvs/cc/lib/python2.7/site-packages/sqlalchemy/orm/relationships.py" in _generate_backref
  1837.                             (backref_key, self, m))

Exception Type: ArgumentError at /api/v1/campaign/
Exception Value: Error creating backref 'children' on relationship 'Region.parent': property of that name exists on mapper 'Mapper|TargetValue|portal_targetvalue'

Here ie the relevant excerpt from my models.py:

# models.py

class TargetValue(MPTTModel):
    # ...
    parent = TreeForeignKey('self', blank=True, null=True, related_name='children')
    
class Region(TargetValue):
    """
    Just the Regions from the TargetValue model.

    The proxy model allows us to automatically configure the API so that m2m fields will work with the "friendly" names.
    """
    objects = portal.managers.RegionManager()
    class Meta:
        proxy = True

Like I said, works fine in 0.6.0 as well as in the Django ORM.

typo in docs

diff --git a/README.rst b/README.rst
index 763af4e..0177d7a 100644
--- a/README.rst
+++ b/README.rst
@@ -58,7 +58,7 @@ Mixins
 Often django models have helper function and properties that helps to
 represent models data (`__unicode__`), or represent some model based logic.

-For integrate it with aldjemy models you can put this methods to separate mixin::
+To integrate it with aldjemy models you can put these methods to separate mixin::

     class TaskMixin(object):
         def __unicode__(self):
@@ -68,5 +68,5 @@ For integrate it with aldjemy models you can put this methods to separate mixin:
         aldjemy_mixin = TaskMixin
         code = models.CharField(_('code'), max_length=32, unique=True)

-Viola! You can user `unicode` on aldjemy classes, because this mixin will be
+Viola! You can use `unicode` on aldjemy classes, because this mixin will be
 mixed into generated aldjemy model.

typo?

diff --git a/aldjemy/table.py b/aldjemy/table.py
index 19047bb..b49279e 100644
--- a/aldjemy/table.py
+++ b/aldjemy/table.py
@@ -33,7 +33,7 @@ DATA_TYPES = {
     'FloatField':        simple(types.Float),
     'IntegerField':      simple(types.Integer),
     'BigIntegerField':   simple(types.BigInteger),
-    'IPAddressField':    lambda field: types.CHAR(lenght=15),
+    'IPAddressField':    lambda field: types.CHAR(length=15),
     'NullBooleanField':  simple(types.Boolean),
     'OneToOneField':     foreign_key,
     'ForeignKey':        foreign_key,

Breaks on Django 1.9

Hi,

When using Aldjemy 0.4.3 with Django 1.9 I get the following error:

Traceback (most recent call last):
  File "/opt/pycharm-5/helpers/pycharm/django_test_manage.py", line 53, in <module>
    django.setup()
  File "/home/adam/.virtualenvs/fleetv2/local/lib/python2.7/site-packages/django/__init__.py", line 18, in setup
    apps.populate(settings.INSTALLED_APPS)
  File "/home/adam/.virtualenvs/fleetv2/local/lib/python2.7/site-packages/django/apps/registry.py", line 115, in populate
    app_config.ready()
  File "/home/adam/.virtualenvs/fleetv2/local/lib/python2.7/site-packages/aldjemy/apps.py", line 17, in ready
    prepare_models()
  File "/home/adam/.virtualenvs/fleetv2/local/lib/python2.7/site-packages/aldjemy/orm.py", line 86, in prepare_models
    tables = get_tables()
  File "/home/adam/.virtualenvs/fleetv2/local/lib/python2.7/site-packages/aldjemy/core.py", line 67, in get_tables
    generate_tables(get_meta())
  File "/home/adam/.virtualenvs/fleetv2/local/lib/python2.7/site-packages/aldjemy/table.py", line 79, in generate_tables
    typ = DATA_TYPES[internal_type](field)
  File "/home/adam/.virtualenvs/fleetv2/local/lib/python2.7/site-packages/aldjemy/types.py", line 19, in foreign_key
    parent_model = field.related.model
AttributeError: 'ManyToOneRel' object has no attribute 'related'

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.