किसी फ़ंक्शन कॉल / कॉल करने योग्य के लिए Django मॉडल फ़ील्ड का डिफ़ॉल्ट मान कैसे सेट करें (जैसे, मॉडल ऑब्जेक्ट निर्माण के समय के सापेक्ष दिनांक)


101

संपादित:

मैं हर बार एक नए मॉडल ऑब्जेक्ट के निर्माण का मूल्यांकन करने वाले फ़ंक्शन के लिए एक Django फ़ील्ड का डिफ़ॉल्ट कैसे सेट कर सकता हूं?

मैं निम्नलिखित कुछ करना चाहता हूं, सिवाय इसके कि इस कोड में कोड का एक बार मूल्यांकन हो जाता है और प्रत्येक मॉडल ऑब्जेक्ट के लिए एक ही तिथि के लिए डिफ़ॉल्ट सेट करता है, कोड के मूल्यांकन के बजाय हर बार जब कोई मॉडल ऑब्जेक्ट बनता है:

from datetime import datetime, timedelta
class MyModel(models.Model):
  # default to 1 day from now
  my_date = models.DateTimeField(default=datetime.now() + timedelta(days=1))



मूल:

मैं फ़ंक्शन पैरामीटर के लिए एक डिफ़ॉल्ट मान बनाना चाहता हूं जैसे कि यह गतिशील है और हर बार फ़ंक्शन को कॉल करने और सेट करने के लिए कहा जाता है। मैं उसे कैसे कर सकता हूँ? जैसे,

from datetime import datetime
def mydate(date=datetime.now()):
  print date

mydate() 
mydate() # prints the same thing as the previous call; but I want it to be a newer value

विशेष रूप से, मैं इसे Django में करना चाहता हूं, जैसे,

from datetime import datetime, timedelta
class MyModel(models.Model):
  # default to 1 day from now
  my_date = models.DateTimeField(default=datetime.now() + timedelta(days=1))

प्रश्न गलत है: इसका फंक्शन पैरामीटर डिफॉल्ट्स से कोई लेना-देना नहीं है। मेरा जवाब देखिए।
नेड बाचेल्डर

प्रति @ नेडबैचल्डर की टिप्पणी के अनुसार, मैंने अपना प्रश्न संपादित किया ("EDITED:" के रूप में इंगित किया गया) और मूल को छोड़ दिया ("मूल:" के रूप में संकेत दिया गया)
रोब बेडनार्क

जवाबों:


140

सवाल गुमराह करने वाला है। Django में एक मॉडल फ़ील्ड बनाते समय, आप फ़ंक्शन को परिभाषित नहीं कर रहे हैं, इसलिए फ़ंक्शन डिफ़ॉल्ट मान अप्रासंगिक हैं:

from datetime import datetime, timedelta
class MyModel(models.Model):
  # default to 1 day from now
  my_date = models.DateTimeField(default=datetime.now() + timedelta(days=1))

यह अंतिम पंक्ति एक फ़ंक्शन को परिभाषित नहीं कर रही है; यह कक्षा में एक क्षेत्र बनाने के लिए एक समारोह का आह्वान कर रहा है।

PRE Django 1.7

Django आपको डिफ़ॉल्ट के रूप में एक कॉल करने योग्य पास देता है , और यह हर बार इसे लागू करेगा, जैसा आप चाहते हैं:

from datetime import datetime, timedelta
class MyModel(models.Model):
  # default to 1 day from now
  my_date = models.DateTimeField(default=lambda: datetime.now() + timedelta(days=1))

Django 1.7+

कृपया ध्यान दें कि Django 1.7 के बाद से, डिफ़ॉल्ट मान के रूप में लैम्ब्डा का उपयोग अनुशंसित नहीं है (cf @stvnw टिप्पणी)। ऐसा करने का उचित तरीका यह है कि क्षेत्र से पहले एक फ़ंक्शन घोषित किया जाए और इसे डिफ़ॉल्ट में एक कॉल करने योग्य के रूप में उपयोग किया जाए जिसका नाम arg है:

from datetime import datetime, timedelta

# default to 1 day from now
def get_default_my_date():
  return datetime.now() + timedelta(days=1)

class MyModel(models.Model):
  my_date = models.DateTimeField(default=get_default_my_date)

@ साइमनस जवाब में अधिक जानकारी नीचे दी गई है


2
साभार @NedBatchelder यही वह है जिसकी तलाश में मैं हूं। मुझे महसूस नहीं हुआ कि 'डिफ़ॉल्ट' कॉल करने योग्य हो सकता है। और अब मैं देखता हूं कि फंक्शन इनवोकेशन बनाम फंक्शन डेफिनेशन के संबंध में मेरा सवाल वास्तव में कैसे गलत था।
रॉब बेडनर्क

25
ध्यान दें कि Django के लिए = 1.7 क्षेत्र विकल्पों के लिए लैम्ब्डा के उपयोग की अनुशंसा नहीं की जाती है, क्योंकि वे पलायन के साथ असंगत हैं। Ref: डॉक्स , टिकट
StvnW

4
कृपया इस उत्तर को अनचेक करें, क्योंकि यह Djange> = 1.7 के लिए गलत है। @ साइमनस द्वारा उत्तर बिल्कुल सही है और इसलिए इसे स्वीकार किया जाना चाहिए।
AplusKminus

यह पलायन के साथ कैसे काम करता है? क्या सभी पुरानी वस्तुओं को प्रवास के समय के आधार पर तारीख मिलती है? क्या माइग्रेशन के साथ उपयोग किए जाने के लिए एक अलग डिफ़ॉल्ट सेट करना संभव है?
१t:०५ पर टाइमथेलियन '

3
क्या होगा अगर मैं कुछ पैरामीटर पास करना चाहता हूं get_default_my_date?
सदन ए।

59

ऐसा करना default=datetime.now()+timedelta(days=1)बिलकुल गलत है!

इसका मूल्यांकन तब होता है जब आप django का उदाहरण शुरू करते हैं। यदि आप अपाचे के अधीन हैं तो यह शायद काम करेगा, क्योंकि कुछ कॉन्फ़िगरेशन पर अपाचे आपके अनुरोध पर आपके django आवेदन को रद्द कर देता है, लेकिन फिर भी आप अपने कोड के माध्यम से किसी दिन स्वयं को ढूंढ सकते हैं और यह पता लगाने की कोशिश कर सकते हैं कि यह गणना आपकी अपेक्षा के अनुरूप क्यों नहीं है। ।

ऐसा करने का सही तरीका डिफ़ॉल्ट तर्क के लिए एक कॉल करने योग्य ऑब्जेक्ट को पास करना है। यह एक datetime.today फ़ंक्शन या आपका कस्टम फ़ंक्शन हो सकता है। फिर हर बार जब आप नए डिफ़ॉल्ट मान का अनुरोध करते हैं तो इसका मूल्यांकन हो जाता है।

def get_deadline():
    return datetime.today() + timedelta(days=20)

class Bill(models.Model):
    name = models.CharField(max_length=50)
    customer = models.ForeignKey(User, related_name='bills')
    date = models.DateField(default=datetime.today)
    deadline = models.DateField(default=get_deadline)

21
यदि मेरा डिफ़ॉल्ट मॉडल में किसी अन्य फ़ील्ड के मूल्य पर आधारित है, तो क्या उस फ़ील्ड को पैरामीटर के रूप में पास करना संभव है जैसे कि कुछ में get_deadline(my_parameter)?
YPCrumble

@YPCrumble यह एक नया प्रश्न होना चाहिए!
jsmedmar

2
नहीं। यह संभव नहीं है। आपको इसे करने के लिए कुछ अलग दृष्टिकोण का उपयोग करना होगा।
सिमंस

फ़ंक्शन deadlineको हटाते समय आप फ़ील्ड को फिर से कैसे हटाते get_deadlineहैं? मैंने डिफ़ॉल्ट मान के लिए फ़ंक्शन के साथ एक फ़ील्ड निकाल दिया है, लेकिन अब Django फ़ंक्शन को हटाने के बाद स्टार्टअप पर क्रैश हो जाता है। मैं मैन्युअल रूप से माइग्रेशन को संपादित कर सकता हूं, जो इस मामले में ठीक होगा, लेकिन क्या होगा यदि आप बस डिफ़ॉल्ट फ़ंक्शन को बदलते हैं, और पुराने फ़ंक्शन को निकालना चाहते हैं?
बर्लिन

8

निम्नलिखित दो DateTimeField निर्माणकर्ताओं के बीच एक महत्वपूर्ण अंतर है:

my_date = models.DateTimeField(auto_now=True)
my_date = models.DateTimeField(auto_now_add=True)

यदि आप auto_now_add=Trueकंस्ट्रक्टर में उपयोग करते हैं, तो my_date द्वारा संदर्भित डेटाइम "अपरिवर्तनीय" है (केवल एक बार सेट होने पर पंक्ति तालिका में डाली जाती है)।

auto_now=Trueहालाँकि, ऑब्जेक्ट को सहेजे जाने के बाद , हर बार डेटाटाइम मान अपडेट किया जाएगा।

यह निश्चित रूप से एक बिंदु पर मेरे लिए एक गोचा था। संदर्भ के लिए, डॉक्स यहां हैं:

https://docs.djangoproject.com/en/dev/ref/models/fields/#datetimefield


3
आपने स्वतः की अपनी परिभाषाएँ प्राप्त की हैं auto_now और auto_now_add मिश्रित हैं, यह दूसरा तरीका है।
माइकल बेट्स

@MichaelBates अब बेहतर है?
हेंडी इरावन

4

कभी-कभी आपको नया उपयोगकर्ता मॉडल बनाने के बाद मॉडल डेटा तक पहुंचने की आवश्यकता हो सकती है।

यहां बताया गया है कि मैं अपने उपयोगकर्ता नाम के पहले 4 वर्णों का उपयोग करके प्रत्येक नए उपयोगकर्ता प्रोफ़ाइल के लिए एक टोकन उत्पन्न करता हूं:

from django.dispatch import receiver
class Profile(models.Model):
    auth_token = models.CharField(max_length=13, default=None, null=True, blank=True)


@receiver(post_save, sender=User) # this is called after a User model is saved.
def create_user_profile(sender, instance, created, **kwargs):
    if created: # only run the following if the profile is new
        new_profile = Profile.objects.create(user=instance)
        new_profile.create_auth_token()
        new_profile.save()

def create_auth_token(self):
    import random, string
    auth = self.user.username[:4] # get first 4 characters in user name
    self.auth_token =  auth + ''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits + string.ascii_lowercase) for _ in range(random.randint(3, 5)))

3

आप सीधे ऐसा नहीं कर सकते; डिफ़ॉल्ट मान का मूल्यांकन तब किया जाता है जब फ़ंक्शन परिभाषा का मूल्यांकन किया जाता है। लेकिन इसके आसपास दो तरीके हैं।

सबसे पहले, आप प्रत्येक बार एक नया फ़ंक्शन बना सकते हैं (और फिर कॉल कर सकते हैं)।

या, और अधिक, बस डिफ़ॉल्ट को चिह्नित करने के लिए एक विशेष मूल्य का उपयोग करें। उदाहरण के लिए:

from datetime import datetime
def mydate(date=None):
  if date is None:
    date = datetime.now()
  print date

यदि Noneयह पूरी तरह से उचित पैरामीटर मान है, और इसके स्थान पर आपके द्वारा उपयोग किए जा सकने वाला कोई अन्य उचित मूल्य नहीं है, तो आप बस एक नया मान बना सकते हैं जो निश्चित रूप से आपके फ़ंक्शन के डोमेन के बाहर है:

from datetime import datetime
class _MyDateDummyDefault(object):
  pass
def mydate(date=_MyDateDummyDefault):
  if date is _MyDateDummyDefault:
    date = datetime.now()
  print date
del _MyDateDummyDefault

कुछ दुर्लभ मामलों में, आप मेटा-कोड लिख रहे हैं जो वास्तव में पूरी तरह से कुछ भी लेने में सक्षम होने की आवश्यकता है, यहां तक ​​कि, कहते हैं mydate.func_defaults[0],। उस मामले में, आपको कुछ इस तरह करना होगा:

def mydate(*args, **kw):
  if 'date' in kw:
    date = kw['date']
  elif len(args):
    date = args[0]
  else:
    date = datetime.now()
  print date

1
ध्यान दें कि वास्तव में डमी मूल्य वर्ग को तुरंत करने का कोई कारण नहीं है - बस कक्षा को डमी मूल्य के रूप में उपयोग करें।
अंबर

आप इसे सीधे कर सकते हैं, फ़ंक्शन फ़ंक्शन के परिणाम के बजाय फ़ंक्शन में पास करें। मेरा पोस्ट किया गया जवाब देखें।

नहीं, तुम नहीं कर सकते। फ़ंक्शन का परिणाम सामान्य मापदंडों के समान नहीं है, इसलिए इसे सामान्य पैरामीटर के लिए डिफ़ॉल्ट मान के रूप में यथोचित उपयोग नहीं किया जा सकता है।
4

1
ठीक है, यदि आप किसी फ़ंक्शन के बजाय ऑब्जेक्ट में पास करते हैं तो यह एक अपवाद को बढ़ाएगा। यदि आप किसी स्ट्रिंग की अपेक्षा पैरामीटर में फ़ंक्शन पास करते हैं तो यह सच है। मैं नहीं देखता कि यह कैसे प्रासंगिक है।

यह प्रासंगिक है क्योंकि उसका myfuncकार्य लेने (और प्रिंट करने के लिए) बनाया गया है datetime; आपने इसे बदल दिया है इसलिए इसका उपयोग उस तरह से नहीं किया जा सकता है।
4

2

फ़ंक्शन कॉल के परिणाम में पास होने के बजाय फ़ंक्शन को पैरामीटर के रूप में पास करें।

इसके बजाय, यह है:

def myfunc(date=datetime.now()):
    print date

इसे इस्तेमाल करे:

def myfunc(date=datetime.now):
    print date()

यह काम नहीं करता है, क्योंकि अब उपयोगकर्ता वास्तव में एक पैरामीटर को पारित नहीं कर सकता है - आप इसे एक फ़ंक्शन के रूप में कॉल करने और एक अपवाद फेंकने की कोशिश करेंगे। जिस स्थिति में आप बस print datetime.now()बिना किसी परमानेंट और बिना शर्त के ले सकते हैं ।
बजे

कोशिश करो। आप कोई दिनांक नहीं दे रहे हैं, आप datetime.now फ़ंक्शन को पास कर रहे हैं।

हां, डिफ़ॉल्ट datetime.nowफंक्शन पास कर रहा है । लेकिन कोई भी उपयोगकर्ता जो एक गैर-डिफ़ॉल्ट मान से गुजरता है, वह फ़ंक्शन नहीं बल्कि डेटटाइम पार कर जाएगा। foo = datetime.now(); myfunc(foo)उठाएंगे TypeError: 'datetime.datetime' object is not callable। अगर मैं वास्तव में आपके फ़ंक्शन का उपयोग करना चाहता था, तो मुझे myfunc(lambda: foo)इसके बजाय कुछ करना होगा , जो एक उचित इंटरफ़ेस नहीं है।
बजे

1
कार्य स्वीकार करने वाले इंटरफेस असामान्य नहीं हैं। मैं अजगर stdlib से उदाहरण नामकरण शुरू कर सकता है, अगर आप की तरह।

2
Django पहले से ही एक कॉल करने योग्य स्वीकार करता है जैसा कि यह सवाल बताता है।
नेड बाचेल्डर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.