Django: ทำไมฟิลด์บางรุ่นถึงขัดแย้งกัน?


174

ฉันต้องการสร้างวัตถุที่มี 2 ลิงค์ไปยังผู้ใช้ ตัวอย่างเช่น:

class GameClaim(models.Model):
    target = models.ForeignKey(User)
    claimer = models.ForeignKey(User)
    isAccepted = models.BooleanField()

แต่ฉันได้รับข้อผิดพลาดต่อไปนี้เมื่อใช้เซิร์ฟเวอร์:

  • Accessor for clashes 'target' field ที่มีฟิลด์ที่เกี่ยวข้อง 'User.gameclaim_set' เพิ่มอาร์กิวเมนต์ related_name เข้ากับคำจำกัดความของ 'target'

  • การเข้าถึงสำหรับฟิลด์ 'ผู้อ้างสิทธิ์' ที่มีฟิลด์ที่เกี่ยวข้อง 'User.gameclaim_set' เพิ่มอาร์กิวเมนต์ related_name เข้ากับคำจำกัดความของ'aimer '

คุณช่วยอธิบายได้ไหมว่าทำไมฉันถึงได้รับข้อผิดพลาดและวิธีแก้ไข?


ข้อความผิดพลาดเหล่านี้ดีจริงๆ พวกเขาอธิบายวิธีแก้ไขแล้ว และการอ่านข้อมูลเพิ่มเติม ** [ related_nameในเอกสารประกอบ] ** ( docs.djangoproject.com/en/dev/ref/models/fields/#arguments ) จะอธิบายว่าทำไมจึงเกิดขึ้น
Lutz Prechelt

คำตอบ:


294

คุณมีกุญแจสองปุ่มสำหรับผู้ใช้งาน Django จะสร้างความสัมพันธ์ที่กลับจากผู้ใช้กลับไป GameClaim gameclaim_setซึ่งมักจะ อย่างไรก็ตามเนื่องจากคุณมี FK สองตัวคุณจะมีgameclaim_setคุณสมบัติสองอย่างซึ่งเป็นไปไม่ได้แน่นอน ดังนั้นคุณต้องบอก Django ว่าชื่อใดที่ใช้สำหรับความสัมพันธ์แบบย้อนกลับ

ใช้related_nameคุณสมบัติในการกำหนด FK เช่น

class GameClaim(models.Model):
    target = models.ForeignKey(User, related_name='gameclaim_targets')
    claimer = models.ForeignKey(User, related_name='gameclaim_users')
    isAccepted = models.BooleanField()

49
คำตอบที่ดี แต่ฉันไม่คิดว่าคุณประสบความสำเร็จในการหลีกเลี่ยงความรุนแรง: P "ทำไม" ไม่ชัดเจนเว้นแต่คุณจะทราบว่า django ทำงานอย่างไรภายใน
Kenny

14
สำหรับใครบางคนเพียงแค่เรียนรู้กรอบนี้จะไม่ชัดเจน
jkyle

3
ขอบคุณข้อความแสดงข้อผิดพลาดไม่ชัดเจนสำหรับฉันเช่นกัน แต่คำอธิบายของคุณเกี่ยวกับความสัมพันธ์แบบย้อนกลับนั้นมีประโยชน์มาก
ruquay

1
เพียงเพราะการปะทะกันเป็นวงดนตรีที่ดีไม่ได้ทำให้พวกเขาเป็นข้อผิดพลาดที่สื่อความหมายโดยเฉพาะอย่างยิ่ง;)
btown

7
มันควรจะกล่าวว่าถ้าคุณไม่จำเป็นต้องใช้ความสัมพันธ์แบบย้อนกลับสำหรับทุกรุ่น ในบางกรณีคุณอาจต้องการให้โมเดลมีความสัมพันธ์แบบทางเดียว ในกรณีนี้คุณใช้ related_name = '+' สิ่งนี้บอกให้ Django สร้างความสัมพันธ์แบบทางเดียวและไม่สนใจความสัมพันธ์แบบย้อนกลับ
Tommy Strand

8

Userรุ่นพยายามที่จะสร้างสองเขตข้อมูลที่มีชื่อเดียวกันหนึ่งสำหรับGameClaimsที่มีที่Userเป็นtargetและอื่น ๆ สำหรับGameClaimsที่มีที่เป็นUser claimerนี่คือเอกสารของrelated_nameซึ่งเป็นวิธีการของ Django ให้คุณตั้งชื่อของคุณสมบัติเพื่อให้คนที่สร้างอัตโนมัติไม่ขัดแย้ง


7

OP ไม่ได้ใช้คลาสฐานที่เป็นนามธรรม ... แต่ถ้าคุณเป็นคุณจะพบว่าการเข้ารหัส hard_name ที่เกี่ยวข้องใน FK (เช่น ... , related_name = "myname") จะส่งผลให้เกิดข้อผิดพลาดที่ขัดแย้งกันจำนวนหนึ่ง - หนึ่งคลาสสำหรับแต่ละคลาสที่สืบทอดมาจากคลาสฐาน ลิงก์ด้านล่างมีวิธีแก้ไขซึ่งง่าย แต่ไม่ชัดเจน

จากเอกสาร django ...

หากคุณกำลังใช้แอททริบิวที่เกี่ยวข้องกับชื่อ ForeignKey หรือ ManyToManyField คุณต้องระบุชื่อย้อนกลับที่ไม่ซ้ำกันสำหรับฟิลด์ ปกติแล้วสิ่งนี้จะทำให้เกิดปัญหาในคลาสพื้นฐานที่เป็นนามธรรมเนื่องจากฟิลด์ในคลาสนี้จะรวมอยู่ในคลาสย่อยแต่ละคลาสพร้อมกับค่าเดียวกันสำหรับแอตทริบิวต์ (รวมทั้ง related_name) ในแต่ละครั้ง

ข้อมูลเพิ่มเติมที่นี่


2

บางครั้งคุณต้องใช้การจัดรูปแบบพิเศษrelated_name - จริง ๆ แล้วเมื่อใดก็ตามที่มีการใช้การสืบทอด

class Value(models.Model):
    value = models.DecimalField(decimal_places=2, max_digits=5)
    animal = models.ForeignKey(
        Animal, related_name="%(app_label)s_%(class)s_related")

    class Meta:
        abstract = True

class Height(Value):
    pass

class Weigth(Value):
    pass

class Length(Value):
    pass

ไม่มีการปะทะกันที่นี่ แต่ related_name จะถูกกำหนดหนึ่งครั้งและ Django จะดูแลการสร้างชื่อความสัมพันธ์ที่ไม่ซ้ำกัน

จากนั้นในระดับย่อยของ Value คุณจะสามารถเข้าถึง:

herdboard_height_related
herdboard_lenght_related
herdboard_weight_related

0

ฉันดูเหมือนจะเจอสิ่งนี้เป็นครั้งคราวเมื่อฉันเพิ่ม submodule เป็นแอปพลิเคชั่นในโครงการ django ตัวอย่างเช่นตามโครงสร้างต่อไปนี้:

myapp/
myapp/module/
myapp/module/models.py

หากฉันเพิ่มสิ่งต่อไปนี้ใน INSTALLED_APPS:

'myapp',
'myapp.module',

Django ดูเหมือนจะประมวลผลไฟล์ myapp.mymodule models.py สองครั้งและส่งข้อผิดพลาดด้านบน สามารถแก้ไขได้โดยไม่รวมโมดูลหลักในรายการ INSTALLED_APPS:

'myapp.module',

การรวมmyappแทนที่จะmyapp.moduleทำให้ตารางฐานข้อมูลทั้งหมดถูกสร้างขึ้นด้วยชื่อที่ไม่ถูกต้องดังนั้นนี่จึงเป็นวิธีที่ถูกต้องในการทำ

ฉันเจอโพสต์นี้ในขณะที่มองหาวิธีแก้ไขปัญหานี้ดังนั้นฉันจึงคิดว่าฉันจะใส่นี่ไว้ :)


0

เพียงเพิ่มคำตอบของจอร์แดน (ขอบคุณสำหรับเคล็ดลับจอร์แดน) มันสามารถเกิดขึ้นได้หากคุณนำเข้าระดับเหนือแอพแล้วนำเข้าแอพเช่น

myproject/ apps/ foo_app/ bar_app/

ดังนั้นหากคุณกำลังนำเข้าแอพ foo_app และ bar_app คุณจะได้รับปัญหานี้ ฉันมีแอพ foo_app และ bar_app ทั้งหมดที่ระบุไว้ในการตั้งค่า INSTALLED_APPS

และคุณต้องการหลีกเลี่ยงการนำเข้าแอพอยู่ดีเพราะคุณมีแอพเดียวกันติดตั้งอยู่ในเนมสเปซ 2 แบบ

apps.foo_app และ foo_app

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.