Django: Limit QuerySet to user input (checkboxes) - django

My question is similar to Django Advanced Filtering but I need another approach:
Abstract:
Tables: manufacturer, supplies
Manufacturers have multiple supplies (1 or 0 in "supply" table)
I have a HTML form with multiple (20+ checkboxes) which should limit the queryset with AND queries (so standard). The HTML checkbox names equal MySQL field names. My table looks like this:
mysql> explain supply;
+----------------------+------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------------+------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| manufacturer_id | int(11) | NO | MUL | NULL | |
| supply1 | tinyint(1) | NO | | NULL | |
| supply2 | tinyint(1) | NO | | NULL | |
| supply3 | tinyint(1) | NO | | NULL | |
| [...] | tinyint(1) | NO | | NULL | |
| supply20 | tinyint(1) | NO | | NULL | |
Now in pseudo SQL, I'd like to:
User selected checkboxes supply2 and supply14: SELECT * FROM supply WHERE supply2 = 1 AND supply14 = 1;
User selected checkboxes supply1, supply9 and supply18: SELECT * FROM supply WHERE supply1 = 1 AND supply9 = 1 AND supply18 = 1;
I'm pretty sure I need some QuerySet with kwargs, but I'm unable to construct the view for my needs (still learning Django).

I wonder if the data model here couldn't use some tweaking? You might want to have a supply table with twenty rows and an intermediate table connecting them (that is a ManytoMany(Supply) or something like that). Then you could just have a multi select field, rather than 20 check boxes (unless you really need them for some other reason).
If you need to add another supply, it's simply adding another row, rather than a schema migration.

supplies = Supply.objects.filter( supply1 = 1 )
And if you want to filter again:
supplies = supplies.filter(supply2 = 1)
The filter() method returns a QuerySet, so you can chain as many filter() calls as you like.

Related

How to use prefetch_related to retrieve multiple rows similar to SQL result

I’ve a question about the usage of prefetch_related. Based on my understanding I need to use prefetch_related for reverse foreign key relationships
As an example I have a User(id, name) model and SchoolHistory(id, start_date, school_name, user_id[FK user.id]) model. A user can have multiple school history records.
If I’m querying the database using the following SQL query:
SELECT
user.id,
name,
start_date,
school_name
FROM user
INNER JOIN school_history ON school_history.user_id = user.id
the expected result would be:
| User ID | Name | Start Date | School |
| 1 | Human | 1/1/2022 | Michigan |
| 1 | Human | 1/1/2021 | Wisconsin |
| 2 | Alien | | |
This is the current result that I’m getting instead with ORM and a serializer:
| User ID | Name | school_history
| 1 | Human | [{start_date:1/1/2022 , school:Michigan}, {start_date:1/1/2021 , school:Wisconsin}] |
| 2 | Alien | [] |
This is the ORM query that I’m using:
User.objects.prefetch_related(
Prefetch(
‘school_history’
query_set=SchoolHistory.objects.order_by(‘start_date’)
)
)
Is there a way for the ORM query to have a similar result as SQL? I want multiple rows if there are multiple schools associated with that user

How to add "description" for a column in Postgres DB using the corresponding Django model?

For e.g., in this table, I'd like to be able add the "description" text at the Django ORM layer and have it reflected at the database level.
test=# \d+ django_model
Table "public.django_model"
Column | Type | Modifiers | Description
--------+---------+-----------+-------------
i | integer | |
j | integer | |
Indexes:
"mi" btree (i) - Tablespace: "testspace"
"mj" btree (j)
Has OIDs: no
I suppose you can't do it. Here's the https://code.djangoproject.com/ticket/13867 request. Closed 6 ya as "Won't do".
You still can use postgres COMMENT extension, eg:
t=# create table t (i int, t text);
CREATE TABLE
Time: 12.068 ms
t=# comment on column t.i is 'some description';
COMMENT
Time: 2.994 ms
t=# \d+ t
Table "postgres.t"
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
--------+---------+-----------+----------+---------+----------+--------------+------------------
i | integer | | | | plain | | some description
t | text | | | | extended | |

Some TextFields created in database with NOT NULL YES/NO

I have the following Model:
class SystemMessage(Model):
subject = TextField(default=None)
message = TextField(default=None)
And the following output from explain
| id | int(11) | NO | PRI | NULL | auto_increment |
| language_code | varchar(5) | NO | | NULL | |
| subject | longtext | NO | | NULL | |
| message | longtext | YES | | NULL | |
I have no outstanding migrations or makemigrations
Is there any reason why message is NULLable but subject is not? I would like both to be NOT NULLable.
I'm provided a default value for each field to ensure IntegrityError when saving the strings with no value.

Update Autonumber field after DELETE query

INTRODUCTION AND RELEVANT INFORMATION:
I have MS ACCESS 2007 database that I edit using ADO and C++.
PROBLEM:
My problem is that primary key also represents an ordinal number of the record, and after deletion, it should be properly updated. Primary key is of autonumber type.
Here is an example of what I am talking about:
| #PK | Other data ... |
| 1 | ... |
| 2 | ... |
| 3 | ... |
| 4 | ... |
| 5 | ... |
Now if I delete the 3rd record I get the following problem:
| #PK | Other data ... |
| 1 | ... |
| 2 | ... |
| 4 | ... |
| 5 | ... |
but I should get the following result:
| #PK | Other data ... |
| 1 | ... |
| 2 | ... |
| 3 | ... | // edited to reflect the change ( previous value was 4 )
| 4 | ... | // edited to reflect the change ( previous value was 5 )
If I delete last record and then insert new one I get this result:
| #PK | Other data ... |
| 1 | ... |
| 2 | ... |
| 3 | ... |
| 4 | ... |
| 6 | ... | // this should be 5
QUESTIONS:
Is there a way for me to programmatically update the autonumber field after I perform the DELETE query ?
EDIT:
Since I am aware this is a bad practice, I would prefer adding new field that should be ordinal number so my table can look like this:
| #PK | Ordinal | Other data ... |
| 1 | 1 | ... |
| 2 | 2 | ... |
| 4 | 3 | ... |
| 5 | 4 | ... |
but I would prefer it to update itself automatically. If this is not possible, I would prefer to update the field with SQL query after I perform the deletion.
Thank you.
Best regards.
It is possible, but not the right way. Primary keys are used for relationships, so if you change the values, you need to update all related tables. Even if you currently don't have any related tables, you still should consider adding a separate field for the order, otherwise you may face the same problem in the future when you want to add related tables.
EDIT To answer your question:
Is there a way to add another field that would represent ordinal number and will automatically increment after inserting new record?
If you set it to autonumber, it will automatically increment, but you will not be able to modify it. You can set it to number and when you insert, you use SELECT MAX(oredinal) + 1 FROM mytable to increment it.
For MS Access use
ALter Table Customer alter column CustomerID Counter(1,1)
For Sql Server
DBCC CHECKIDENT (orders, RESEED, 0)
This will set the value of the next ID to be 1, you can use above command.
Ref URL# http://www.howtogeek.com/howto/database/reset-identity-column-value-in-sql-server/
I have decided to add a new field in my table that will hold the ordinal number of the record.
If we assume the field is named OrdinalNumber then the following solution worked for me:
// when inserting record, I just had to add COUNT( PK ) + 1
INSERT INTO MyTable ( OrdinalNumber , ... ) SELECT COUNT( PK ) + 1 , ...
from MyTable ;
// when deleting, I had to perform following two queries :
DELETE from MyTable where PK = ? ;
// decrement all the successors ordinal number by one
UPDATE MyTable set OrdinalNumber = ( OrdinalNumber - 1 ) where ( PK > ? );
Everything seem to work well. I wish there was an easier way though...
Thanks everyone for helping. I have upvoted all the answers.

ERROR 1452 (23000): Cannot add or update a child row

I have the following database and when I try to run the query that has been shown below I get the error that says Cannot add or update a child row. I do not understand why am I getting this error.
The object_id that I am entering (327) exists in the database. I have tried this with other object_ids as well and the same error comes up. What is happening here?
like_objects
+-------------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------+------+-----+---------+----------------+
| object_id | int(11) | NO | MUL | NULL | |
| id | int(11) | NO | PRI | NULL | auto_increment |
| user_id | int(11) | NO | MUL | NULL | |
+-------------+---------+------+-----+---------+----------------+
objects
+--------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+--------------+------+-----+---------+----------------+
| object_name | longtext | NO | | NULL | |
| object_desc | longtext | NO | | NULL | |
| id | int(11) | NO | PRI | NULL | auto_increment |
| likes | int(11) | NO | | NULL | |
+--------------+--------------+------+-----+---------+----------------+
Here's the query and the error it produces:
insert into like_objects (object_id,user_id) values (327,1)
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails
(`test_db`.`like_objects`, CONSTRAINT `object_id_refs_id_57f96810` FOREIGN KEY (`object_id`)
REFERENCES `objects` (`id`))
This is very strange because I have used a similar like logic for another table and it is working absolutely fine.
Important I have obtained objects table from a mysqldump. Initially the objects table was created form PhpMyAdmin and the like_objects table has been created by the django models
I have figured out what the problem was. As I have posted in my question that the objects table was created using phpmyadmin and then dumped into my database which is part of a django project.
So the storage engine of the initially created table was MyISAM, but the tables created by django were having storage engine innodb. So as result whenever I tried to insert an object in the like_objects table which referenced the objects table there was this incompatibility of the the storage types.
This link helped me to find out what was the storage engine for my table and then I changed the MyISAM engine to innodb using the belwo given command and it is working fine.
ALTER TABLE products ENGINE = innodb