I am creating models in django. This is my config in the models file. I want to create a table governmentoffical that references counties and citizen. However, when I ran manage.py sqlal, it changed my column name in government official tables.
class counties(models.Model):
name = models.CharField(max_length=50, primary_key=True, unique=True)
population = models.IntegerField()
governer = models.CharField(max_length=75)
class citizen(models.Model):
ssn = models.CharField(max_length=40, primary_key=True)
citizen_name = models.CharField(max_length=50, unique=True)
age = models.IntegerField()
income = models.IntegerField()
username = models.CharField(max_length=30)
password = models.CharField(max_length=30)
class governmentOfficial(models.Model):
countyName = models.ForeignKey(counties, primary_key=True)
offical_name = models.ForeignKey(citizen, to_field='citizen_name')
position = models.CharField(max_length=50)
year_elected = models.IntegerField(max_length=4)
party = models.CharField(max_length=25)
county_username=models.CharField(max_length=20)
county_password=models.CharField(max_length=20)
Here is my sql output.
CREATE TABLE `troywebsite_governmentofficial` (
`countyName_id` varchar(50) NOT NULL PRIMARY KEY,
`offical_name_id` varchar(50) NOT NULL,
`position` varchar(50) NOT NULL,
`year_elected` integer NOT NULL,
`party` varchar(25) NOT NULL,
`county_username` varchar(20) NOT NULL,
`county_password` varchar(20) NOT NULL
)
;
ALTER TABLE `troywebsite_governmentofficial` ADD CONSTRAINT `countyName_id_refs_name_2c9a2c94` FOREIGN KEY (`countyName_id`) REFERENCES `troywebsite_counties` (`name`);
ALTER TABLE `troywebsite_governmentofficial` ADD CONSTRAINT `offical_name_id_refs_citizen_name_6f795c2a` FOREIGN KEY (`offical_name_id`) REFERENCES `troywebsite_citizen` (`citizen_name`);
CREATE INDEX `troywebsite_governmentofficial_effdd6a5` ON `troywebsite_governmentofficial` (`offical_name_id`);
CREATE INDEX `troywebsite_solider_c5b4e228` ON `troywebsite_solider` (`solider_name_id`);
Is there a way to take out the CREATE INDEX in governmentofficial, and leave to to be countyName and Official_name as the column?
You can use the db_column parameter to call the column whatever you like.
https://docs.djangoproject.com/en/dev/ref/models/fields/#db-column
countyName = models.ForeignKey(counties, primary_key=True, db_column='whatever')
Related
I have these two objects:
class Account(Base):
__tablename__ = "accounts"
uuid = Column(UUID(as_uuid=True), primary_key=True, server_default=text("gen_random_uuid()"))
name = Column(String(255), nullable=False)
description = Column(String(255), nullable=True)
created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
profiles = relationship("Profile")
class Profile(Base): # pragma: integration
__tablename__ = "profiles"
uuid = Column(UUID(as_uuid=True), primary_key=True, server_default=text("gen_random_uuid()"))
name = Column(String(255), nullable=False)
description = Column(String(255), nullable=True)
account_uuid = Column(UUID(as_uuid=True), ForeignKey(Account.uuid), nullable=False)
created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
An account can have multilple profiles and a profile cannot exist without it belonging to an account.
Now lets suppose I have an account Account A and that account has Profile 1 and I want to change description in Account A.
I'm fetching and modifying Account A like this:
account = SESSION.query(Account)\
.select_from(Account)\
.filter_by(uuid='uuid-here')\
.options(noload('*'))\
.all()[0]
account.description = "New description"
SESSION.merge(account)
SESSION.commit()
but I get this error:
{IntegrityError}(psycopg2.errors.NotNullViolation) null value in column "account_uuid" of relation "profiles" violates not-null constraint
DETAIL: Failing row contains (2023-01-25 10:28:04.067598+00, 2023-01-25 10:44:44.45617+00, c2e25467-b058-469f-99bb-28debd6289cd, Profile 1, This is a profile for testing, null).
[SQL: UPDATE profiles SET updated_at=now(), account_uuid=%(account_uuid)s WHERE profiles.uuid = %(profiles_uuid)s]
[parameters: {'account_uuid': None, 'profiles_uuid': UUID('c2e25467-b058-469f-99bb-28debd6289cd')}]
(Background on this error at: https://sqlalche.me/e/14/gkpj)
I don't understand why this error is comming up, I am not touching the profiles table at all (I purposefully didn't even let it be loaded with noload('*')) and I haven't changed Account A's uuid either.
Why is it trying to update profiles?
EDIT:
I can solve this by changing the code to:
account = SESSION.query(Account)\
.select_from(Account)\
.filter_by(uuid='uuid-here')\
.options(noload('*'))\
.all()[0]
account.description = "New description"
SESSION.expunge_all()
SESSION.add(account)
SESSION.merge(account)
SESSION.commit()
but that doesn't feel right
I have a function that creates some new DB entries in Flask app with SQL Alchemy
def add_volunteer_client_record(volunteer_id, **kwargs):
try:
volunteer_client = VolunteerClient(volunteer_id=volunteer_id, **kwargs)
volunteer_report_action_items = VolunteerReportActionItems(volunteer_client_id = volunteer_client.id)
db_session.add(volunteer_client)
db_session.add(volunteer_report_action_items)
db_session.commit()
return volunteer_client
except IntegrityError as e:
db_session.rollback()
message = "Integrity error occurred"
raise BadRequestError(messages={'volunteer_client': [message]})
volunteer_client gets created fine but when volunteer_report_action_items is added to the session I received an IntegrityError and I can not quite understand why.
My Models
class VolunteerClient(Base):
__tablename__ = 'volunteer_client'
id = Column(Integer, primary_key=True, autoincrement=True, index=True)
volunteer_id = Column(Integer, ForeignKey('provider_user.user_id', onupdate='CASCADE', ondelete='RESTRICT'), unique=True)
client_id = Column(Integer, ForeignKey('user.id', onupdate='CASCADE', ondelete='RESTRICT'), unique=True)
class VolunteerReportActionItems(Base):
__tablename__ = 'volunteer_report_action_items'
id = Column(Integer, primary_key=True, autoincrement=True, index=True)
volunteer_client_id = Column(Integer, ForeignKey('volunteer_client.id', onupdate='CASCADE', ondelete='RESTRICT'))
SQL
CREATE TABLE IF NOT EXISTS public.volunteer_client
(
id serial PRIMARY KEY,
volunteer_id integer NOT NULL,
client_id integer NOT NULL,
created_by text,
created_at timestamp NOT NULL DEFAULT now(),
updated_by text,
updated_at timestamp NOT NULL DEFAULT now(),
UNIQUE(volunteer_id, client_id),
CONSTRAINT fk_volunteer_client_volunteer FOREIGN KEY (volunteer_id)
REFERENCES public.user (id) MATCH SIMPLE
ON UPDATE CASCADE
ON DELETE RESTRICT,
CONSTRAINT fk_volunteer_client_client FOREIGN KEY (client_id)
REFERENCES public.user (id) MATCH SIMPLE
ON UPDATE CASCADE
ON DELETE RESTRICT
);
ALTER TABLE public.volunteer_client OWNER to navigate;
CREATE TABLE IF NOT EXISTS public.volunteer_report_action_items
(
id serial PRIMARY KEY,
volunteer_client_id integer NOT NULL,
created_by text,
created_at timestamp NOT NULL DEFAULT now(),
updated_by text,
updated_at timestamp NOT NULL DEFAULT now(),
CONSTRAINT fk_volunteer_report_action_items_volunteer_client FOREIGN KEY (volunteer_client_id)
REFERENCES public.volunteer_client (id) MATCH SIMPLE
ON UPDATE CASCADE
ON DELETE RESTRICT
);
ALTER TABLE public.volunteer_report_action_items OWNER to navigate;
Any help or advice here would be great. Thanks!
You need to flush the VolunteerClient to be able to access the VolunteerClient.id
def add_volunteer_client_record(volunteer_id, **kwargs):
try:
volunteer_client = VolunteerClient(volunteer_id=volunteer_id, **kwargs)
db_session.add(volunteer_client)
db_session.flush()
volunteer_report_action_items = VolunteerReportActionItems(volunteer_client_id = volunteer_client.id)
db_session.add(volunteer_report_action_items)
db_session.commit()
...
I have somewhat of a general question, also curious about best practices. I have a model in SQL which looks as so:
CREATE TABLE IF NOT EXISTS public.volunteer_report
(
id serial PRIMARY KEY,
volunteer_id integer NOT NULL,
client_id integer NOT NULL,
user_need_id integer NOT NULL,
report character varying(255) NOT NULL,
report_category character varying(255) NOT NULL,
created_by text,
created_at timestamp NOT NULL DEFAULT now(),
updated_by text,
updated_at timestamp NOT NULL DEFAULT now(),
CONSTRAINT fk_volunteer_report_volunteer FOREIGN KEY (volunteer_id)
REFERENCES public.user (id) MATCH SIMPLE
ON UPDATE CASCADE
ON DELETE RESTRICT,
CONSTRAINT fk_volunteer_report_client FOREIGN KEY (client_id)
REFERENCES public.user (id) MATCH SIMPLE
ON UPDATE CASCADE
ON DELETE RESTRICT,
CONSTRAINT fk_volunteer_report_client_need FOREIGN KEY (user_need_id)
REFERENCES public.user_need (id) MATCH SIMPLE
ON UPDATE CASCADE
ON DELETE RESTRICT
);
Both FK's make a reference to the user PK.
MY FLASK APP
class VolunteerReport(Base):
__tablename__ = 'volunteer_report'
id = Column(Integer, primary_key=True, autoincrement=True, index=True)
volunteer_id = Column(Integer, ForeignKey('volunteer_client.volunteer_id', onupdate='CASCADE', ondelete='RESTRICT'))
client_id = Column(Integer, ForeignKey('volunteer_client.client_id', onupdate='CASCADE', ondelete='RESTRICT'))
user_need_id = Column(Integer, ForeignKey('user_need.id', onupdate='CASCADE', ondelete='RESTRICT'))
report = Column(String(255), nullable=False)
report_category = Column(String(255), nullable=False)
The FK references are different here. referencing volunteer_client table instead of user table, but the int FK value that gets stored is the same.
Is this expected to work and perform fine, or should the table references be exactly identical?
I'm setting up multiple foreign keys but it shows error
from flask_sqlalchemy import SQLAlchemy
sql= SQLAlchemy(app)
app.secret_key = os.urandom(24)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql:///test'
app.config['SECERET_KEY'] = 'RANDAM'
class Users(sql.Model):
__tablename__='users'
id = sql.Column(sql.Integer, primary_key=True, nullable=False,
default='')
name = sql.Column(sql.String(25),nullable=False, default='')
username = sql.Column(sql.String(25),nullable=False, default='')
email = sql.Column(sql.String(25), primary_key=True,nullable=False,
default='')
password = sql.Column(sql.String(100),nullable=False, default='')
reg_time = sql.func.current_timestamp()
online = sql.Column(sql.String(1),nullable=False, default='')
class friendgroup(sql.Model):
__tablename__='friendgroup'
group_id = sql.Column(sql.Integer,sql.ForeignKey('users.id'),
primary_key=True,nullable=False, default='')
fg_name = sql.Column(sql.String(25), primary_key=True, nullable=False,
default='')
owner_email = sql.Column(sql.String(25),sql.ForeignKey('users.email'),
primary_key=True, nullable=False,default='')
description = sql.Column(sql.String(25), nullable=False, default='')
class belong(sql.Model):
__tablename__ = 'belong'
group_id=sql.Column(sql.Integer,sql.ForeignKey('friendgroup.group_id')
,primary_key=True,nullable=False,default='')
email = sql.Column(sql.String(25),sql.ForeignKey('users.email'),
nullable=False, default='', primary_key=True)
owner_email = sql.Column(sql.String(25),
sql.ForeignKey('friendgroup.owner_email'),nullable=False,
default='', primary_key=True)
fg_name = sql.Column(sql.String(25),
sql.ForeignKey('friendgroup.fg_name'),nullable=False, default='',
primary_key=True)
sql.create_all()
app.run(debug=True)
I expect all these will be entered into the database but it shows error:
sqlalchemy.exc.OperationalError:
(MySQLdb._exceptions.OperationalError) (1005, 'Can\'t create table
test.friendgroup (errno: 150 "Foreign key constraint is
incorrectly formed")')
When I run SHOW ENGINE INNODB STATUS, it shows this error under the LATEST FOREIGN KEY ERROR section:
Cannot find an index in the referenced table where the referenced
columns appear as the first columns, or column types in the table and
the referenced table do not match for constraint. Note that the
internal storage type of ENUM and SET changed in tables created with
>= InnoDB-4.1.12, and such columns in old tables cannot be referenced by such columns in new tables.
We can disregard the stuff about ENUM and SET, and the type definitions between the two are exact, so that just leaves the issue about the index.
If you add index=True to the column definitions of Users.email and friendgroup.fg_name it provides an index that can be used for mysql to generate the foreign keys on and your tables should create.
However, I would advise a rethink of your primary keys your tables. You are defining each of those tables with an autoincrement primary key field, yet include other fields in a composite primary key. You don't need to do that. If you remove the non-autoincrement columns from the primary key and add a unique constraint on them instead, all your problems go away.
Additionally, by including the field friendgroup.owner_email in either the primary key or a unique constraint means that each user can only own a single friend group. Is that what you want? Similarly, having owner_email and fg_name in the primary key of the belong table would mean that only one user can belong to any group owned by a particular user.
If it helps, this is how I would put those models together. It resolves your issues with the foreign keys and uses relationship attributes instead of duplicating data like email addresses and group names across tables.
class Users(sql.Model):
__tablename__ = "users"
id = sql.Column(sql.Integer, primary_key=True)
name = sql.Column(sql.String(25), nullable=False)
username = sql.Column(sql.String(25), nullable=False)
email = sql.Column(sql.String(25), unique=True, nullable=False)
password = sql.Column(sql.String(100), nullable=False)
reg_time = sql.Column(
sql.TIMESTAMP, server_default=sql.func.current_timestamp()
)
online = sql.Column(sql.String(1), nullable=False, default="")
class friendgroup(sql.Model):
__tablename__ = "friendgroup"
group_id = sql.Column(
sql.Integer, sql.ForeignKey("users.id"), primary_key=True
)
fg_name = sql.Column(sql.String(25), unique=True, nullable=False)
owner_id = sql.Column(
sql.Integer, sql.ForeignKey("users.id"), nullable=False
)
description = sql.Column(sql.String(25), nullable=False, default="")
owner = sql.relationship("User")
class belong(sql.Model):
__tablename__ = "belong"
group_id = sql.Column(
sql.Integer, sql.ForeignKey("friendgroup.group_id"), primary_key=True
)
user_id = sql.Column(
sql.Integer, sql.ForeignKey("users.id"), primary_key=True
)
user = sql.relationship("User")
group = sql.relationship("friendgroup")
from django.db import models
class doctors(models.Model):
docid = models.AutoField(primary_key=True, unique=True) # Need autoincrement, unique and primary
name = models.CharField(max_length=35)
regid = models.CharField(max_length=15, default="")
photo = models.CharField(max_length=35, default="")
email = models.EmailField(default="")
phone = models.IntegerField(default=0, null=True)
qualifications = models.CharField(max_length=50, default="")
about = models.CharField(max_length=35, default="")
specialities = models.CharField(max_length=50, default="")
department = models.CharField(max_length=50, default="ENT")
fees = models.FloatField(default=300.0, null=True)
displayfee = models.IntegerField(default=0, null=True)
slotrange = models.CharField(max_length=50)
slotdurn = models.IntegerField(default=10, null=True)
breakrange = models.CharField(max_length=50, default="")
slotsleft = models.CharField(max_length=50, default="")
What I intended: If one of the fields like phone, fees, displayfee, or slotdurn is not specified, they should be filled in a default value. Unfortunately these are filled with an automatic value of NULL when I do the following:
from appointments.models import doctors
doc=doctors(name="Dr Joel", regid="12524", email="joel#mydomain.com")
doc.save()
I checked the sql created, and it is like this:
CREATE TABLE `appointments_doctors` (
`docid` int(11) NOT NULL,
`name` varchar(35) NOT NULL,
`regid` varchar(15) NOT NULL,
`photo` varchar(35) NOT NULL,
`email` varchar(254) NOT NULL,
`phone` int(11) DEFAULT NULL,
`qualifications` varchar(50) NOT NULL,
`about` varchar(35) NOT NULL,
`specialities` varchar(50) NOT NULL,
`department` varchar(50) NOT NULL,
`fees` double DEFAULT NULL,
`displayfee` int(11) DEFAULT NULL,
`slotrange` varchar(50) NOT NULL,
`slotdurn` int(11) DEFAULT NULL,
`breakrange` varchar(50) NOT NULL,
`slotsleft` varchar(50) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
It seems the default value I specified is being overridden by the Null value. I added the null because previously I was being prompted that these fields cannot be null, even when I had specified the default value.
Edit: After removing the float, my class looks like this:
class doctors(models.Model):
docid = models.AutoField(primary_key=True, unique=True) # Need autoincrement, unique and primary
name = models.CharField(max_length=35)
regid = models.CharField(max_length=15, default="")
photo = models.CharField(max_length=35, default="")
email = models.EmailField(default="")
phone = models.IntegerField(default=0)
qualifications = models.CharField(max_length=50, default="")
about = models.CharField(max_length=35, default="")
specialities = models.CharField(max_length=50, default="")
department = models.CharField(max_length=50, default="ENT")
fees = models.FloatField(default=300.0)
displayfee = models.IntegerField(default=0)
slotrange = models.CharField(max_length=50)
slotdurn = models.IntegerField(default=10)
breakrange = models.CharField(max_length=50, default="")
slotsleft = models.CharField(max_length=50, default="")
Migration script looks like this:
class Migration(migrations.Migration):
dependencies = [
('appointments', '0006_auto_20180726_0502'),
]
operations = [
migrations.AlterField(
model_name='doctors',
name='displayfee',
field=models.IntegerField(default=0),
),
migrations.AlterField(
model_name='doctors',
name='fees',
field=models.FloatField(default=300.0),
),
migrations.AlterField(
model_name='doctors',
name='phone',
field=models.IntegerField(default=0),
),
migrations.AlterField(
model_name='doctors',
name='slotdurn',
field=models.IntegerField(default=10),
),
]
But the generated sql still does not have the default values. How can I specify these in the model and have it migrated to sql? I'm using django 2.0.7 on python 3.6.5.
What is the correct way to create the model?