कई से कई
कई (to, through), आवश्यक तर्क के साथ और वैकल्पिक के माध्यम से, लक्ष्य और संबंधपरक नमूना कक्षाएं लेता है।
Sqlalchकॉलम और प्रकार स्वचालित रूप से लक्ष्य नमूना से प्राप्त किए जाते हैं।
- Sqlalchकॉलम: लक्ष्य नमूना प्राथमिक कुंजी कॉलम के लिए कक्षा
- प्रकार (for pydantic): लक्ष्य का प्रकार नमूना
नमूना परिभाषित करें
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 | from typing import List, Optional
import databases
import ormar
import sqlalchemy
DATABASE_URL = "sqlite:///test.db"
ormar_base_config = ormar.OrmarConfig(
database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData()
)
class Author(ormar.Model):
ormar_config = ormar_base_config.copy(tablename="authors")
id: int = ormar.Integer(primary_key=True)
first_name: str = ormar.String(max_length=80)
last_name: str = ormar.String(max_length=80)
class Category(ormar.Model):
ormar_config = ormar_base_config.copy(tablename="categories")
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=40)
class Post(ormar.Model):
ormar_config = ormar_base_config.copy(tablename="posts")
id: int = ormar.Integer(primary_key=True)
title: str = ormar.String(max_length=200)
categories: Optional[List[Category]] = ormar.ManyToMany(Category)
author: Optional[Author] = ormar.ForeignKey(Author)
|
नमूना डेटा बनाएँ:
| गुइडो = लेखक का इंतजार करें। (first_name = "guido", last_name = "Van Rossum")
पोस्ट = प्रतीक्षा करें .(शीर्षक = "हैलो, एम 2 एम", लेखक = गुइडो)
समाचार = श्रेणी का इंतजार करें (name = "News")
|
उलटा संबंध
विदेशी कुंजी क्षेत्र स्वचालित रूप से रिश्ते के रिवर्स साइड को पंजीकृत करता है।
डिफ़ॉल्ट रूप से, यह बच्चा है (source) नमूना नाम + s, जैसा कि निम्नलिखित कोड स्निपेट में पोस्ट में है:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 | कक्षा श्रेणी (ormar. Model):
ormar_config = base_ormar_config (टेबलनाम = "श्रेणियाँ")
आईडी: int = ormar। पूर्णांक (primary_key = True)
नाम: str = ormar। स्ट्रिंग (max_length = 40)
क्लास पोस्ट (ormar. Model):
ormar _ config = आधार _ ormar _ config कॉपी ()
आईडी: int = ormar। पूर्णांक (primary_key = True)
शीर्षक: str = ormar। स्ट्रिंग (max_length = 200)
श्रेणियां: वैकल्पिक [सूची [श्रेणी]] = ormar। MTo(Category)
# कुछ नमूना डेटा बनाएं
पोस्ट = प्रतीक्षा करें .(शीर्षक = "हैलो, एम 2 एम")
समाचार = श्रेणी का इंतजार करें (name = "News")
प्रतीक्षा कर रहा है।
# अब आप दोनों पक्षों से क्वेरी और एक्सेस कर सकते हैं:
post_check = .select_related ("categories").get ()
पोस्ट _ चेक श्रेणियों का आरोप लगाएं [0] == समाचार
ऑटो पंजीकृत रिवर्स साइड के माध्यम से #query
श्रेणी _ जाँच = श्रेणी ("posts").get ()
श्रेणी _ चेक पोस्ट डालें [0] == पोस्ट
|
माता-पिता से संबंधित वस्तुओं का प्रबंधन करने के लिए रिवर्स रिलेशनशिप एपीआई को उजागर करते हैं।
संबंधित नाम
डिफ़ॉल्ट रूप से, सहसंबंध नाम उसी तरह उत्पन्न होता है जैसे विदेशी कुंजी संबंध (class.name () +'), लेकिन आप सहसंबंध नाम पैरामीटर प्रदान करके इस नाम को भी ओवरराइड कर सकते हैं:
| श्रेणियां: वैकल्पिक [संघ [श्रेणी, सूची [श्रेणी]] = ormar। MTo(
श्रेणी, through=PostCategory संबंधित _ नाम = "नई _ श्रेणियां"
)
|
!!!चेतावनी जब आप एक ही नमूना के लिए कई संबंधों की आपूर्ति करते हैं, तो अन्यथा संबंधित \ _ नाम अब आपके लिए स्वचालित रूप से उत्पन्न नहीं हो सकता है। इसलिए, इस मामले में, आपको एक को छोड़कर सभी फ़ील्ड के लिए संबंधित \ _ नाम प्रदान करना होगा (एक डिफ़ॉल्ट और उत्पन्न हो सकता है) या सभी संबंधित फ़ील्ड के लिए।
उलटा संबंध छोड़ें
यदि आप सुनिश्चित हैं कि आप रिवर्स रिलेशनशिप नहीं चाहते हैं, तो आप MToके स्किप \ _ रिवर्स = ट्रू फ्लैग का उपयोग कर सकते हैं।
यदि आप स्किप \ _ रिवर्स फ्लैग को आंतरिक रूप से सेट करते हैं, तो फ़ील्ड अभी भी रिश्ते के दूसरे छोर पर पंजीकृत है, इसलिए आप कर सकते हैं:
- रिवर्स में प्रासंगिक नमूना फ़ील्ड द्वारा फ़िल्टर नमूना
- रिवर्स मॉडल में संबंधित मॉडल फील्ड्स द्वारा ऑर्डर \ _
लेकिन आप नहीं कर सकते:
- रिवर्स नमूना से संबंधित फ़ील्ड तक पहुँचने के लिए संबंधित \ _ नाम का उपयोग करें
- यहां तक कि अगर आप नमूना के रिवर्स साइड से सहसंबंध का चयन करते हैं, तो लौटे नमूना रिवर्स उदाहरण में आबादी नहीं होगी (कोई कनेक्शन अवरुद्ध नहीं किया जाएगा, इसलिए आप अभी भी रिश्ते को फ़िल्टर और सॉर्ट कर सकते हैं)।
- रिश्ता नमूना में आबाद नहीं होता_ डंप () and json ()
जब* एक शब्दकोश या json से आबाद होता है (also via fastapi), आप नेस्टेड संबंधित ऑब्जेक्ट पास नहीं कर सकते। pydकॉन्फ़िगरेशन में अतिरिक्त सेटिंग्स के आधार पर, इसे अनदेखा कर दिया जाएगा या एक त्रुटि फेंक दी जाएगी।
उदाहरण:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36 | कक्षा श्रेणी (ormar. Model):
ormar_config = base_ormar_config (टेबलनाम = "श्रेणियाँ")
आईडी: int = ormar। पूर्णांक (primary_key = True)
नाम: str = ormar। स्ट्रिंग (max_length = 40)
क्लास पोस्ट (ormar. Model):
ormar _ config = आधार _ ormar _ config कॉपी ()
आईडी: int = ormar। पूर्णांक (primary_key = True)
शीर्षक: str = ormar। स्ट्रिंग (max_length = 200)
श्रेणियां: वैकल्पिक [सूची [श्रेणी]] = ormar। MTo(श्रेणी, स्किप _ रिवर्स = सच)
# कुछ नमूना डेटा बनाएं
पोस्ट = प्रतीक्षा करें .(शीर्षक = "हैलो, एम 2 एम")
समाचार = श्रेणी का इंतजार करें (name = "News")
प्रतीक्षा कर रहा है।
पोस्ट करें। श्रेणियां [0] == समाचार #ok
Assert # विशेषता त्रुटि!
# लेकिन अभी भी ऑर्डर_बाय में उपयोग कर सकते हैं
श्रेणियाँ = (
प्रतीक्षा करें श्रेणी। वस्तुएं। _ संबंधित ("posts") चुनें। order_by ("posts__title"). सभी ()
)
श्रेणियां डालें [0]। पहला _ नाम = = "टेस्ट"
# ध्यान दें कि पदों को स्पष्ट रूप से भले ही लेखकों के लिए आबादी नहीं है
# select_related में शामिल - मॉडल _ डंप () में कोई पोस्ट नोट न करें
खबर दें। मॉडल _ डंप (exout =){"id"}) = = {"name": "News"}
#still संबंधित मॉडल के क्षेत्रों के माध्यम से फ़िल्टर कर सकता है
श्रेणियाँ = प्रतीक्षा करें श्रेणियाँ.objects.filter (posts__title="हैलो, M2M").all ()
श्रेणियां डालें [0]। नाम = = "समाचार"
लेन (श्रेणियाँ) == 1
|
नमूना के माध्यम से
या, यदि आप अतिरिक्त फ़ील्ड जोड़ना चाहते हैं, तो आप स्पष्ट रूप से नमूना वर्ग बना सकते हैं और पास कर सकते हैं।
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 | import databases
import ormar
import sqlalchemy
DATABASE_URL = "sqlite:///test.db"
ormar_base_config = ormar.OrmarConfig(
database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData()
)
class Category(ormar.Model):
ormar_config = ormar_base_config.copy(tablename="categories")
id = ormar.Integer(primary_key=True)
name = ormar.String(max_length=40)
class PostCategory(ormar.Model):
ormar_config = ormar_base_config.copy(tablename="posts_x_categories")
id: int = ormar.Integer(primary_key=True)
sort_order: int = ormar.Integer(nullable=True)
param_name: str = ormar.String(default="Name", max_length=200)
class Post(ormar.Model):
ormar_config = ormar_base_config.copy()
id: int = ormar.Integer(primary_key=True)
title: str = ormar.String(max_length=200)
categories = ormar.ManyToMany(Category, through=PostCategory)
|
!!!चेतावनी कृपया ध्यान दें कि भले ही आप इसे नमूना के माध्यम से प्रदान नहीं करते हैं, यह स्वचालित रूप से आपके लिए बनाया जाएगा और अभी भी एलेम्बिक माइग्रेशन के उदाहरण में शामिल किया जाना चाहिए।
!!!टिप ध्यान दें कि यदि आप थ्रू नमूना नाम या नमूना के डेटाबेस और तालिका नाम को अनुकूलित करना चाहते हैं, तो आपको थ्रू नमूना प्रदान करना होगा।
यदि आप "पास" फ़ील्ड प्रदान नहीं करते हैं, तो सिस्टम इसे आपके लिए उत्पन्न करेगा।
डिफ़ॉल्ट नामकरण सम्मेलन है:
- वर्ग नामों के लिए, यह दो वर्ग नामों का संघ है (parent + other), इसलिए ऊपर दिए गए उदाहरण में यह श्रेणी होगी
- तालिका नामों के लिए, यह समान है, लेकिन लोअरकेस क्लास नाम के अंत में एक अंडरस्कोर और एस के साथ, जो ऊपर दिए गए उदाहरण में पोस्ट \ _ श्रेणी होगा
रिश्ते के नाम से अनुकूलित करें
डिफ़ॉल्ट रूप से, संबंधित नमूना नाम नमूना संबंध नाम से कम है।
तो इस उदाहरण में:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 | ... # पाठ्यक्रम घोषणा छोड़ दी गई
कक्षा का छात्र (ormar. Model):
ormar _ config = आधार _ ormar _ config कॉपी ()
आईडी: int = ormar। पूर्णांक (primary_key = True)
नाम: str = ormar। स्ट्रिंग (max_length = 100)
पाठ्यक्रम = ormar। MTo(कोर्स)
# इस प्रकार नमूना के माध्यम से डिफ़ॉल्ट उत्पादन करेगा (example simplified)
क्लास स्टूडेंटकोर्स (ormar. Model):
ormar_config = base_ormar_config (टेबलनाम = "स्टूडेंट्स_कोर्स")
आईडी: int = ormar। पूर्णांक (primary_key = True)
छात्र = ormar। विदेशी (छात्र) # डिफ़ॉल्ट नाम
कोर्स = ormar। विदेशी कुंजी (कोर्स) # डिफ़ॉल्ट नाम
|
थ्रू नमूना में फ़ील्ड / संबंध नामों को अनुकूलित करने के लिए, अब आप MToके नए मापदंडों का उपयोग कर सकते हैं:
- \ _ संबंध \ _ नाम के माध्यम से - क्षेत्र का नाम MToघोषित करने नमूना लिए अग्रणी है
- \ _ रिवर्स \ _ संबंध \ _ नाम के माध्यम से - उस नमूना के फ़ील्ड नाम के लिए जो MToकी ओर जाता है
उदाहरण:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 | ... # पाठ्यक्रम घोषणा छोड़ दी गई
base_ormar_config = ormar। marConfig (
डेटाबेस = डेटाबेस। डेटाबेस ("sqlite: //db.sqlite"),
मेटाडेटा = वर्गधर्मी। मेटाडेटा (),
)
कक्षा का छात्र (ormar. Model):
ormar _ config = आधार _ ormar _ config कॉपी ()
आईडी: int = ormar। पूर्णांक (primary_key = True)
नाम: str = ormar। स्ट्रिंग (max_length = 100)
पाठ्यक्रम = ormar। MTo(पाठ्यक्रम,
थ्रू_रिलेशन_नाम = "स्टूडेंट_आईडी",
थ्रू_रिवर्स_रिलेशन_नाम = "कोर्स_आईडी")
# इस प्रकार नमूना के माध्यम से उत्पादन करेगा (example simplified)
क्लास स्टूडेंटकोर्स (ormar. Model):
ormar_config = base_ormar_config (टेबलनाम = "student_courses")
आईडी: int = ormar। पूर्णांक (primary_key = True)
student_id = ormar। विदेशी (छात्र) #set by _relation_name
कोर्स_आईडी = ormar। विदेशी कुंजी (कोर्स) #set by _reverset_relation_name
|
!!!ध्यान दें कि थ्रू नमूना में संबंधों को स्पष्ट रूप से घोषित करना निषिद्ध है, इसलिए यहां तक कि अगर आप अपना स्वयं का कस्टम प्रदान करते हैं तो नमूना के माध्यम से, आप वहां नाम नहीं बदल सकते हैं, और आपको \ _ संबंध \ _ नाम और \ _ रिवर्स \ _ संबंध \ _ नाम मापदंडों के माध्यम से समान उपयोग करने की आवश्यकता है।
खेतों के माध्यम से
पास फ़ील्ड को स्वचालित रूप से रिश्ते के रिवर्स साइड में जोड़ा जाता है।
उजागर फ़ील्ड को वर्ग नाम से लोअरकेस नाम दिया गया है।
उजागर क्षेत्र स्पष्ट रूप से किसी भी रिश्ते को लोड नहीं करता है क्योंकि संबंध पहले से ही MToक्षेत्र में आबाद है, इसलिए यह केवल उपयोगी है यदि अतिरिक्त फ़ील्ड थ्रू नमूना पर प्रदान किए जाते हैं।
सेटअप नमूना उदाहरण में, यह इस तरह दिखता है:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 | import databases
import ormar
import sqlalchemy
DATABASE_URL = "sqlite:///test.db"
ormar_base_config = ormar.OrmarConfig(
database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData()
)
class Category(ormar.Model):
ormar_config = ormar_base_config.copy(tablename="categories")
id = ormar.Integer(primary_key=True)
name = ormar.String(max_length=40)
class PostCategory(ormar.Model):
ormar_config = ormar_base_config.copy(tablename="posts_x_categories")
id: int = ormar.Integer(primary_key=True)
sort_order: int = ormar.Integer(nullable=True)
param_name: str = ormar.String(default="Name", max_length=200)
class Post(ormar.Model):
ormar_config = ormar_base_config.copy()
id: int = ormar.Integer(primary_key=True)
title: str = ormar.String(max_length=200)
categories = ormar.ManyToMany(Category, through=PostCategory)
|
अधिकांश Queryसंचालन में फ़ील्ड के माध्यम से एक सामान्य नमूना फ़ील्ड के रूप में उपयोग किया जा सकता है।
कृपया ध्यान दें कि पास फ़ील्ड केवल क्वेरी के संबंधित पक्ष से जुड़ा हुआ है, इसलिए:
| पोस्ट = प्रतीक्षा करें .select_related ("categories").get ()
# स्रोत नमूना क्षेत्र के माध्यम से नहीं है
पोस्ट डालें। पोस्टश्रेणी कोई नहीं है
# संबंधित मॉडल क्षेत्रों के माध्यम से हैं
assert .[0] .श्रेणी कोई नहीं है
#same उलट प्रश्नों के लिए लागू है
श्रेणी = प्रतीक्षा करें ("posts").get ()
जोर श्रेणी .postश्रेणी कोई नहीं है
श्रेणी। पद [0] .श्रेणी कोई नहीं है
|
डेटा को फ़िल्टर करने के लिए फ़ील्ड का उपयोग किया जा सकता है।
| पोस्ट = (
प्रतीक्षा करें .select_related ("categories")
। फ़िल्टर (postcategory__sort_order__gt=1)
। प्राप्त करें ()
)
|
!!!टिप ध्यान दें कि यद्यपि वास्तविक उदाहरण स्रोत नमूना में आबादी नहीं है, आप इसे प्रश्नों में नमूना के माध्यम से दोनों पक्षों से एक्सेस कर सकते हैं, बयानों द्वारा क्रमबद्ध करना हैं, आदि। इसलिए निम्नलिखित क्वेरी का बिल्कुल समान प्रभाव है (श्रेणी द्वारा नोट एक्सेस)
| ```python
post = (
await Post.objects.select_related("categories")
.filter(categories__postcategory__sort_order__gt=1)
.get()
)
```
|
नमूना के माध्यम से क्रमिक रूप से प्रश्नों का उपयोग किया जा सकता है।
| पोस्ट = (
प्रतीक्षा करें .select_related ("categories")
। आदेश _ द्वारा ("- postcategory__sort_order")
। प्राप्त करें ()
)
|
आप सामान्य Queryफैशन में स्तंभों के सबसेट का चयन करने के लिए फ़ील्ड और \ _ फ़ील्ड को छोड़कर भी उपयोग कर सकते हैं।
| पोस्ट 2 = (
प्रतीक्षा करें .select_related ("categories")
बहिष्कार_फ़ील्ड ("postcategory__param_name")
। प्राप्त करें ()
)
|
!!! चेतावनी ध्यान दें कि चूंकि थ्रू फ़ील्ड स्पष्ट रूप से सभी संबंधपरक फ़ील्ड को अमान्य कर देता है क्योंकि संबंध MToफ़ील्ड में आबाद है, मानक नमूना तरीके जैसे कि सहेजें () and update () डेटाबेस से फ़ील्ड को पुनः लोड करने से पहले उपयोग नहीं किया जाना चाहिए।
यदि आप पास फ़ील्ड को संशोधित करना चाहते हैं, तो डेटाबेस से इसे पुनः लोड करना याद रखें। अन्यथा, आप संबंध को "कोई नहीं" पर सेट करेंगे, प्रभावी रूप से फ़ील्ड को बेकार कर देंगे!
| # रेलवे संशोधन से पहले क्षेत्र को फिर से लोड करता है
2.श्रेणियों की प्रतीक्षा कर रहा है [0] .लोड ()
# तभी फ़ील्ड अपडेट करें
प्रतीक्षा करें 2.श्रेणियां [0] . (sort_order = 3)
|
ध्यान दें कि नमूना को फिर से लोड करना वास्तव में रिश्ते को pk \ _ के रूप में नमूना (केवल प्राथमिक कुंजी सेट है), इसलिए वे पूरी तरह से आबादी वाले नहीं हैं, लेकिन अपडेट होने पर रिश्ते को संरक्षित करने के लिए पर्याप्त हैं।
!!!चेतावनी यदि आप यानी फास्टापी का उपयोग करते हैं, तो फ़ील्ड अनुभाग के माध्यम से लोड किए गए संबंधित मॉडल पाइडेंटिक सत्यापन त्रुटियों का कारण बन सकते हैं (जो मुख्य कारण है कि वे डिफ़ॉल्ट रूप से आबादी नहीं हैं)। इसलिए, आपको या तो संबंधित फ़ील्ड को प्रतिक्रिया से बाहर करने या संबंधित मॉडल को पूरी तरह से लोड करने की आवश्यकता होगी।
ऊपर के उदाहरण में, यह माध्य है: python await post2.categories[0].postcategory.post.load() await post2.categories[0].postcategory.category.load() वैकल्पिक रूप से, आप लोड \ _ all () का उपयोग कर सकते हैं: python await post2.categories[0].postcategory.load_all()
पसंदीदा अपडेट विधि क्वेरीसेट प्रॉक्सी अपडेट () विधि के माध्यम से है
| # फ़ील्ड के माध्यम से वांछित संबंधित मॉडल को फ़िल्टर करें और केवल फ़ील्ड परम के माध्यम से अपडेट करें
प्रतीक्षा करें 2.categories.filter (name = 'Test category').अद्यतन (postcategory={"sort_order": 3})
|
संबंधपरक विधि
जोड़ें
जोड़ें (आइटम: मॉडल, **Kwargs)
आपको कई-से-कई संबंधों में मॉडल जोड़ने की अनुमति देता है।
| # एक पोस्ट में एक श्रेणी जोड़ें।
प्रतीक्षा कर रहा है।
# दूसरे छोर से:
प्रतीक्षा कर रहा है (post)
|
!!!चेतावनी: सभी गैर-कोई नहीं मामलों में, संबंधित नमूना का प्राथमिक कुंजी मूल्य डेटाबेस में मौजूद होना चाहिए।
| अन्यथा आपके डेटाबेस ड्राइवर लाइब्रेरी द्वारा एक इंटीग्रिटीएरर उठाया जाएगा।
|
यदि आप अतिरिक्त क्षेत्रों के साथ एक थ्रू मॉडल के साथ एक नमूना नमूना के साथ एक मॉडल की घोषणा करते हैं, तो आप रिश्ते के अलावा बच्चे के मॉडल को आबाद कर सकते हैं।
ऐसा करने के लिए, फ़ील्ड नाम और मान के साथ कीवर्ड तर्क को ऐड () कॉल में पास करें।
कृपया ध्यान दें कि यह केवल कई-से-कई रिश्तों पर लागू होता है।
| पोस्ट = प्रतीक्षा पोस्ट (शीर्षक = "टेस्ट पोस्ट") .()
श्रेणी = प्रतीक्षा श्रेणी (name = "Test category").save ()
# नमूना पास तर्कों से अलग नमूना क्षेत्रों के माध्यम से संदर्भित
प्रतीक्षा करें .(श्रेणी, sort_order = 1, param_name = 'test')
|
खत्म करना
संबंधित मॉडल एक-एक करके हटा दिए जाते हैं।
डेटाबेस में संबंध भी हटाएं।
| प्रतीक्षा कर रहा है (post)
|
स्पष्ट
एक एकल कॉल सभी संबंधित मॉडल को हटा देता है।
डेटाबेस में संबंध भी हटाएं।
के लिए प्रतीक्षा कर रहा है ()
क्वेरी सेट एजेंट
उलटा संबंध QueryProएपीआई को उजागर करता है, जो आपको संबंधित मॉडल को क्वेरी करने की अनुमति देता है जैसे आप एक सामान्य क्वेरी करेंगे।
क्वेरीसेट के कौन से तरीके उपलब्ध हैं, यह जानने के लिए नीचे दिए गए क्वेरीसेटप्रॉक्सी पढ़ें