দুটি alচ্ছিক, তবে একটি বাধ্যতামূলক বিদেশী কী সহ একটি মডেল তৈরি করা


9

আমার সমস্যাটি হ'ল আমার কাছে এমন একটি মডেল রয়েছে যা দুটি ধরণের বিদেশী কীগুলির মধ্যে একটি নিতে পারে এটি কী ধরণের মডেল তা বলতে। আমি চাই যে এটি কমপক্ষে একটি নেবে তবে দুটোই নয়। আমি কি এটি এখনও একটি মডেল হতে পারি বা আমি এটি দুটি ধরণের মধ্যে বিভক্ত করা উচিত? কোডটি এখানে:

class Inspection(models.Model):
    InspectionID = models.AutoField(primary_key=True, unique=True)
    GroupID = models.ForeignKey('PartGroup', on_delete=models.CASCADE, null=True, unique=True)
    SiteID = models.ForeignKey('Site', on_delete=models.CASCADE, null=True, unique=True)

    @classmethod
    def create(cls, groupid, siteid):
        inspection = cls(GroupID = groupid, SiteID = siteid)
        return inspection

    def __str__(self):
        return str(self.InspectionID)

class InspectionReport(models.Model):
    ReportID = models.AutoField(primary_key=True, unique=True)
    InspectionID = models.ForeignKey('Inspection', on_delete=models.CASCADE, null=True)
    Date = models.DateField(auto_now=False, auto_now_add=False, null=True)
    Comment = models.CharField(max_length=255, blank=True)
    Signature = models.CharField(max_length=255, blank=True)

সমস্যা Inspectionমডেল। এটি কোনও গ্রুপ বা কোনও সাইটের সাথে লিঙ্ক করা উচিত, তবে উভয়ই নয়। বর্তমানে এই সেট আপের সাথে এটি উভয়েরই দরকার।

আমি বরং এই দুই এর মতো প্রায় একই মডেলের মধ্যে আপ বিভক্ত করতে হবে না চাই GroupInspectionএবং SiteInspectionতাই কোনো সমাধান এক মডেল হিসেবে রাখে আদর্শ হতে হবে।


সম্ভবত এখানে সাবক্লাসিং ব্যবহার করা আরও ভাল। আপনি একটি শ্রেণিবদ্ধ করতে পারেন Inspectionএবং তারপরে অ-সাধারণ অংশগুলিতে SiteInspectionএবং এর GroupInspectionজন্য সাবক্লাস করতে পারেন ।
উইলেম ভ্যান অনসেম

সম্ভবত সম্পর্কিত নয়, তবে unique=Trueআপনার এফকে ক্ষেত্রের অংশটির অর্থ এই যে Inspectionকোনও দেওয়া GroupIDবা SiteIDউদাহরণের জন্য কেবলমাত্র একটি উদাহরণ থাকতে পারে - আইওডাব্লু, এটি একের সাথে এক সম্পর্ক, অনেকের সাথে এক নয়। এই কি আপনি চান সত্যিই ?
ব্রুনো ডেথুইলিয়ার্স

"বর্তমানে এই সেট আপের সাথে এটি উভয়েরই দরকার" " => প্রযুক্তিগতভাবে, এটি হয় না - ডাটাবেস স্তরে আপনি উভয় সেট করতে পারেন, হয় বা সেই কীগুলির মধ্যে কোনওটি নেই (উপরে উল্লিখিত ক্যাভিয়েট সহ)। কোনও মডেলফর্ম ব্যবহার করার সময় (সরাসরি বা জ্যাঙ্গো অ্যাডমিনের মাধ্যমে) সেই ক্ষেত্রগুলি প্রয়োজনীয় হিসাবে চিহ্নিত করা হবে, এবং এর কারণ আপনি 'ফাঁকা = সত্য' যুক্তিটি পাস করেন নি।
ব্রুনো ডেথুইলিয়ার্স

@brunodesthuilliers হ্যাঁ ধারণা আছে হয় Inspectionমধ্যে একটি লিঙ্ক হতে Groupবা Siteএবং InspectionIDতারপর, আমি আকারে একাধিক "পরিদর্শন" থাকতে পারে InspectionReportযে এক সম্পর্কের জন্য। এই ঘটনার পর যাতে আমি আরও সহজে সাজানোর দ্বারা করতে পারেন Dateএক সাথে সম্পর্কিত সকল রেকর্ডের জন্য Groupবা Site। আশা করি তা উপলব্ধি করা হয়েছে
CalMac

@ Cm0295 আমি ভয় করি যে এই ইন্ডিरेশন লেভেলের বিন্দুটি দেখতে না পাচ্ছি - গ্রুপ / সাইট এফকে সরাসরি ইনস্পেকশনরেপার্টে রাখলে ঠিক একই সার্ভিস এএএফএসিটি পাওয়া যায় - উপযুক্ত কী দ্বারা আপনার ইন্সপেকশন রিপোর্টগুলি ফিল্টার করুন (বা কেবল সাইট থেকে বিপরীত বর্ণনাকারী অনুসরণ করুন বা গোষ্ঠী), তাদের তারিখ অনুসারে বাছাই করুন এবং আপনার কাজ শেষ।
13

উত্তর:


5

আমি আপনাকে পরামর্শ দিচ্ছি যে আপনি জ্যাঙ্গো উপায়ে যেমন বৈধকরণ করেন

cleanজ্যাঙ্গো মডেলের পদ্ধতিটি ওভাররাইড করে

class Inspection(models.Model):
    ...

    def clean(self):
        if <<<your condition>>>:
            raise ValidationError({
                    '<<<field_name>>>': _('Reason for validation error...etc'),
                })
        ...
    ...

নোট করুন, তবে, মডেল.ফুল_ক্লান () এর মতো, যখন আপনি আপনার মডেলটির সেভ () পদ্ধতিটি কল করেন তখন কোনও মডেলের ক্লিন () পদ্ধতি চালু করা হয় না। মডেলটির ডেটা যাচাই করার জন্য এটি ম্যানুয়ালি বলা দরকার, বা Modelক্লাস সেভ পদ্ধতিটি ট্রিগার করার আগে আপনি সর্বদা ক্লিন () পদ্ধতিতে কল করার জন্য মডেলের সংরক্ষণ পদ্ধতিটি ওভাররাইড করতে পারেন can


একাধিক টেবিলের সাথে সম্পর্কিত এমন একটি পলিমারফিক ক্ষেত্র সরবরাহের জন্য জেনেরিক্যালিলিকেশনগুলি ব্যবহার করতে সহায়তা করতে পারে এমন আরেকটি সমাধান , তবে এই টেবিলগুলি / অবজেক্টগুলি প্রথম স্থান থেকে সিস্টেম ডিজাইনে পরিবর্তিতভাবে ব্যবহার করা যেতে পারে।


2

মন্তব্যে উল্লিখিত হিসাবে, "এই সেটআপের সাথে এটি উভয়ের প্রয়োজন" এর কারণটি হ'ল blank=Trueআপনি আপনার এফকে ক্ষেত্রে যোগ করতে ভুলে গেছেন , সুতরাং আপনার ModelForm(কাস্টম একটি বা অ্যাডমিন দ্বারা উত্পাদিত ডিফল্ট) ফর্ম ক্ষেত্রটি প্রয়োজনীয় করে তুলবে । ডিবি স্কিমা স্তরে, আপনি উভয়ই পূরণ করতে পারেন, উভয়ই এফকে বা যেকোন একটিও নয়, কারণ আপনি এই ডিবি ক্ষেত্রগুলিকে নলাবদ্ধ করে দিয়েছেন ( null=Trueযুক্তি দিয়ে)।

এছাড়াও, (আমার অন্যান্য মন্তব্য সিএফ), আপনি যাচাই করতে চাইতে পারেন যে আপনি সত্যই এফকে অনন্য হতে চান। এই প্রযুক্তিগতভাবে আপনার একটিকে অনেক সম্পর্কের সাথে একের সম্পর্কের মধ্যে রূপান্তরিত করে - আপনি কেবলমাত্র একটি গ্রুপআইডিডি বা সাইটআইডির জন্য কেবল একটি একক 'পরিদর্শন' রেকর্ডের অনুমতি পেয়েছেন (একটি গ্রুপআইড বা সাইটআইডির জন্য আপনার দুটি বা আরও 'পরিদর্শন' থাকতে পারে না) । যদি এটি সত্যিই আপনি চান তবে আপনি পরিবর্তে একটি স্পষ্ট ওয়ানটোওফিল্ড ব্যবহার করতে চাইতে পারেন (ডিবি স্কিমাটি একই হবে তবে মডেলটি আরও স্পষ্ট এবং সম্পর্কিত বর্ণনাকারী এই ব্যবহারের ক্ষেত্রে আরও বেশি ব্যবহারযোগ্য হবে)।

পার্শ্ব নোট হিসাবে: একটি জ্যাঙ্গো মডেলে, একটি বিদেশী ক্ষেত্রটি কোনও কাঁচা আইডি হিসাবে নয়, সম্পর্কিত মডেল উদাহরণ হিসাবে প্রমাণিত করে। IOW, এটি দেওয়া:

class Foo(models.Model):
    name = models.TextField()

class Bar(models.Model):
    foo = models.ForeignKey(Foo)


foo = Foo.objects.create(name="foo")
bar = Bar.objects.create(foo=foo)

তারপরে bar.fooসংকল্প হবে foo, না foo.id। সুতরাং আপনি অবশ্যই আপনার InspectionIDএবং SiteIDক্ষেত্রগুলির যথাযথ inspectionএবং নামকরণ করতে চান site। বিটিডাব্লু, পাইথনে, নামকরণ সম্মেলনটি শ্রেণীর নাম এবং সিউডো-কনস্ট্যান্ট বাদে অন্য যে কোনও কিছুর জন্য 'অল_ল্লোয়ার_উইথ_ফন্ডসরস'।

এখন আপনার মূল প্রশ্নের জন্য: ডাটাবেস স্তরে "একটি বা অন্য" বাধা প্রয়োগের কোনও নির্দিষ্ট স্ট্যান্ডার্ড এসকিউএল উপায় নেই, তাই এটি সাধারণত একটি চেক বাধা ব্যবহার করে সম্পন্ন করা হয়, যা মডেলটির মেটা "সীমাবদ্ধতা" দিয়ে জাজানো মডেলে করা হয় বিকল্প

এটি বলা হচ্ছে, ডিবি স্তরে কীভাবে সীমাবদ্ধতাগুলি আসলে সমর্থন করা হয় এবং প্রয়োগ করা হয় তা আপনার ডিবি বিক্রেতার উপর নির্ভর করে (মাইএসকিউএল <8.0.16 কেবল উদাহরণস্বরূপ এগুলি উপেক্ষা করুন ), এবং আপনার যে ধরণের প্রতিবন্ধকতার প্রয়োজন হবে তা ফর্মটিতে প্রয়োগ করা হবে না বা মডেল স্তরের বৈধতা , কেবলমাত্র মডেলটি সংরক্ষণ করার চেষ্টা করার সময়, আপনি মডেল স্তরে (সর্বাধিক) বা ফর্ম স্তরের বৈধতা উভয় ক্ষেত্রে (রেস।) মডেল বা ফর্মের পদ্ধতিতে বৈধতা যুক্ত করতে চান ।clean()

একটি দীর্ঘ গল্প সংক্ষিপ্ত করতে:

  • প্রথমে ডাবল-চেক করুন যে আপনি সত্যিই এই unique=Trueসীমাবদ্ধতা চান এবং যদি হ্যাঁ হয় তবে আপনার এফকে ক্ষেত্রটি ওয়ানটোঅনফিল্ডের সাথে প্রতিস্থাপন করুন।

  • একটি যোগ blank=Trueআপনার এফ কে (অথবা OneToOne) উভয় ARG ক্ষেত্র

  • আপনার মডেলের মেটাতে যথাযথ চেক সীমাবদ্ধতা যুক্ত করুন - ডকটি সাফল্যযুক্ত তবে এখনও আপনি যদি ওআরএম এর সাথে জটিল প্রশ্নগুলি করতে জানেন তবে (এবং আপনি যদি সময় শিখেন না ;-))
  • clean()আপনার মডেলটিতে এমন একটি পদ্ধতি যুক্ত করুন যা আপনার এক বা অন্য ক্ষেত্রটি পরীক্ষা করে এবং অন্য কোনও বৈধতা ত্রুটি উত্থাপন করে

এবং আপনার ঠিক হওয়া উচিত, আপনার RDBMS অবশ্যই চেক সীমাবদ্ধতার সম্মান করে।

কেবলমাত্র নোট করুন, এই নকশার সাহায্যে আপনার Inspectionমডেলটি একেবারে অকেজো (এখনও ব্যয়বহুল!) ইন্ডিয়ারেশন - আপনি সরাসরি এফকে (এবং সীমাবদ্ধতা, বৈধকরণ ইত্যাদি) সরাসরি স্থানান্তরিত করে স্বল্প মূল্যে একই বৈশিষ্ট্যগুলি পেতে পারেন InspectionReport

এখন আর একটি সমাধান হতে পারে - পরিদর্শন মডেলটি রাখুন, তবে সম্পর্কের অন্য প্রান্তে (সাইট এবং গোষ্ঠীতে) এফকে ওয়ানটোনফিল্ড হিসাবে রাখুন:

class Inspection(models.Model):
    id = models.AutoField(primary_key=True) # a pk is always unique !

class InspectionReport(models.Model):
    # you actually don't need to manually specify a PK field,
    # Django will provide one for you if you don't
    # id = models.AutoField(primary_key=True)

    inspection = ForeignKey(Inspection, ...)
    date = models.DateField(null=True) # you should have a default then
    comment = models.CharField(max_length=255, blank=True default="")
    signature = models.CharField(max_length=255, blank=True, default="")


class Group(models.Model):
    inspection = models.OneToOneField(Inspection, null=True, blank=True)

class Site(models.Model):
    inspection = models.OneToOneField(Inspection, null=True, blank=True)

এবং তারপরে আপনি কোনও প্রদত্ত সাইট বা গোষ্ঠীর জন্য সমস্ত প্রতিবেদন পেতে পারেন yoursite.inspection.inspectionreport_set.all()

এটি কোনও নির্দিষ্ট সীমাবদ্ধতা বা বৈধতা যুক্ত করতে এড়ায় না, তবে অতিরিক্ত ইন্ডাইরেশন লেভেলের (এসকিউএল joinক্লজ ইত্যাদি) ব্যয় করে।

এই সমাধানগুলির মধ্যে কোনটি "সেরা" হবে তা প্রকৃতপক্ষে প্রাসঙ্গিক নির্ভর, সুতরাং আপনার উভয়েরই বোঝা বুঝতে হবে এবং আপনার নিজের প্রয়োজনের জন্য কোনটি উপযুক্ত। এটির জন্য আপনি সাধারণত কীভাবে আপনার মডেলগুলি ব্যবহার করেন তা যাচাই করতে হবে। যতদূর আমি উদ্বিগ্ন এবং আরও প্রসঙ্গ ছাড়াই (বা সন্দেহের ভিত্তিতে) আমি বরং সমাধানটি কম ইন্ডিরিশন লেভেলের সাথে ব্যবহার করব, তবে ওয়াইএমএমভি।

জেনেরিক সম্পর্কের বিষয়ে এনবি: যখন আপনার কাছে সত্যিকারের অনেকগুলি সম্পর্কিত সম্পর্কিত মডেল থাকে এবং / বা কোন মডেলগুলি আপনার নিজের সাথে সম্পর্কযুক্ত করতে চাইবে তা আগে জানা থাকে না সেগুলি কার্যকর হতে পারে। এটি পুনরায় ব্যবহারযোগ্য অ্যাপ্লিকেশনগুলির জন্য (ভাবুন "মন্তব্যগুলি" বা "ট্যাগগুলি" ইত্যাদি বৈশিষ্ট্যগুলি) বা এক্সটেনসিবল অ্যাপ্লিকেশনের জন্য (সামগ্রী সামগ্রী ফ্রেমওয়ার্ক ইত্যাদি) বিশেষভাবে কার্যকর। ক্ষতিটি হ'ল এটি অনেক ভারী জিজ্ঞাসাবাদ করে তোলে (এবং আপনি যখন আপনার ডিবিতে ম্যানুয়াল অনুসন্ধান করতে চান তখন বরং ব্যবহারিক হয় না)। অভিজ্ঞতা থেকে, তারা দ্রুত একটি পিআইটিএ বট আর্ট / কোড এবং পারফস হয়ে উঠতে পারে, তখন এর চেয়ে আরও ভাল সমাধান যখন না থাকে (এবং / অথবা যখন রক্ষণাবেক্ষণ এবং রানটাইম ওভারহেড কোনও সমস্যা না হয়)।

আমার 2 সেন্ট।


2

জ্যাঙ্গোর ডিবি সীমাবদ্ধতা তৈরি করার জন্য একটি নতুন (২.২ থেকে) ইন্টারফেস রয়েছে: https://docs.djangoproject.com/en/3.0/ref/models/constraints/

আপনি CheckConstraintএক এবং একমাত্র প্রয়োগ করার জন্য অ-নালকে ব্যবহার করতে পারেন । আমি স্পষ্টতার জন্য দুটি ব্যবহার করি:

class Inspection(models.Model):
    InspectionID = models.AutoField(primary_key=True, unique=True)
    GroupID = models.OneToOneField('PartGroup', on_delete=models.CASCADE, blank=True, null=True)
    SiteID = models.OneToOneField('Site', on_delete=models.CASCADE, blank=True, null=True)

    class Meta:
        constraints = [
            models.CheckConstraint(
                check=~Q(SiteID=None) | ~Q(GroupId=None),
                name='at_least_1_non_null'),
            ),
            models.CheckConstraint(
                check=Q(SiteID=None) | Q(GroupId=None),
                name='at_least_1_null'),
            ),
        ]

এটি কেবলমাত্র ডিবি স্তরে সীমাবদ্ধতা প্রয়োগ করবে। আপনাকে নিজের ফর্ম বা সিরিয়ালাইজারগুলিতে ম্যানুয়ালি ইনপুটগুলি বৈধতা দিতে হবে।

পার্শ্ব নোট হিসাবে, আপনি সম্ভবত OneToOneFieldপরিবর্তে ব্যবহার করা উচিত ForeignKey(unique=True)। এছাড়াও আপনি চাইবেন blank=True


0

আমি মনে করি আপনি জেনেরিক সম্পর্ক , ডক্স সম্পর্কে কথা বলছেন । আপনার উত্তর অনুরূপ এই এক

কিছুকাল আগে আমার জেনেরিক সম্পর্কগুলি ব্যবহার করার দরকার ছিল তবে আমি একটি বইতে এবং অন্য কোথাও ব্যবহারটি এড়ানো উচিত বলে আমি পড়েছিলাম, আমি মনে করি এটি জাজানোর দুটি স্কুপ ছিল।

আমি এই জাতীয় মডেল তৈরি করে শেষ করেছি:

class GroupInspection(models.Model):
    InspectionID = models.ForeignKey..
    GroupID = models.ForeignKey..

class SiteInspection(models.Model):
    InspectionID = models.ForeignKey..
    SiteID = models.ForeignKey..

আমি নিশ্চিত না যে এটি একটি ভাল সমাধান কিনা এবং আপনি যেমনটি উল্লেখ করেছেন আপনি এটি ব্যবহার করবেন না, তবে এটি আমার ক্ষেত্রে কাজ করা হয়েছে।


"আমি একটি বইতে এবং অন্য কোথাও পড়েছি" কিছু করার (বা করা এড়ানো) এর আরও খারাপ কারণ সম্পর্কে।
ব্রুনো ডেথুইলিয়ার্স

@ ব্রুনোডেসথুইলিয়ার্স আমি ভেবেছিলাম জ্যাঙ্গোর দুটি স্কুপ একটি ভাল বই ছিল।
লুইস সিলভা

বলতে পারি না, আমি পড়িনি। তবে এটি সম্পর্কিত নয়: আমার বক্তব্যটি হ'ল বইটি কেন এমনটি বলে তা যদি আপনি বুঝতে না পারেন তবে এটি জ্ঞান বা অভিজ্ঞতা নয়, এটি ধর্মীয় বিশ্বাস। ধর্মের কথা আসলে ধর্মীয় বিশ্বাসকে আমি আপত্তি করি না, তবে সিএসে তাদের কোনও স্থান নেই। হয় আপনি বুঝতে পারবেন যে কোনও বৈশিষ্ট্যের কী কী উপকারিতা তা জানা যায় এবং তারপরে আপনি এটি নির্ধারণ করতে পারেন যে এটি কোনও নির্দিষ্ট প্রসঙ্গে উপযুক্ত কিনা , বা আপনি তা করেন না এবং তারপরে আপনি যা পড়েছেন তা নির্বোধভাবে তোতা দেওয়া উচিত নয় not জেনেরিক সম্পর্কের জন্য খুব বৈধ ব্যবহারের কেস রয়েছে, পয়েন্টটি এগুলি এড়াতে নয় তবে কখন এড়ানো উচিত তা জানার নয়।
ব্রুনো ডেসথুইলিয়ার্স

এনবি আমি পুরোপুরি বুঝতে পারি যে সিএস সম্পর্কে কেউ জানতে পারে না - এমন কিছু ডোমেন রয়েছে যেখানে আমার কাছে কোনও বইয়ের উপর নির্ভর করা ছাড়া অন্য কোনও বিকল্প নেই। তবে তারপরে আমি সম্ভবত সেই বিষয়ে প্রশ্নের উত্তর দেব না ;-)
ব্রুনো ডেসথুইলিয়ার্স

0

আপনার প্রশ্নের উত্তর দিতে দেরি হতে পারে তবে আমি ভেবেছিলাম আমার সমাধানটি অন্য কোনও ব্যক্তির ক্ষেত্রে মাপসই হতে পারে।

আমি একটি নতুন মডেল তৈরি করব, আসুন এটি কল করুন Dependencyএবং সেই মডেলটিতে যুক্তি প্রয়োগ করুন।

class Dependency(models.Model):
    Group = models.ForeignKey('PartGroup', on_delete=models.CASCADE, null=True, unique=True)
    Site = models.ForeignKey('Site', on_delete=models.CASCADE, null=True, unique=True)

তারপরে আমি যুক্তিটি খুব স্পষ্টভাবে প্রযোজ্য হয়ে লিখব।

class Dependency(models.Model):
    group = models.ForeignKey('PartGroup', on_delete=models.CASCADE, null=True, unique=True)
    site = models.ForeignKey('Site', on_delete=models.CASCADE, null=True, unique=True)

    _is_from_custom_logic = False

    @classmethod
    def create_dependency_object(cls, group=None, site=None):
        # you can apply any conditions here and prioritize the provided args
        cls._is_from_custom_logic = True
        if group:
            _new = cls.objects.create(group=group)
        elif site:
            _new = cls.objects.create(site=site)
        else:
            raise ValueError('')
        return _new

    def save(self, *args, **kwargs):
        if not self._is_from_custom_logic:
            raise Exception('')
        return super().save(*args, **kwargs)

এখন ForeignKeyআপনার Inspectionমডেলটিতে কেবল একটি একক তৈরি করতে হবে ।

আপনার viewফাংশনগুলিতে আপনাকে একটি Dependencyঅবজেক্ট তৈরি করতে হবে এবং তারপরে এটি আপনার Inspectionরেকর্ডে বরাদ্দ করতে হবে । আপনি create_dependency_objectআপনার viewকার্যাদি ব্যবহার করেন তা নিশ্চিত করুন ।

এটি আপনার কোডটি সুস্পষ্ট এবং বাগ প্রমাণ তৈরি করে। প্রয়োগকারীটিকে খুব সহজেই বাইপাস করা যায়। তবে মূল কথাটি হ'ল বাইপাস করার জন্য এই সঠিক সীমাবদ্ধতার পূর্বের জ্ঞান প্রয়োজন।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.