With Doctrine 2, if you have (for example) a tournament with 2 sponsors (ids 1 and 2), and a user then removes sponsor 1 and adds sponsor 3 in one action (like from a list), what is the best way to sync the changes to the database, so that there is only one delete query and one insert query?
The UI will provide me with the new set of ids, for example "1,3", and I need to use that to determine what has been added, and what has been removed.
I had the same situation for linking books to authors. If I wanted to update the author list (via pivot aka linking table) I would just remove all author ids from the pivot table where book_id = 1, then add the new list of authors. This way you don't have to introduce complex logic to determine diffs. Also, it's best if this is wrapped in a transaction.
Related
I have a nested set category table developed with the PHP ORM Doctrine and I would like to port it to a Django app.
I started porting it to django-treebeard, but I am having difficulties and I am not sure it can work.
The original table had the needed fields lft, rgt and depth, so I added the tree_id field.
I also had a foreign key to Accounts with one tree/account. Thus the table hold multiple independent trees that are not under a common root, with the lft and depth columns starting at 1 for each tree. So basically one nested set for each account in the table.
I can add nodes to a tree just fine, but when I call the get_last_child method, I get nodes from other accounts.
Does anyone know if there is a way to use treebeard, mptt or any other package without having to restructure the trees?
I made some progress by adding the correct tree_id as a sequential number by account_id, which fixed some of the issues, with the query:
UPDATE category c,
(SELECT id, DENSE_RANK() OVER (ORDER BY account_id) AS seq
FROM category ) tree_rank
SET c.tree_id = tree_rank.seq
WHERE c.id = tree_rank.id;
Now trying to get the admin to work.
I'm currently designing my data base using postgresql with Django and I was wondering: What is best practice - having several instances of the same model with the same value or a many to many relation ship?
Let me elaborate. Let's say I'm designing a store. The store sells items. Items can have one or many statuses (e.g. ordered, shipped, delivered, paid, pre-ordered etc.).
What would be a better practice:
Relating the items to their status via a many-to-many relationship, which will lead to one status having hundreds of thousand and later millions of relations? Will so many relations become problematic?
Or is it better for each item to have a foreignkey to their statuses? So that each status only has one item. And if I would like to query all the items that have the same status (e.g. shipped), I would have to iterate over all statuses with a common name.
What would be better, especially for the long term?
I would recommend going with a many-to-many relationship.
Hundreds of thousands or even millions of relations should not be a problem. The many-to-many relationship is stored as a table with id, item_id, status_id. SQL will be performant at querying the table either by status_id or item_id even if the table gets big. This is exactly the kind of thing it was built to handle.
Let me elaborate. Let's say I'm designing a store. The store sells
items. Items can have one or many statuses (e.g. ordered, shipped,
delivered, paid, pre-ordered etc.).
If many people will have this many itens you should use manytomany relations, better let django handle with this "third table", since this table just hold ids you can interate over them using reverse lookup, i do prefer using many to many instad of simple foreignkeys.
In your case, who you will handle when your User will hold many itens? like what if my User buy one potato and 2 bananas? you will duplicate the tuple in your User Table to tell "here he have the potato and in this second one he have the banana"? so you will be slave of Disctinct attribute while you still dirtying your main table User
...
class Item(models.Model):
...
class User(models.Model):
items = models.ManyToMany(Item)
So when i query my Item and my User will only bring attributes related to them... while if you use item inside of User Model you will have multiple instances of same user.
So instead of use User.items.all() you will use User.objects.filter(id=id)and them items = [user.item for user in User.objects.filter(id=id)]
Look how complex this get and makeing your database so dirty
I have a model class in my django project:
*user_id
*amount
*net_balance
*created_on
I have a list of user_ids(let's say 3). I need to get the last row for each user_id and then do some operation and create a new row for each user id. How do this efficiently. I can certainly do 6 transactions (if there are 3 items in list of userids).
If you want the most recent entry then
YourModel.objects.filter(user=user_id).latest('created_on')
If I understand your question correctly then you need to get all the user_ids (presumably you have a separate User model?) and then loop through them - for each user getting the most recent entry and then create the new row.
You need 1 select (at least) for all the records you interested and 1 insert query for each record returned.
The select query can be generated by ORM abilities (aggregation) or you can use raw SQL if you fill comfortable. If you use PostgreSQL, you can use distinct ability (I recommended) as:
Model.objects.order_by('user_id', '-created_on').distinct('user_id')
or you can use aggregation abilities as:
Model.objects.filter(user_id__in=[1,2,3]).values('user_id', 'created_on').annotate(last_row=Max('created_on')).filter(created_on=F('last_row'))
The correct answer depends on your Django version and database. But there are lots of good features in Django to achieve this kind of stuffs.
I'm having some problems with the following...
I have a table with phone numbers. I want to use the same table for both users and companies. A user can have several phone numbers and a company too. So i want a One to many unidirectional relationship with two different join tables. One linking phone numbers to users, the other linking phone numbers to companies.
This is solution following the doctrine2 manual chapter 5.9 found here: (click)
My users entity holds this code:
/** #ORM\ManyToMany(targetEntity="Application\Entity\PhoneNumber")
* #ORM\JoinTable(name="user_phone_number_linker",
* joinColumns={#ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="phone_number_id", referencedColumnName="id")}
* )
*/
protected $phone_numbers;
I use a unidirectional one to many because the thing is I can't make a bidirectional one because if I refer back to the user I cannot use the same phone number entity class for the company. Now it all works fine, but when I delete a phone number I get the following error:
An exception occurred while executing 'DELETE FROM phone_number WHERE id = ?' with params {"1":1}:
SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails (database/user_phone_number_linker, CONSTRAINT user_phone_number_linker_ibfk_11 FOREIGN KEY (phone_number_id) REFERENCES phone_number (id))
If I set the ON DELETE CASCADE value manually in the database it works fine, but this is not the idea of using doctrine2 and I think I should be able to solve it within the code without going to my phpMyAdmin panel. Somehow the cascading from the phone number towards the join table should be initiated on deletion, but without making a reference back to the join table from the phone_number entity.
Hope someone smart can help me solve this.
EDIT
In the meantime I learned a lot more about Doctrine2 and reviewing my old question made me realize that this is not a correct way to store several phoneNumbers in one table in the first place. To be able to store user phone numbers and company phone numbers in the same table I should use table inheritance with a discriminator column. The column should hold some user/company discriminator.
Because of this column the doctrine ORM will "know" if that phoneNumber is actually a user or a company phone-number. I need to make two different entity definitions following the single table inheritance mapping principles from the doctrine 2 specs.
One class UserPhoneNumber will have a many-to-one relationship with User the other called CompanyPhoneNumber a one-to-many relationship with Company. I don't necessarily need a join column, the user_id or company_id columns can be in the phone-number table. In the User class the Company association is omitted and in the Company class the User association is omitted (database should allow null values for those columns).
If I do use a join table it is according to the one-to-many unidirectional with join table description in the Doctrine2 specs
READ MORE
Otherwise you can also read more on associations and cascade issues here on this elaborate Doctrine2 in depth website.
As you said, your relation is unidirectional. You've defined a relation from Users to PhoneNumbers. The cascade delete will work when you delete a User, it will remove all rows in user_phone_number_linker because that's the relation you've defined.
If you want to do it the other way, you've got to create a relation from PhoneNumbers to Users. Doctrine needs it to work for you. But you have the problem that the entity is shared by two other entities, Users and Companies.
Keep in mind that entities are objects, not tables. So you could try to create two entities to the same table, one named PhoneNumberUsers and the other PhoneNumberCompanies. This way you'll be able to create the needed relation to do the cascade delete. I haven't tested by myself, but I think it could work.
By the way, you can remove the oncascade parameter on the Users' entity join table. I've the same scenario as you with users and roles, and I haven't used it. I think it's only needed when you want to cascade from entity to entity. I'm not sure about that, but that's what I've been experiencing until now.
My bad,
The phone number user relationship is regarded a Many-To-Many relationship, so if want to remover the phone number I should not only remove the phone number itself, but I have to explicitly remove the phone number from the user as well. So in the Controller like this:
// Remove the phone number user connection from the database
$user->removePhoneNumber($phone_number);
// Remove the phone number from the database
$em->remove($phone_number);
I just thought the unique restriction which makes the relationship to a unidirectional One-To-Many would be enough to make doctrine take care of it. That was not correct.
I want to create a model that will order its children models in the appropriate way. For instance, a Book has many Chapters, but the Chapters have to be in a specific order.
I assume that I need to put an IntegerField on the Chapter model that specifies the order of the Chapters like the following question suggests: Ordered lists in django
My main issue is that whenever I want to insert a new Chapter in between two existing chapters or reorder them in any way, I have to update (almost) every Chapter in the Book. Is there a way (perhaps in the Django Admin, which I'm using) to avoid having to manually change every index on every Chapter whenever I change the order?
I'm not a big fan of creating a "Linked List" style model, as proposed in the above-linked question, as I am under the impression that's not good practice for database creation.
What is the "right" way to model this relationship?
The answer you alluded to was probably the best way to handle this efficiently. Probably requiring a raw SQL statement UPDATE Chapter SET order = order + 1 WHERE book_id = <id_for_book> AND order <= <insert_index_location>. For Django 1.1+: You could use F() to write this in a single line as the following, but it might still be O(n) queries under the hood, using transactions.
Book.objects.get(id=<id_of_book>).chapter_set.filter(order__gt=<place_to_insert>).update(order=F('order')+1)
Use a float instead of an integer to avoid your problem of updating multiple items when you insert between two.
So if you want to insert an item between item 42 and item 43, you can give it an order value halfway between the two (42.5), and you won't have to update any other items.
Insert z between x and y...
z.order = (y.order - x.order) / 2 + x.order