1.
" " None Django, :
Q(profilearmor__profile=None)
, " ". ,
self.armor_category.armor_set.filter(
Q(profilearmor__profile=self.request.user.profile) |
Q(profilearmor__profile=None))
, self.request.user, . Duck Helm: - ( ) .
2.
, , : SQL:
SELECT `myapp_armor`.`id`, `myapp_armor`.`armor_category_id`, `myapp_armor`.`name`,
COUNT(`myapp_profilearmor`.`id`) AS `profile_armor_count`
FROM `myapp_armor`
LEFT OUTER JOIN `myapp_profilearmor`
ON `myapp_armor`.`id` = `myapp_profilearmor`.`armor_id`
AND `myapp_profilearmor`.`profile_id` = %s
WHERE `myapp_armor`.`armor_category_id` = %s
GROUP BY `myapp_armor`.`id`, `myapp_armor`.`armor_category_id`, `myapp_armor`.`name`
, - Django, , . ORM SQL-. :
sql = '''
SELECT `myapp_armor`.`id`, `myapp_armor`.`armor_category_id`, `myapp_armor`.`name`,
COUNT(`myapp_profilearmor`.`id`) AS `profile_armor_count`
FROM `myapp_armor`
LEFT OUTER JOIN `myapp_profilearmor`
ON `myapp_armor`.`id` = `myapp_profilearmor`.`armor_id`
AND `myapp_profilearmor`.`profile_id` = %s
WHERE `myapp_armor`.`armor_category_id` = %s
GROUP BY `myapp_armor`.`id`, `myapp_armor`.`armor_category_id`, `myapp_armor`.`name`
'''
armor = Armor.objects.raw(sql, [self.request.user.profile.id, self.armor_category.id])
for armor_item in armor:
print('{:14}{}'.format(armor_item.name, armor_item.profile_armor_count))
:
>>> helmets = ArmorCategory.objects.get(id=1)
>>> profile = Profile.objects.get(id=1)
>>> armor = Armor.objects.raw(sql, [profile.id, helmets.id])
>>> for armor_item in armor:
... print('{:14}{}'.format(armor_item.name, armor_item.profile_armor_count))
...
Dragon Helm 0
Duck Helm 1
Needle Helm 0
3.
Django:
armor = self.armor_category.armor_set.filter(
Q(profilearmor__profile=self.request.user.profile) |
Q(profilearmor__profile=None)
).annotate(profile_armor_count=Count('profilearmor__id'))
, , SQL, , queryset query :
>>> from django.db.models import Q
>>> helmets = ArmorCategory.objects.get(name='Helmets')
>>> profile = Profile.objects.get(id=1)
>>> print(helmets.armor_set.filter(Q(profilearmor__profile=profile) |
... Q(profilearmor__profile=None)
... ).annotate(profile_armor_count=Count('profilearmor__id')).query)
SELECT `myapp_armor`.`id`, `myapp_armor`.`armor_category_id`, `myapp_armor`.`name`,
COUNT(`myapp_profilearmor`.`id`) AS `profile_armor_count`
FROM `myapp_armor`
LEFT OUTER JOIN `myapp_profilearmor`
ON (`myapp_armor`.`id` = `myapp_profilearmor`.`armor_id`)
LEFT OUTER JOIN `myapp_profile`
ON (`myapp_profilearmor`.`profile_id` = `myapp_profile`.`id`)
WHERE (`myapp_armor`.`armor_category_id` = 1
AND (`myapp_profilearmor`.`profile_id` = 1
OR `myapp_profile`.`id` IS NULL))
GROUP BY `myapp_armor`.`id`, `myapp_armor`.`armor_category_id`, `myapp_armor`.`name`
ORDER BY NULL
? SQL, 5. .
4. SQL-
, , SQL ( , ). , :
mysql> SELECT * FROM myapp_armorcategory;
+----+---------+---------+
| id | name | slug |
+----+---------+---------+
| 1 | Helmets | helmets |
| 2 | Suits | suits |
+----+---------+---------+
2 rows in set (0.00 sec)
mysql> SELECT * FROM myapp_armor;
+----+-------------------+-------------+
| id | armor_category_id | name |
+----+-------------------+-------------+
| 1 | 1 | Dragon Helm |
| 2 | 1 | Duck Helm |
| 3 | 1 | Needle Helm |
| 4 | 2 | Spiky Suit |
| 5 | 2 | Flower Suit |
| 6 | 2 | Battle Suit |
+----+-------------------+-------------+
6 rows in set (0.00 sec)
a JOIN 12 2 6 :
mysql> SELECT * FROM myapp_armorcategory JOIN myapp_armor;
+----+---------+---------+----+-------------------+-------------+
| id | name | slug | id | armor_category_id | name |
+----+---------+---------+----+-------------------+-------------+
| 1 | Helmets | helmets | 1 | 1 | Dragon Helm |
| 2 | Suits | suits | 1 | 1 | Dragon Helm |
| 1 | Helmets | helmets | 2 | 1 | Duck Helm |
| 2 | Suits | suits | 2 | 1 | Duck Helm |
| 1 | Helmets | helmets | 3 | 1 | Needle Helm |
| 2 | Suits | suits | 3 | 1 | Needle Helm |
| 1 | Helmets | helmets | 4 | 2 | Spiky Suit |
| 2 | Suits | suits | 4 | 2 | Spiky Suit |
| 1 | Helmets | helmets | 5 | 2 | Flower Suit |
| 2 | Suits | suits | 5 | 2 | Flower Suit |
| 1 | Helmets | helmets | 6 | 2 | Battle Suit |
| 2 | Suits | suits | 6 | 2 | Battle Suit |
+----+---------+---------+----+-------------------+-------------+
12 rows in set (0.00 sec)
, , . , , , :
mysql> SELECT * FROM myapp_armorcategory JOIN myapp_armor
ON myapp_armorcategory.id = myapp_armor.armor_category_id;
+----+---------+---------+----+-------------------+-------------+
| id | name | slug | id | armor_category_id | name |
+----+---------+---------+----+-------------------+-------------+
| 1 | Helmets | helmets | 1 | 1 | Dragon Helm |
| 1 | Helmets | helmets | 2 | 1 | Duck Helm |
| 1 | Helmets | helmets | 3 | 1 | Needle Helm |
| 2 | Suits | suits | 4 | 2 | Spiky Suit |
| 2 | Suits | suits | 5 | 2 | Flower Suit |
| 2 | Suits | suits | 6 | 2 | Battle Suit |
+----+---------+---------+----+-------------------+-------------+
6 rows in set (0.08 sec)
. , , . :
mysql> INSERT INTO myapp_armorcategory (name, slug) VALUES ('Arm Guards', 'armguards');
Query OK, 1 row affected (0.00 sec)
(SELECT * FROM myapp_armorcategory JOIN myapp_armor ON myapp_armorcategory.id = myapp_armor.armor_category_id;), : , JOIN. , , , : a LEFT OUTER JOIN:
mysql> SELECT * FROM myapp_armorcategory LEFT OUTER JOIN myapp_armor
ON myapp_armorcategory.id = myapp_armor.armor_category_id;
+----+------------+-----------+------+-------------------+-------------+
| id | name | slug | id | armor_category_id | name |
+----+------------+-----------+------+-------------------+-------------+
| 1 | Helmets | helmets | 1 | 1 | Dragon Helm |
| 1 | Helmets | helmets | 2 | 1 | Duck Helm |
| 1 | Helmets | helmets | 3 | 1 | Needle Helm |
| 2 | Suits | suits | 4 | 2 | Spiky Suit |
| 2 | Suits | suits | 5 | 2 | Flower Suit |
| 2 | Suits | suits | 6 | 2 | Battle Suit |
| 3 | Arm Guards | armguards | NULL | NULL | NULL |
+----+------------+-----------+------+-------------------+-------------+
7 rows in set (0.00 sec)
, , NULL .
5.
, :
mysql> INSERT INTO myapp_profile (name) VALUES ('user1');
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO myapp_profilearmor (profile_id, armor_id) VALUES (1, 2);
Query OK, 1 row affected (0.00 sec)
, , :
mysql> SELECT `myapp_armor`.*, `myapp_profilearmor`.*, T5.*
FROM `myapp_armor`
LEFT OUTER JOIN `myapp_profilearmor`
ON (`myapp_armor`.`id` = `myapp_profilearmor`.`armor_id`)
LEFT OUTER JOIN `myapp_profile` T5
ON (`myapp_profilearmor`.`profile_id` = T5.`id`)
WHERE `myapp_armor`.`armor_category_id` = 1;
+----+-------------------+-------------+------+------------+----------+------+-------+
| id | armor_category_id | name | id | profile_id | armor_id | id | name |
+----+-------------------+-------------+------+------------+----------+------+-------+
| 1 | 1 | Dragon Helm | NULL | NULL | NULL | NULL | NULL |
| 2 | 1 | Duck Helm | 1 | 1 | 1 | 1 | user1 |
| 3 | 1 | Needle Helm | NULL | NULL | NULL | NULL | NULL |
+----+-------------------+-------------+------+------------+----------+------+-------+
3 rows in set (0.04 sec)
, (myapp_profilearmor.profile_id = 1 OR T5.id IS NULL), .
:
mysql> INSERT INTO myapp_profile (name) VALUES ('user2');
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO myapp_profilearmor (profile_id, armor_id) VALUES (2, 1);
Query OK, 1 row affected, 1 warning (0.09 sec)
:
mysql> SELECT `myapp_armor`.*, `myapp_profilearmor`.*, T5.*
FROM `myapp_armor`
LEFT OUTER JOIN `myapp_profilearmor`
ON (`myapp_armor`.`id` = `myapp_profilearmor`.`armor_id`)
LEFT OUTER JOIN `myapp_profile` T5
ON (`myapp_profilearmor`.`profile_id` = T5.`id`)
WHERE `myapp_armor`.`armor_category_id` = 1;
+----+-------------------+-------------+------+------------+----------+------+-------+
| id | armor_category_id | name | id | profile_id | armor_id | id | name |
+----+-------------------+-------------+------+------------+----------+------+-------+
| 1 | 1 | Dragon Helm | 2 | 2 | 1 | 2 | user2 |
| 2 | 1 | Duck Helm | 1 | 1 | 2 | 1 | user1 |
| 3 | 1 | Needle Helm | NULL | NULL | NULL | NULL | NULL |
+----+-------------------+-------------+------+------------+----------+------+-------+
3 rows in set (0.00 sec)
, (myapp_profilearmor.profile_id = 2 OR T5.id IS NULL), 1 3. 2 .
, , Q(profilearmor__profile=None) T5.id IS NULL, , ( ) ProfileArmor.
6.
, , count() :
if self.armor_category.armor_set.filter(
profilearmor__profile=self.request.user.profile
).count() == 0:
, , , exists() .
ManyToManyField Armor, ? Armor :
Q(profilearmor__profile = ...)
, , :
Q(profile = ...)
7.
. Django , .