SQLAlchemy add index in mixin based upon inherited table keys? - indexing

In SQLAlchemy, I want to define a mixin that automatically creates an Index in inheriting tables.
Assuming that the inheriting table has a member list called 'keys', I want the mixin to create in the inheriting table a single multi-column Index over the columns listed in keys. However, the mixin doesn't know what the keys are until the table is created!
How would I do this?

Example:
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.declarative import declared_attr
from sqlalchemy import MetaData, Column, Index, Integer
metadata = MetaData()
Base = declarative_base(metadata=metadata)
class MyMixin(object):
#declared_attr
def __table_args__(cls):
return (Index('test_idx_%s' % cls.__tablename__, *cls.INDEX),)
class MyModel(MyMixin, Base):
__tablename__ = 'atable'
INDEX = ('a', 'b',)
id = Column(Integer, primary_key=True)
a = Column(Integer)
b = Column(Integer)
c = Column(Integer)
if __name__ == '__main__':
from sqlalchemy import create_engine
engine = create_engine('sqlite:///', echo=True)
metadata.bind = engine
metadata.create_all()
Docs: Combining Table/Mapper Arguments from Multiple Mixins

Related

How to create a one to many relationship using Tortoise ORM?

I am creating an app in which I have a User entity and an Item entity that are related one to many.
I am using TORTOISE ORM, in a file with the path: app/models/user.py I have the following code:
from tortoise import fields
from app.models.base_class import Base
class User(Base):
name = fields.CharField(max_length = 50, nullable = False)
last_name = fields.CharField(max_length = 50, nullable = False)
email = fields.CharField(max_length = 128, unique = True, nullable = False)
password = fields.CharField(max_length = 128, nullable = False)
create_date = fields.DatetimeField(auto_now = True)
class Meta:
table = 'user_db'
Hello, I am creating an app in which I have a User entity and an Item entity that are related one to many.
I am using TORTOISE ORM, in a file with the path: app/models/user.py I have the following code:
And in the path: app/models/item.py I have the following code:
from tortoise.models import Model
from tortoise import fields
from app.models.base_class import Base
class Item(Base):
title = fields.CharField(max_length = 50, nullable = False)
description = fields.TextField(nullable = False)
weight = fields.DecimalField(max_digits=3)
cost = fields.DecimalField(max_digits=3)
url_image = fields.CharField(max_length = 255)
user_id = fields.ForeignKeyField(
'app.models.user.User',
'id',
on_delete = fields.CASCADE
)
My question is if I am correctly implementing the foreign key in the user_id field, is it correct to write the path 'app.models.user.User' for the model name parameter? Do I have to import User in item.py to be able to do this?
Or, on the other hand, should I write in this parameter is 'user_db', which will be the name of the User model table? I'm tangled up with this.

How do I make and access regex capture groups in Django without RawSQL?

How do I annotate a Django queryset with a Regex capture group without using RawSQL so that I later can use that value for filtering and sorting?
For example, in PostgreSQL I could make the following query:
CREATE TABLE foo (id varchar(100));
INSERT INTO foo (id) VALUES ('disk1'), ('disk10'), ('disk2');
SELECT
"foo"."id",
CAST((regexp_matches("foo"."id", '^(.*\D)([0-9]*)$'))[2] AS integer) as grp2
FROM "foo"
ORDER BY "grp2"
dbfiddle
You can use a custom Func class created to get it working, but I would like to implement in a better way, just like a normal function which could be used for further processing using other functions or annotations or etc. Like a "block" in the Django ORM ecosystem.
I would like to start with an "beta version" of the class which looks like this one:
from django.db.models.expressions import Func, Value
class RegexpMatches(Func):
function = 'REGEXP_MATCHES'
def __init__(self, source, regexp, flags=None, group=None, output_field=None, **extra):
template = '%(function)s(%(expressions)s)'
if group:
if not hasattr(regexp, 'resolve_expression'):
regexp = Value(regexp)
template = '({})[{}]'.format(template, str(group))
expressions = (source, regexp)
if flags:
if not hasattr(flags, 'resolve_expression'):
flags = Value(flags)
expressions += (flags,)
self.template = template
super().__init__(*expressions, output_field=output_field, **extra)
and a fully working example for an admin interface:
from django.contrib.admin import ModelAdmin, register
from django.db.models import IntegerField
from django.db.models.functions import Cast
from django.db.models.expressions import Func, Value
from .models import Foo
class RegexpMatches(Func):
function = 'REGEXP_MATCHES'
def __init__(self, source, regexp, flags=None, group=None, output_field=None, **extra):
template = '%(function)s(%(expressions)s)'
if group:
if not hasattr(regexp, 'resolve_expression'):
regexp = Value(regexp)
template = '({})[{}]'.format(template, str(group))
expressions = (source, regexp)
if flags:
if not hasattr(flags, 'resolve_expression'):
flags = Value(flags)
expressions += (flags,)
self.template = template
super().__init__(*expressions, output_field=output_field, **extra)
#register(Foo)
class Foo(ModelAdmin):
list_display = ['id', 'required_field', 'required_field_string']
def get_queryset(self, request):
qs = super().get_queryset(request)
return qs.annotate(
required_field=Cast(RegexpMatches('id', r'^(.*\D)([0-9]*)$', group=2), output_field=IntegerField()),
required_field_string=RegexpMatches('id', r'^(.*\D)([0-9]*)$', group=2)
)
def required_field(self, obj):
return obj.required_field
def required_field_string(self, obj):
return obj.required_field_string
As you see in I've added 2 annotations and one outputs like a number and the other one like a normal string (character), of course, we don't see it in the admin interface but it does in the SQL are executed:
SELECT "test_foo"."id" AS Col1,
((REGEXP_MATCHES("test_foo"."id", '^(.*\D)([0-9]*)$'))[2])::integer AS "required_field", (REGEXP_MATCHES("test_foo"."id", '^(.*\D)([0-9]*)$'))[2] AS "required_field_string"
FROM "test_foo"
And also a screenshot with an example for you :)
Github gist with a better source code formatting https://gist.github.com/phpdude/50675114aaed953b820e5559f8d22166
From Django 1.8 onwards, you can use Func() expressions.
from django.db.models import Func
class EndNumeric(Func):
function = 'REGEXP_MATCHES'
template = "(%(function)s(%(expressions)s, '^(.*\D)([0-9]*)$'))[2]::integer"
qs = Foo.objects.annotate(
grp2=EndNumeric('id'),
).values('id', 'grp2').order_by('grp2')
Reference: Get sorted queryset by specified field with regex in django

Odoo 10 selection fields value

How can i get selection fields value in odoo 10?
def compute_default_value(self):
return self.get_value("field")
I tried this,
def compute_default_value(self):
return dict(self._fields['field'].selection).get(self.type)
Also tried this,but it is not working.
Please help me, i could not find the solution.
Thank you.
You can do this in a following manner:
self._fields['your_field']._desription_selection(self.env)
This will return the selection list of pairs (value, label).
If you just need possible values, you can use get_values method.
self._fields['your_field'].get_values(self.env)
But it's not a common way. Most of the time people define selections differently and then use those definitions. For example, I commonly use classes for those.
class BaseSelectionType(object):
""" Base abstract class """
values = None
#classmethod
def get_selection(cls):
return [(x, cls.values[x]) for x in sorted(cls.values)]
#classmethod
def get_value(cls, _id):
return cls.values.get(_id, False)
class StateType(BaseSelectionType):
""" Your selection """
NEW = 1
IN_PROGRESS = 2
FINISHED = 3
values = {
NEW: 'New',
IN_PROGRESS: 'In Progress',
FINISHED: 'Finished'
}
You can use this class wherever you want, just import it.
state = fields.Selection(StateType.get_selection(), 'State')
And it's really handy to use those in the code. For example, if you want to do something on a specific state:
if self.state == StateType.NEW:
# do your code ...
I don't get the question fully, but let me try to answer. Why not just define the selection as method and use it for both situations:
from datetime import datetime
from odoo import models, fields
class MyModel(models.Model):
_name = 'my.model'
def month_selection(self):
return [(1, 'Month1'), (2, 'Month2')]
def compute_default_value(self):
selection = self.month_selection()
# do whatever you want here
month = fields.Selection(
selection=month_selection, string='Month',
default=datetime.now().month, required=True)

Serializer for mongo models excluding specific related class type

Consider the following models:
class Line(Document):
name = StringField()
class Root(Document):
name = StringField()
children = ListField(fields=ReferenceField('RootContent'))
class RootContent(Document):
meta = { 'allow_inheritance': True }
class Directory(RootContent):
name = StringField()
children = ListField(fields=ReferenceField('RootContent'))
class File(RootContent):
name = StringField()
children = ListField(fields=ReferenceField('Line'))
I need a serializer using django-rest-framework-mongoengine that may provide me with all roots having all directories and files, but not lines. I may set a fairly large value of "depth". How do I write a serializer that does it?
Finally I ended up doing something like the following:
from rest_framework_mongoengine import serializers as mongo_serializers
class ChildField(mongo_serializers.serializers.Serializer):
def to_native(self, value):
return self.parent.to_native(value)
class TreeSerializer(mongo_serializers.MongoEngineModelSerializer):
name = mongo_serializers.fields.SerializerMethodField(method_name='get_name')
children = ChildField(many=True)
class Meta:
model = Root
def get_name(self, obj):
"""Mainly in to nullify children of
object"""
if isinstance(obj, File):
obj.children = []
return obj.name

How to automatically reflect table relationships in SQLAlchemy or SqlSoup ORM?

How do I tell SQLAlchemy to automatically reflect basic Foreign Key references as references to other ORM objects and not integer fields?
In both SQLAlchemy and it's SqlSoup, table columns are reflected automatically and relations can be defined manually:
class User(Base):
__table__ = metadata.tables['users']
loan = relation(Loans)
...
You can define relationships on SqlSoup classes:
>>> db.users.relate('loans', db.loans)
Try this magic )
Works for simple FK relations, and without db schemes
from sqlalchemy import create_engine, MetaData
from sqlalchemy.orm import mapper, relation
engine = create_engine("sqlite://", echo=True)
engine.execute('''
create table foo (
id integer not null primary key,
x integer
)''')
engine.execute('''
create table bar (
id integer not null primary key,
foo_id integer,
FOREIGN KEY(foo_id) REFERENCES foo(id)
)''')
metadata = MetaData()
metadata.reflect(bind=engine)
MAPPERS = {
}
repr_name = lambda t: '%s%s' % (t[0].upper(), t[1:])
for table in metadata.tables:
cls = None
# 1. create class object
cls_name = repr_name(str(table))
exec("""class %s(object): pass""" % cls_name)
exec("""cls = %s""" % cls_name)
# 2. collect relations by FK
properties = {}
for c in metadata.tables[table].columns:
for fk in c.foreign_keys:
name = str(fk.column).split('.')[0]
properties.update({
name: relation(lambda: MAPPERS[repr_name(name)]),
})
# 3. map table to class object
mapper(cls, metadata.tables[table], properties=properties)
MAPPERS.update({cls_name: cls})
if __name__ == '__main__':
from sqlalchemy.orm import sessionmaker
print 'Mappers: '
for m in MAPPERS.values():
print m
session = sessionmaker(bind=engine)()
foo = Foo()
foo.x = 1
session.add(foo)
session.commit()
print session.query(Foo).all()
bar = Bar()
bar.foo = foo
session.add(bar)
session.commit()
print session.query(Bar).all()