জ্যাঙ্গো মডেল ফিল্ড ডিফল্ট একই মডেলের অন্য একটি ক্ষেত্রের ভিত্তিতে


92

আমার একটি মডেল রয়েছে যা আমি একটি বিষয়ের নাম এবং তাদের আদ্যক্ষর অন্তর্ভুক্ত রাখতে চাই (তার ডেটা কিছুটা বেনামে এবং আদ্যক্ষর দ্বারা ট্র্যাক করা হয়)।

এই মুহুর্তে, আমি লিখেছি

class Subject(models.Model):

    name = models.CharField("Name", max_length=30)
    def subject_initials(self):
        return ''.join(map(lambda x: '' if len(x)==0 else x[0],
                           self.name.split(' ')))
    # Next line is what I want to do (or something equivalent), but doesn't work with
    # NameError: name 'self' is not defined
    subject_init = models.CharField("Subject Initials", max_length=5, default=self.subject_initials)

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

আমি যদি লাইনটি এতে পরিবর্তন করি তবে আমি subject_init = models.CharField("Subject initials", max_length=2, default=subject_initials)সিঙ্কডিবি করতে পারি, তবে নতুন বিষয় তৈরি করতে পারি না।

জাঙ্গোতে কি এটি সম্ভব, কলযোগ্য ফাংশন থাকা অন্য ক্ষেত্রের মানের ভিত্তিতে কিছু ক্ষেত্রে ডিফল্ট দেয়?

(কৌতূহলের জন্য, আমি আমার স্টোর আদ্যক্ষর পৃথকভাবে আলাদা করতে চাইছি এমন বিরল ক্ষেত্রে যেখানে আমি ট্র্যাক করছি তার চেয়ে অদ্ভুত শেষ নামগুলি আলাদা থাকতে পারে Eg "জেএম" পরিবর্তে "জেএম" এবং প্রশাসক হিসাবে এটি সম্পাদনা ঠিক করতে চায়))

উত্তর:


89

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

আপনি যে প্রভাবটি চান তা পেতে মডেল ক্লাসের সেভ () পদ্ধতিটি ওভাররাইড করুন। প্রয়োজনে যে কোনও পরিবর্তন আপনি প্রয়োজনীয় করে নিন, তারপরে প্রকৃত সঞ্চয় করার জন্য সুপারক্লাসের পদ্ধতিতে কল করুন। এখানে একটি দ্রুত উদাহরণ।

def save(self, *args, **kwargs):
    if not self.subject_init:
        self.subject_init = self.subject_initials()
    super(Subject, self).save(*args, **kwargs)

এটি ডকুমেন্টেশনে ওভাররাইডিং মডেল পদ্ধতিগুলিতে আচ্ছাদিত ।


4
দ্রষ্টব্য যে পাইথন 3 এ আপনি রেফারেন্সড ডকুমেন্টেশনের উদাহরণ হিসাবে কেবল super().save(*args, **kwargs)( Subject, selfআর্গুমেন্ট ছাড়াই ) কল করতে পারেন ।
কুর্ট পিক

4
খুব খারাপ এটি অন্যটির উপর ভিত্তি করে ডিফল্ট মডেল বৈশিষ্ট্য মানটি সংজ্ঞা দিতে দেয় না যা অ্যাডমিন সাইডে বিশেষত কার্যকর (উদাহরণস্বরূপ, একটি স্ব-স্বীকৃত ক্ষেত্রের জন্য), যেহেতু এটি সংরক্ষণ করার সময় এটি পরিচালনা করে। নাকি আমি এটা ভুল বুঝছি?
ভাদোরকোয়েস্ট

18

যদি এই কাজ করার একটি ভাল উপায় নেই আমি জানি না, কিন্তু আপনি করতে পারেন একটি সংকেত হ্যান্ডলার ব্যবহার জন্য সংকেত :pre_save

from django.db.models.signals import pre_save

def default_subject(sender, instance, using):
    if not instance.subject_init:
        instance.subject_init = instance.subject_initials()

pre_save.connect(default_subject, sender=Subject)

4
আপনি এর post_saveপরিবর্তে আমদানি করেছেন pre_save
আলী রসিম কোকাল

4
@ আরোকোকাল: মাথা আপ করার জন্য ধন্যবাদ, ঠিক এটি ঠিক করা হয়েছে। আপনি এই ক্ষেত্রে নিজেকে সম্পাদনা করার পরামর্শ দিতে পারেন, এটি এই জাতীয় জিনিসগুলিকে ঠিক করতে সহায়তা করে :)
গবি পুরিকারু

4
দেখে মনে হচ্ছে এই বাস্তবায়নে **kwargsযে সমস্ত যুক্তিটি ডকস.ডজ্যাঙ্গোপ্রজেক্ট / এন / ২.০ / টপিকস / সিগন্যালস / এর মতে থাকা উচিত তা যুক্তিটি মিস করছে ?
কুর্ট পিক

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

7

ব্যবহার জ্যাঙ্গো সংকেত , এই বেশ আগে থেকেই কাজ করা যেতে পারে, গ্রহণ করে সংকেত মডেল থেকে।post_init

from django.db import models
import django.dispatch

class LoremIpsum(models.Model):
    name = models.CharField(
        "Name",
        max_length=30,
    )
    subject_initials = models.CharField(
        "Subject Initials",
        max_length=5,
    )

@django.dispatch.receiver(models.signals.post_init, sender=LoremIpsum)
def set_default_loremipsum_initials(sender, instance, *args, **kwargs):
    """
    Set the default value for `subject_initials` on the `instance`.

    :param sender: The `LoremIpsum` class that sent the signal.
    :param instance: The `LoremIpsum` instance that is being
        initialised.
    :return: None.
    """
    if not instance.subject_initials:
        instance.subject_initials = "".join(map(
                (lambda x: x[0] if x else ""),
                instance.name.split(" ")))

post_initসংকেত বর্গ দ্বারা প্রেরিত একবার এটি উদাহরণস্বরূপ উপর initialisation করেছেন করা হয়। এইভাবে, উদাহরণটি nameএটির অ-অযোগ্য ক্ষেত্রগুলি সেট করা আছে কিনা তা পরীক্ষার আগে একটি মান পেয়ে যায় ।


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

2

একটি বিকল্প বাস্তবায়ন হিসাবে Gabi Purcaru এর উত্তর, এছাড়াও আপনি সংযোগ করতে পারেন pre_saveসংকেত ব্যবহার করে receiverপ্রসাধক :

from django.db.models.signals import pre_save
from django.dispatch import receiver


@receiver(pre_save, sender=Subject)
def default_subject(sender, instance, **kwargs):
    if not instance.subject_init:
        instance.subject_init = instance.subject_initials()

এই রিসিভার ফাংশনটি **kwargsওয়াইল্ডকার্ড কীওয়ার্ড আর্গুমেন্টগুলিতেও নেয় যা সমস্ত সিগন্যাল হ্যান্ডলারদের অবশ্যই https://docs.djangoproject.com/en/2.0/topics/signals/#receiver-function অনুসারে গ্রহণ করতে হবে ।

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