I'm reading someone else's Django code, using PostgreSQL, and this is something I don't understand.
It seems that, when this code defines a class from another, a foreign key to that class is created within this one. I don't really understand why there would be a connection between the two, seems like inheritance and foreign keys are completely different concepts.
Here's a bit of code, the class is Contractor, which inherits from auth.User - which is a custom class created elsewhere in the project.
class Contractor(lancer.auth.User):
a = models.xxxx
b = models.xxxx
....
After I syncdb on that, the database shows something like this,
CREATE TABLE lancer_contractor
(
user_ptr_id integer NOT NULL,
a integer,
b text NOT NULL,
....
CONSTRAINT lancer_contractor_pkey PRIMARY KEY (user_ptr_id ),
CONSTRAINT lancer_contractor_user_ptr_id_fkey FOREIGN KEY (user_ptr_id)
REFERENCES lancer_user (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED
)
From this SQL code I understand 2 things,
Somehow there's a foreign key created inside the Contractor table pointing to the User table
That foreign key is also the primary key for Contractor
After some testing with some other random classes I can confirm that this always happens. What is going on here? Why are foreign keys getting mixed up with inheritance?
Thanks!
Multi-table inheritance
Related
I am new to Django, and I am working on my models, but I don't know exactly how I am gonna represent the generalization relationship in Django, I was following the method of creating the superclass table and all the subclass tables while the subclass tables gonna include the primary key of the superclass table, should I represent that as the foreign key in all subclass tables in Django?
I want to have two foreign key for a model. One of these foreign key must create when something special happens. How can I write this and call it at a specific time? Can I write it as a function in model and call it in view when something special happens?
If this something special is when an specific object is manipulated then you can use django signals, otherwise if you want to handle it yourself you can set null=True, blank=True so the database can set the field to null and then you can create that object in one of your views functions and assign it to the related object.
Not sure what would be the use case for multiple Foreign Keys but in the question
One of these foreign key must create when something special happens
This looks like something that can be achieved using Django signals
https://docs.djangoproject.com/en/3.2/topics/signals/
It's especially useful when you would like to create a new User or modify the database on a certain change in the database
I have two models:
class Foo(Model):
special_id = IntegerField(primary_key=True)
class FooDetail(Model):
special_id = IntegerField(primary_key=True)
special_id comes from an outside source -- it's a foreign key into another database. Yes, Foo and FooDetail should be combined into a single model -- but assuming I can't -- can I create a related field between the two models such that I can use it in queries (like in values or select_related)?
I could add a ForeignKey('FooDetail') in Foo, but I'd be essentially storing the special_id twice.
If you want to use the ORM's features for related models, you should create a relationship (one-to-one in this case) between the two models. In one of the models you can (and should) then omit the special_id reference.
You can use the foreign key as a primary key in FooDetail, and if you keep special_id as a primary key in Foo, you'll be saving exactly the same type and amount of columns and data as in your example (namely one column in each that contains the relevant special_id).
What you get though is the benefit of a relationship and enforced integrity.
The only difference is that when you introduce a new special_id, you have to create Foo first to be able to point to it in FooDetail – hardly a big price to pay.
If you get a warning on setting the reference field to Foo to be the primary key then it might be that you defined it as a ForeignKey. You should define the field as a OneToOneField since you're dealing with a one-to-one relationship as noted above. The field is still technically a foreign key (= reference to the primary key of a row in another table) which is why I used this term; but it has a unique constraint that allows it to be used as a primary key.
I have a foreign key relationship between two tables UserProducts and Users in my database, with UserProducts having a UserID referencing the UserID in the Users table.
ALTER TABLE [dbo].[UserProducts] WITH CHECK ADD CONSTRAINT [FK_UserProducts_Users] FOREIGN KEY ([UserID])
REFERENCES [dbo].[Users] ([UserID])
GO
ALTER TABLE [dbo].[UserProducts] CHECK CONSTRAINT [FK_UserProducts_Users]
GO
The UserID column in the UserProducts table is part of a composite primary key with another column ProductID. There are also two additional DateTime columns, so Entity Framework does not treat UserProducts as a link table.
There is NO cascade delete on that foreign key above, nor did I set up anything to handle OnDelete on the Entity Framework foreign key association. Yet, when I delete a User entity from code, Entity Framework is taking the liberty of deleting the UserProducts associated with it by UserID. It is also generating a lot of SQL to do it: there is a separate DELETE per related record in the UserProducts table.
The code to perform the entity deletion is as follows:
using (var context = new LicensingRegistrationContext(_csb))
{
context.Database.Log = a => _logger.Trace(a);
var dbUser = GetUserDbSetWithIncludes(context)
.Where(a => a.UserID == user.Id).Single();
context.DbUsers.Remove(dbUser);
//TODO(MRL): Um...how are the dbUserProducts being removed???
context.SaveChanges();
}
How is this happening? In EF 4 I am pretty sure EF never took this liberty of doing this: you HAD to load and then delete all related entities manually in code.
Thanks
Entity framework by default has a
OneToManyCascadeDelete
convention. Here is the link http://msdn.microsoft.com/en-us/library/system.data.entity.modelconfiguration.conventions.onetomanycascadedeleteconvention(v=vs.113).aspx
So entity framework cascade deletes the one to many relationship by default.
You can disable this by disabling the convention or explicitly disabled it for this relationship via the fluent API.
I found this on MSDN and I believe this is what is happening:
When a primary key of the principal entity is also part of the primary key of the dependent entity, the relationship is an identifying relationship. In an identifying relationship the dependent entity cannot exist without the principal entity. This constraint causes the following behaviors in an identifying relationship: Deleting the principal object also deletes the dependent object. This is the same behavior as specifying OnDelete Action="Cascade" in the model for the relationship. Removing the relationship deletes the dependent object. Calling the Remove method on the EntityCollection marks both the relationship and the dependent object for deletion.
This is what is happening in my model where the UserComponent table has a composite primary key: UserID, ComponentID and the UserID column is a foreign key to the UserID in the User table.
i want to use eclipselink to partition my database. for performance reasons i will have one table (entity A) replicated to all nodes and one table (entity B) that is hash partitioned over all nodes.
Since every A has a one-to-one relationship with a B entity eclipseLink creates a foreign key constraint on a column of the "A"-Table. because of the different partitioning mechanisms this contraint will fail for a lot of entries in A.
currently the properties of the entities can change dayly so i wouldn't want to miss ddl-generation for tests and development.
Is it possible to tell eclipse link not to create this specific foreign key? all foreign keys?
the current test database is an in memory hsqldb. is it possible to tell the db to ignore foreign key constraints?
You can use your own DDL script to create the tables, or just drop the constraint with your own script or native SQL query.
You can disable all constraints by subclassing your database platform class (and using "eclipselink.target-database" with your subclass).
If there is no foreign key there is no relationship.
Alternatively, you could mark the property b in class A as transient so it does not get managed by JPA. It means that you will have to retrieve the appropiate b value yourself.
Also, you could just try to make field b nullable (if JPA supports null=true for a One-to-One relationship, I am not sure) and check what happens.