জাজানো ইন্টিজারফিল্ডটি পছন্দসই…… নাম অনুসারে সেট করুন


109

যখন আপনার কাছে একটি পছন্দ বিকল্পের সাথে একটি মডেল ক্ষেত্র থাকে তখন আপনার কিছু পাঠযোগ্য নামগুলির সাথে জাদু মান যুক্ত থাকে। জ্যাঙ্গোতে কি মানের পরিবর্তে মানব পাঠযোগ্য নাম দ্বারা এই ক্ষেত্রগুলি সেট করার সুবিধাজনক উপায় আছে?

এই মডেলটি বিবেচনা করুন:

class Thing(models.Model):
  PRIORITIES = (
    (0, 'Low'),
    (1, 'Normal'),
    (2, 'High'),
  )

  priority = models.IntegerField(default=0, choices=PRIORITIES)

এক পর্যায়ে আমাদের কাছে একটি বিষয় রয়েছে এবং আমরা এর অগ্রাধিকারটি সেট করতে চাই। অবশ্যই আপনি করতে পারেন,

thing.priority = 1

তবে এটি আপনাকে অগ্রাধিকারের মান-নাম ম্যাপিং মুখস্থ করতে বাধ্য করে। এটি কাজ করে না:

thing.priority = 'Normal' # Throws ValueError on .save()

বর্তমানে আমার এই নির্বাক কাজটি রয়েছে:

thing.priority = dict((key,value) for (value,key) in Thing.PRIORITIES)['Normal']

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

উত্তর:


164

এখানে দেখা হিসাবে কি । তারপরে আপনি এমন একটি শব্দ ব্যবহার করতে পারেন যা যথাযথ পূর্ণসংখ্যাকে উপস্থাপন করে।

তাই ভালো:

LOW = 0
NORMAL = 1
HIGH = 2
STATUS_CHOICES = (
    (LOW, 'Low'),
    (NORMAL, 'Normal'),
    (HIGH, 'High'),
)

তারপরে তারা এখনও ডিবিতে পূর্ণসংখ্যা হয়।

ব্যবহার হবে thing.priority = Thing.NORMAL


2
বিষয়টিতে একটি সুন্দর বিস্তারিত ব্লগ পোস্ট করা। গুগলের সাথে খুঁজে পাওয়াও খুব কঠিন তাই ধন্যবাদ।
আলেকজান্ডার লাজংবার্গ

1
এফডব্লিউআইডাব্লু, যদি আপনার এটি একটি আক্ষরিক স্ট্রিং (সম্ভবত কোনও ফর্ম, ব্যবহারকারীর ইনপুট, বা অনুরূপ থেকে) সেট করা দরকার হয় তবে আপনি কেবল এটি করতে পারেন: জিনিস.প্রাইরিটি = গ্যাটআটার (জিনিস, স্ট্রভালিউ.উপার ())।
মুরুনি

1
সত্যিই ব্লগের এনক্যাপসুলেশন বিভাগটি পছন্দ করুন।
নাথন কেলার

আমার একটি সমস্যা আছে: আমি সবসময় অ্যাডমিনের ডিফল্ট মান দেখতে পাই! আমি পরীক্ষা করেছি যে মানটি সত্যিই পরিবর্তিত হয়! আমার এখন কি করা উচিত?
মাহদি

এটি যাওয়ার উপায় তবে সাবধান থাকুন: আপনি যদি ভবিষ্যতে পছন্দগুলি যুক্ত করেন বা সরিয়ে থাকেন তবে আপনার সংখ্যাটি অনুক্রমিক হবে না। ভবিষ্যতে বিভ্রান্তি না ঘটে এবং আপনি ডিবি সংঘর্ষে দৌড়াবেন না এমন হিসাবে আপনি সম্ভবত অবজ্ঞাপিত পছন্দগুলি মন্তব্য করতে পারেন।
গ্রোকপট

7

আমি সম্ভবত একবার এবং সকলের জন্য বিপরীত দর্শন স্থাপন করব, তবে আমি যদি কেবল এটি ব্যবহার না করতাম:

thing.priority = next(value for value, name in Thing.PRIORITIES
                      if name=='Normal')

এটিকে আবার টস করতে ফ্লাইটিতে ডিক তৈরির চেয়ে সহজ বলে মনে হচ্ছে ;-)।


হ্যাঁ, ডিকটি টস করা একটু নির্বোধ, এখন আপনি এটি বলছেন। :)
আলেকজান্ডার লাজংবার্গ

7

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

  class ChoiceField(models.IntegerField):
    def __init__(self, choices, **kwargs):
        if not hasattr(choices[0],'__iter__'):
            choices = zip(range(len(choices)), choices)

        self.val2choice = dict(choices)
        self.choice2val = dict((v,k) for k,v in choices)

        kwargs['choices'] = choices
        super(models.IntegerField, self).__init__(**kwargs)

    def to_python(self, value):
        return self.val2choice[value]

    def get_db_prep_value(self, choice):
        return self.choice2val[choice]

1
এটা খারাপ অ্যালান না। ধন্যবাদ!
আলেকজান্ডার লাজংবার্গ

5

আমি ধ্রুবক সংজ্ঞায়িত পদ্ধতিটির প্রশংসা করি তবে আমি বিশ্বাস করি এই কাজের জন্য এনুম প্রকারটি সবচেয়ে ভাল। আপনার কোডটি আরও পঠনযোগ্য রাখার সময় তারা একই সময়ে কোনও আইটেমের জন্য পূর্ণসংখ্যা এবং একটি স্ট্রিং উপস্থাপন করতে পারে।

এনামগুলি পাইথনের সাথে 3.4 সংস্করণে প্রবর্তিত হয়েছিল। আপনি যদি কোনও নিম্ন ব্যবহার করে থাকেন (যেমন v2.x) আপনি এখনও ব্যাকপোর্ট প্যাকেজ ইনস্টল করে এটি পেতে পারেন :pip install enum34

# myapp/fields.py
from enum import Enum    


class ChoiceEnum(Enum):

    @classmethod
    def choices(cls):
        choices = list()

        # Loop thru defined enums
        for item in cls:
            choices.append((item.value, item.name))

        # return as tuple
        return tuple(choices)

    def __str__(self):
        return self.name

    def __int__(self):
        return self.value


class Language(ChoiceEnum):
    Python = 1
    Ruby = 2
    Java = 3
    PHP = 4
    Cpp = 5

# Uh oh
Language.Cpp._name_ = 'C++'

এটি বেশ অনেক কিছুই। আপনি উত্তরাধিকারী হতে পারেChoiceEnumআপনার নিজের সংজ্ঞা তৈরি হতে পারেন এবং এগুলি একটি মডেল সংজ্ঞায় যেমন ব্যবহার করতে পারেন:

from django.db import models
from myapp.fields import Language

class MyModel(models.Model):
    language = models.IntegerField(choices=Language.choices(), default=int(Language.Python))
    # ...

আপনার অনুমান হিসাবে জিজ্ঞাসাবাদ করা কেকটিতে আইসিং দিচ্ছে:

MyModel.objects.filter(language=int(Language.Ruby))
# or if you don't prefer `__int__` method..
MyModel.objects.filter(language=Language.Ruby.value)

স্ট্রিং তাদের প্রতিনিধিত্ব করা সহজ করা হয়েছে:

# Get the enum item
lang = Language(some_instance.language)

print(str(lang))
# or if you don't prefer `__str__` method..
print(lang.name)

# Same as get_FOO_display
lang.name == some_instance.get_language_display()

1
তোমার মত একটি বেস বর্গ পরিচয় করিয়ে দিতে পছন্দ না করেন ChoiceEnum, আপনি ব্যবহার করতে পারেন .valueএবং .name@kirpit বর্ণনা এবং ব্যবহারের প্রতিস্থাপন choices()সঙ্গে tuple([(x.value, x.name) for x in cls])--either একটি ফাংশন (শুষ্ক) সরাসরি ক্ষেত্রের কন্সট্রাকটর অথবা।
শেঠ

4
class Sequence(object):
    def __init__(self, func, *opts):
        keys = func(len(opts))
        self.attrs = dict(zip([t[0] for t in opts], keys))
        self.choices = zip(keys, [t[1] for t in opts])
        self.labels = dict(self.choices)
    def __getattr__(self, a):
        return self.attrs[a]
    def __getitem__(self, k):
        return self.labels[k]
    def __len__(self):
        return len(self.choices)
    def __iter__(self):
        return iter(self.choices)
    def __deepcopy__(self, memo):
        return self

class Enum(Sequence):
    def __init__(self, *opts):
        return super(Enum, self).__init__(range, *opts)

class Flags(Sequence):
    def __init__(self, *opts):
        return super(Flags, self).__init__(lambda l: [1<<i for i in xrange(l)], *opts)

এটি এর মতো ব্যবহার করুন:

Priorities = Enum(
    ('LOW', 'Low'),
    ('NORMAL', 'Normal'),
    ('HIGH', 'High')
)

priority = models.IntegerField(default=Priorities.LOW, choices=Priorities)

3

জ্যাঙ্গো 3.0 হিসাবে, আপনি ব্যবহার করতে পারেন:

class ThingPriority(models.IntegerChoices):
    LOW = 0, 'Low'
    NORMAL = 1, 'Normal'
    HIGH = 2, 'High'


class Thing(models.Model):
    priority = models.IntegerField(default=ThingPriority.LOW, choices=ThingPriority.choices)

# then in your code
thing = get_my_thing()
thing.priority = ThingPriority.HIGH

1

আপনার পছন্দের মানব পাঠযোগ্য মানগুলির সাথে কেবল আপনার সংখ্যাগুলি প্রতিস্থাপন করুন। যেমন:

PRIORITIES = (
('LOW', 'Low'),
('NORMAL', 'Normal'),
('HIGH', 'High'),
)

এটি এটিকে মানব পাঠযোগ্য করে তোলে তবে আপনাকে নিজের ক্রম সংজ্ঞায়িত করতে হবে।


1

আমার উত্তরটি খুব দেরি হয়ে গেছে এবং আজকাল-জাঙ্গো বিশেষজ্ঞদের কাছে এটি সম্ভবত স্পষ্ট বলে মনে হচ্ছে তবে এখানে যে কেউ অবতরণ করেন, আমি সম্প্রতি জাঙ্গো-মডেল-ইউটিস দ্বারা আনা একটি খুব মার্জিত সমাধান আবিষ্কার করেছি: https://django-model-utils.readthedocs.io/ bn / সর্বশেষ / utilities.html # পছন্দ

এই প্যাকেজটি আপনাকে তিন-টি-টিপল দিয়ে পছন্দগুলি সংজ্ঞায়িত করতে দেয় যেখানে:

  • প্রথম আইটেমটি ডাটাবেস মান
  • দ্বিতীয় আইটেমটি একটি কোড-পঠনযোগ্য মান
  • তৃতীয় আইটেমটি একটি মানব-পঠনযোগ্য মান

সুতরাং আপনি যা করতে পারেন তা এখানে:

from model_utils import Choices

class Thing(models.Model):
    PRIORITIES = Choices(
        (0, 'low', 'Low'),
        (1, 'normal', 'Normal'),
        (2, 'high', 'High'),
      )

    priority = models.IntegerField(default=PRIORITIES.normal, choices=PRIORITIES)

thing.priority = getattr(Thing.PRIORITIES.Normal)

এই পথে:

  • আপনার ক্ষেত্রের মানটি বেছে নিতে আপনি আপনার মানব-পঠনযোগ্য মানটি ব্যবহার করতে পারেন (আমার ক্ষেত্রে এটি দরকারী কারণ আমি বন্য সামগ্রীকে স্ক্র্যাপ করছি এবং এটি একটি সাধারণ উপায়ে সংরক্ষণ করছি)
  • একটি পরিষ্কার মান আপনার ডাটাবেসে সঞ্চিত আছে
  • আপনার কাছে করণাবিহীন কিছুই নেই;)

উপভোগ করুন :)


1
জ্যাঙ্গো-মডেল-ব্যবহারগুলি আনতে সম্পূর্ণ বৈধ। পঠনযোগ্যতা বাড়াতে একটি ছোট পরামর্শ; ডিফল্ট প্যারামিটারে ডট-নোটেশনটিও ব্যবহার করুন: priority = models.IntegerField(default=PRIORITIES.Low, choices=PRIORITIES)(এটি বলা বাহুল্য, অগ্রাধিকারের কাজটি থিং-ক্লাসের ভিতরে থাকতে ইন্টেন্ট করা উচিত) ind অজগর শনাক্তকারীটির জন্য ছোট হাতের অক্ষর / অক্ষরগুলি ব্যবহার করার বিষয়েও বিবেচনা করুন, কারণ আপনি কোনও শ্রেণীর কথা উল্লেখ করছেন না, পরিবর্তে একটি প্যারামিটার (আপনার পছন্দগুলি পরে হয়ে যাবে: (0, 'low', 'Low'),এবং আরও অনেক কিছু)।
কিম

0

মূলত আমি @ অ্যালানের উত্তরের একটি পরিবর্তিত সংস্করণ ব্যবহার করেছি:

from enum import IntEnum, EnumMeta

class IntegerChoiceField(models.IntegerField):
    def __init__(self, choices, **kwargs):
        if hasattr(choices, '__iter__') and isinstance(choices, EnumMeta):
            choices = list(zip(range(1, len(choices) + 1), [member.name for member in list(choices)]))

        kwargs['choices'] = choices
        super(models.IntegerField, self).__init__(**kwargs)

    def to_python(self, value):
        return self.choices(value)

    def get_db_prep_value(self, choice):
        return self.choices[choice]

models.IntegerChoiceField = IntegerChoiceField

GEAR = IntEnum('GEAR', 'HEAD BODY FEET HANDS SHIELD NECK UNKNOWN')

class Gear(Item, models.Model):
    # Safe to assume last element is largest value member of an enum?
    #type = models.IntegerChoiceField(GEAR, default=list(GEAR)[-1].name)
    largest_member = GEAR(max([member.value for member in list(GEAR)]))
    type = models.IntegerChoiceField(GEAR, default=largest_member)

    def __init__(self, *args, **kwargs):
        super(Gear, self).__init__(*args, **kwargs)

        for member in GEAR:
            setattr(self, member.name, member.value)

print(Gear().HEAD, (Gear().HEAD == GEAR.HEAD.value))

django-enumfieldsআমি এখন যে প্যাকেজ প্যাকেজটি ব্যবহার করি তার সাথে সরলীকৃত :

from enumfields import EnumIntegerField, IntEnum

GEAR = IntEnum('GEAR', 'HEAD BODY FEET HANDS SHIELD NECK UNKNOWN')

class Gear(Item, models.Model):
    # Safe to assume last element is largest value member of an enum?
    type = EnumIntegerField(GEAR, default=list(GEAR)[-1])
    #largest_member = GEAR(max([member.value for member in list(GEAR)]))
    #type = EnumIntegerField(GEAR, default=largest_member)

    def __init__(self, *args, **kwargs):
        super(Gear, self).__init__(*args, **kwargs)

        for member in GEAR:
            setattr(self, member.name, member.value)

0

মডেলের পছন্দসমূহ বিকল্পটি এই ক্ষেত্রের জন্য পছন্দ হিসাবে ব্যবহার করতে যথাযথ দুটি আইটেমের (যেমন [(এ, বি), (এ, বি) ...]) এর পুনরাবৃত্তির সমন্বয়ে একটি ক্রম গ্রহণ করে।

উপরন্তু, জ্যাঙ্গো উপলব্ধ শুমার ধরনের যে আপনি একটি সংক্ষিপ্ত ভাবে পছন্দ সংজ্ঞায়িত করতে উপশ্রেণী করতে পারেন:

class ThingPriority(models.IntegerChoices):
    LOW = 0, _('Low')
    NORMAL = 1, _('Normal')
    HIGH = 2, _('High')

class Thing(models.Model):
    priority = models.IntegerField(default=ThingPriority.NORMAL, choices=ThingPriority.choices)

জ্যাঙ্গো মানব-পঠনযোগ্য নাম বা লেবেল হিসাবে ব্যবহৃত হতে পারে এই টিপলের শেষে একটি অতিরিক্ত স্ট্রিং মান যুক্ত করে supports লেবেলটি অলস অনুবাদযোগ্য স্ট্রিং হতে পারে।

   # in your code 
   thing = get_thing() # instance of Thing
   thing.priority = ThingPriority.LOW

নোট: যে ব্যবহার করে আপনি ব্যবহার করতে পারেন ThingPriority.HIGH, ThingPriority.['HIGH']অথবা ThingPriority(0)অ্যাক্সেস বা লুকআপ enum জন সদস্য পর্যন্ত।

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