I am building a flask application over an already existing database so there was no need to declare the whole models fully. I have this table:
class Users(db.Model):
__tablename__ = 'my_users'
__table_args__ = {
'autoload': True,
'autoload_with': db.engine
}
the table has about 10 columns but when i query the data i can see that the attribute:
.__dict__
only returns the first 4 columns. i have tried using filter and also filter by but data returned only contains the first 4 columns. Here is my query:
users = Users.query.filter(
section_serial == sectionserial
).all()
I am using the postgres database. Here is a minimal example:
CREATE TABLE public.my_users
(
user_serial integer NOT NULL DEFAULT nextval('my_users_seq'::regclass),
user_name character varying(16) NOT NULL,
user_password character varying(42) NOT NULL,
id_number character varying(155) NOT NULL,
date_added timestamp without time zone NOT NULL DEFAULT now(),
is_enabled boolean NOT NULL DEFAULT true,
expiry_date date NOT NULL DEFAULT (('now'::text)::date + 30),
phone_number character varying(254),
notes text,
section_serial integer,
full_name character varying(155) NOT NULL,
zip_code boolean NOT NULL DEFAULT false,
CONSTRAINT user_serial_pkey PRIMARY KEY (user_serial)
);
After querying the data i only get user_serial, user_name, user_password and id_number. I cannot get the rest of the columns
The problem was it was conflicting with a login model i had created though with a different name. I think models should just be declared once.
class SystemUsers(db.Model):
__tablename__ = 'my_users'
userserial = db.Column(
'user_serial', db.Integer, primary_key=True)
username = db.Column('user_name ', db.String)
password= db.Column('user_password ', db.String)
idnumber = db.Column('id_number', db.String)
isactive = True
isanonymous = False
authenticated = False
I have following django model
class CalculatedResults(models.Model):
id = models.IntegerField(primary_key=True)
tmstamp = models.DateTimeField()
latitude = models.FloatField()
longitude = models.FloatField()
magnitude = models.FloatField()
origin_time = models.DateTimeField()
actioncode = models.IntegerField(db_column='actionCode', blank=True, null=True) # Field name made lowercase.
class Meta:
managed = False
db_table = 'calculated_results'
verbose_name = 'Calculated Result'
verbose_name_plural = 'Calculated Results'
and relevant mysql table is :
CREATE TABLE IF NOT EXISTS `calculated_results` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`tmstamp` timestamp(5) NOT NULL DEFAULT CURRENT_TIMESTAMP,
`latitude` double NOT NULL,
`longitude` double NOT NULL,
`magnitude` double NOT NULL DEFAULT '0',
`origin_time` timestamp(5) NOT NULL DEFAULT '0000-00-00 00:00:00.00000',
`actionCode` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `tmstamp_index` (`tmstamp`),
KEY `origin_time_index` (`origin_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=814 ;
When I try to retrieve data from the table using python manage.py shell using following code,
form eew_main.models import CalculatedResults
a = CalculatedResults.objects.all().order_by('-id')[:1]
I get None for tmstamp and origin_time but as far as I have investigated the issue, following sql query is sent to mysql
SELECT `calculated_results`.`id` , `calculated_results`.`tmstamp` , `calculated_results`.`latitude` , `calculated_results`.`longitude` , `calculated_results`.`magnitude` , `calculated_results`.`origin_time` , `calculated_results`.`actionCode`
FROM `calculated_results`
ORDER BY `calculated_results`.`id` DESC
LIMIT 1
When I try it on mysql with same mysql user that django uses I got all the values.
So please help me to somehow find a way to investigate and resolve this issue.
Thanks!
Seems your tables are created outside of Django. Django's models.DateTimeField will synthesize into a datetime field in MySQL not timestamp.
Check this answer for an implementation similar to DateTimeField that uses timestamp at SQL level.
I have a MySQL table as follows:
create table USER
(
USERID int not null auto_increment,
USERAVATAR varchar(1024) default NULL,
primary key (USERID)
);
I have created an entry in the table where USERID = 1 and USERAVATAR = NULL.
In Main.py
user_list = session.query(USER).all()
return jsonify(users=[r.serialize() for r in user_list])
sqltables.py
class USER(Base):
__tablename__ = 'USER'
USERID = Column(Integer, primary_key=True)
USERAVATAR = Column(String(1024))
def serialize(self):
return unicode({
'id': self.USERID,
'userAvatar': self.USERAVATAR
})
The issue is that even though USERAVATAR has been set to NULL in the database, I'm getting None as my `JSON output.
{
"users": [
"{'userAvatar': None, 'id': 1}"
]
}
Would anyone know what might be the problem here?
Your serialize function is casting into a string. Is that what you want in your JSON output, an array of strings instead of an array of objects?
If not, change your serialize function to not use unicode()
I have a model with a unique_together defined for 3 fields to be unique together:
class MyModel(models.Model):
clid = models.AutoField(primary_key=True, db_column='CLID')
csid = models.IntegerField(db_column='CSID')
cid = models.IntegerField(db_column='CID')
uuid = models.CharField(max_length=96, db_column='UUID', blank=True)
class Meta(models.Meta):
unique_together = [
["csid", "cid", "uuid"],
]
Now, if I attempt to save a MyModel instance with an existing csid+cid+uuid combination, I would get:
IntegrityError: (1062, "Duplicate entry '1-1-1' for key 'CSID'")
Which is correct. But, is there a way to customize that key name? (CSID in this case)
In other words, can I provide a name for a constraint listed in unique_together?
As far as I understand, this is not covered in the documentation.
Its not well documented, but depending on if you are using Django 1.6 or 1.7 there are two ways you can do this:
In Django 1.6 you can override the unique_error_message, like so:
class MyModel(models.Model):
clid = models.AutoField(primary_key=True, db_column='CLID')
csid = models.IntegerField(db_column='CSID')
cid = models.IntegerField(db_column='CID')
# ....
def unique_error_message(self, model_class, unique_check):
if model_class == type(self) and unique_check == ("csid", "cid", "uuid"):
return _('Your custom error')
else:
return super(MyModel, self).unique_error_message(model_class, unique_check)
Or in Django 1.7:
class MyModel(models.Model):
clid = models.AutoField(primary_key=True, db_column='CLID')
csid = models.IntegerField(db_column='CSID')
cid = models.IntegerField(db_column='CID')
uuid = models.CharField(max_length=96, db_column='UUID', blank=True)
class Meta(models.Meta):
unique_together = [
["csid", "cid", "uuid"],
]
error_messages = {
NON_FIELD_ERRORS: {
'unique_together': "%(model_name)s's %(field_labels)s are not unique.",
}
}
Changing index name in ./manage.py sqlall output.
You could run ./manage.py sqlall yourself and add in the constraint name yourself and apply manually instead of syncdb.
$ ./manage.py sqlall test
BEGIN;
CREATE TABLE `test_mymodel` (
`CLID` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
`CSID` integer NOT NULL,
`CID` integer NOT NULL,
`UUID` varchar(96) NOT NULL,
UNIQUE (`CSID`, `CID`, `UUID`)
)
;
COMMIT;
e.g.
$ ./manage.py sqlall test
BEGIN;
CREATE TABLE `test_mymodel` (
`CLID` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
`CSID` integer NOT NULL,
`CID` integer NOT NULL,
`UUID` varchar(96) NOT NULL,
UNIQUE constraint_name (`CSID`, `CID`, `UUID`)
)
;
COMMIT;
Overriding BaseDatabaseSchemaEditor._create_index_name
The solution pointed out by #danihp is incomplete, it only works for field updates (BaseDatabaseSchemaEditor._alter_field)
The sql I get by overriding _create_index_name is:
BEGIN;
CREATE TABLE "testapp_mymodel" (
"CLID" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
"CSID" integer NOT NULL,
"CID" integer NOT NULL,
"UUID" varchar(96) NOT NULL,
UNIQUE ("CSID", "CID", "UUID")
)
;
COMMIT;
Overriding BaseDatabaseSchemaEditor.create_model
based on https://github.com/django/django/blob/master/django/db/backends/schema.py
class BaseDatabaseSchemaEditor(object):
# Overrideable SQL templates
sql_create_table_unique = "UNIQUE (%(columns)s)"
sql_create_unique = "ALTER TABLE %(table)s ADD CONSTRAINT %(name)s UNIQUE (%(columns)s)"
sql_delete_unique = "ALTER TABLE %(table)s DROP CONSTRAINT %(name)s"
and this is the piece in create_model that is of interest:
# Add any unique_togethers
for fields in model._meta.unique_together:
columns = [model._meta.get_field_by_name(field)[0].column for field in fields]
column_sqls.append(self.sql_create_table_unique % {
"columns": ", ".join(self.quote_name(column) for column in columns),
})
Conclusion
You could:
override create_model to use _create_index_name for unique_together contraints.
modify sql_create_table_unique template to include a name parameter.
You may also be able to check a possible fix on this ticket:
https://code.djangoproject.com/ticket/24102
Integrity error is raised from database but from django:
create table t ( a int, b int , c int);
alter table t add constraint u unique ( a,b,c); <-- 'u'
insert into t values ( 1,2,3);
insert into t values ( 1,2,3);
Duplicate entry '1-2-3' for key 'u' <---- 'u'
That means that you need to create constraint with desired name in database. But is django in migrations who names constraint. Look into _create_unique_sql :
def _create_unique_sql(self, model, columns):
return self.sql_create_unique % {
"table": self.quote_name(model._meta.db_table),
"name": self.quote_name(self._create_index_name(model, columns, suffix="_uniq")),
"columns": ", ".join(self.quote_name(column) for column in columns),
}
Is _create_index_name who has the algorithm to names constraints:
def _create_index_name(self, model, column_names, suffix=""):
"""
Generates a unique name for an index/unique constraint.
"""
# If there is just one column in the index, use a default algorithm from Django
if len(column_names) == 1 and not suffix:
return truncate_name(
'%s_%s' % (model._meta.db_table, self._digest(column_names[0])),
self.connection.ops.max_name_length()
)
# Else generate the name for the index using a different algorithm
table_name = model._meta.db_table.replace('"', '').replace('.', '_')
index_unique_name = '_%x' % abs(hash((table_name, ','.join(column_names))))
max_length = self.connection.ops.max_name_length() or 200
# If the index name is too long, truncate it
index_name = ('%s_%s%s%s' % (
table_name, column_names[0], index_unique_name, suffix,
)).replace('"', '').replace('.', '_')
if len(index_name) > max_length:
part = ('_%s%s%s' % (column_names[0], index_unique_name, suffix))
index_name = '%s%s' % (table_name[:(max_length - len(part))], part)
# It shouldn't start with an underscore (Oracle hates this)
if index_name[0] == "_":
index_name = index_name[1:]
# If it's STILL too long, just hash it down
if len(index_name) > max_length:
index_name = hashlib.md5(force_bytes(index_name)).hexdigest()[:max_length]
# It can't start with a number on Oracle, so prepend D if we need to
if index_name[0].isdigit():
index_name = "D%s" % index_name[:-1]
return index_name
For the current django version (1.7) the constraint name for a composite unique constraint looks like:
>>> _create_index_name( 'people', [ 'c1', 'c2', 'c3'], '_uniq' )
'myapp_people_c1_d22a1efbe4793fd_uniq'
You should overwrite _create_index_name in some way to change algorithm. A way, maybe, writing your own db backend inhering from mysql and overwriting _create_index_name in your DatabaseSchemaEditor on your schema.py (not tested)
I believe you have to do that in your Database;
MySQL:
ALTER TABLE `votes` ADD UNIQUE `unique_index`(`user`, `email`, `address`);
I believe would then say ... for key 'unique_index'
One solution is you can catch the IntegrityError at save(), and then make custom error message as you want as below.
try:
obj = MyModel()
obj.csid=1
obj.cid=1
obj.uuid=1
obj.save()
except IntegrityError:
message = "IntegrityError: Duplicate entry '1-1-1' for key 'CSID', 'cid', 'uuid' "
Now you can use this message to display as error message.
I want to have a base entity with a field deleted which marks a deleted record. And i have 2 subclasses, each of them to have their own table with all own columns:
from elixir import *
from sqlalchemy import create_engine
class Catalog(Entity):
using_options(inheritance='concrete')
deleted = Boolean
class Contact(Catalog):
using_options(inheritance='concrete')
name = Field(String(60))
class Location(Catalog):
using_options(inheritance='concrete')
name = Field(String(100))
setup_all()
metadata.bind = create_engine('sqlite:///', echo=True)
metadata.create_all()
And the result:
CREATE TABLE __main___catalog (
id INTEGER NOT NULL,
PRIMARY KEY (id)
)
CREATE TABLE __main___contact (
id INTEGER NOT NULL,
name VARCHAR(60),
PRIMARY KEY (id)
)
CREATE TABLE __main___location (
id INTEGER NOT NULL,
name VARCHAR(100),
PRIMARY KEY (id)
)
Questions:
How to avoid creation of a table for the base entity? - solved: using_options(abstract = True)
Why field deleted is not in the created tables? - this solved - i forgot to put it inside a Field
I want to avoid typing in each subclass using_options(inheritance='concrete') but still have "concrete inheritance". Is there a way to make it default for all subclasses?
This works:
class Catalog(Entity):
deleted = Field(Boolean)
using_options(abstract = True, inheritance = 'concrete')
class Contact(Catalog):
name = Field(String(60))
class Location(Catalog):
name = Field(String(100))
and creates the following tables:
CREATE TABLE __main___contact (
id INTEGER NOT NULL,
deleted BOOLEAN,
name VARCHAR(60),
PRIMARY KEY (id),
CHECK (deleted IN (0, 1))
)
CREATE TABLE __main___location (
id INTEGER NOT NULL,
deleted BOOLEAN,
name VARCHAR(100),
PRIMARY KEY (id),
CHECK (deleted IN (0, 1))
)