একটি জ্যাঙ্গো মডেলের কাস্টম সেভ () পদ্ধতিতে আপনার কীভাবে একটি নতুন অবজেক্ট সনাক্ত করা উচিত?


172

আমি যখন একটি নতুন রেকর্ড সংরক্ষণ করছি (বিদ্যমান রেকর্ডটি আপডেট না করে) তখন জাঙ্গো মডেল অবজেক্টের সংরক্ষণ () পদ্ধতিতে একটি বিশেষ ক্রিয়াটি ট্রিগার করতে চাই)

স্ব-রেকর্ডটি গ্যারান্টিযুক্ত (স্ব.আইডি! = কিছুই নয়) জন্য চেক করা প্রয়োজনীয় এবং যথেষ্ট এবং নতুন আপডেট হচ্ছে না? কোন বিশেষ ক্ষেত্রে এটি উপেক্ষা করা যেতে পারে?


সঠিক উত্তর হিসাবে stackoverflow.com/a/35647389/8893667 নির্বাচন করুন । উত্তর অনেক ক্ষেত্রে যেমন কাজ করে নাUUIDField pk
কোটলিনবয়

উত্তর:


204

আপডেট হয়েছে: স্পষ্টকরণের সাথে যা self._stateকোনও ব্যক্তিগত উদাহরণ পরিবর্তনশীল নয়, তবে দ্বন্দ্ব এড়ানোর জন্য সেই পথটির নামকরণ করা হয়েছে, self._state.addingএখন চেক করা চেক করার সবচেয়ে ভাল উপায়।


self.pk is None:

নতুন মডেল অবজেক্টের মধ্যে সত্যটি ফিরে আসে, যদি না অবজেক্টটির এর UUIDFieldমতো থাকে primary_key

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


20
অবজেক্টের সাথে পরিচয় চেক করার is notপরিবর্তে আপনার ব্যবহার করা উচিত!=None
বেন জেমস

3
সমস্ত মডেলের একটি আইডি বৈশিষ্ট্য থাকে না, অর্থাত্ একটি মডেলের সাথে অন্যটির প্রসার ঘটে models.OneToOneField(OtherModel, primary_key=True)। আমার মনে হয় আপনার ব্যবহার করা দরকারself.pk
এজেপি

4
এটি কিছু ক্ষেত্রে কাজ করতে পারে না। : এই উত্তর দয়া করে চেক করুন stackoverflow.com/a/940928/145349
fjsj

5
এটি সঠিক উত্তর নয়। যদি UUIDFieldকোনও প্রাথমিক কী হিসাবে ব্যবহার করা হয় তবে self.pkতা কখনই হয় না None
ড্যানিয়েল ভ্যান ফ্লাইম্যান

1
পার্শ্ব দ্রষ্টব্য: এই উত্তরটি পূর্ব-তারিখযুক্ত ইউইউডিফিল্ড।
ডেভ ডাব্লু স্মিথ

190

বিকল্প পদ্ধতিতে self.pkআমরা self._stateমডেলটি পরীক্ষা করতে পারি

self._state.adding is True তৈরি

self._state.adding is False আপডেট

আমি এই পৃষ্ঠা থেকে এটি পেয়েছি


12
কাস্টম প্রাথমিক কী ক্ষেত্রটি ব্যবহার করার সময় এটিই একমাত্র সঠিক উপায়।
ওয়েবটিউইকস

9
কীভাবে self._state.addingকাজ করে তার সমস্ত বিশদ সম্পর্কে নিশ্চিত নন , তবে ন্যায্য সতর্কতা যে Falseআপনি কল করার পরে এটি পরীক্ষা করলে এটি সর্বদা সমান বলে মনে হয় super(TheModel, self).save(*args, **kwargs): github.com/django/django/blob/stable/1.10.x/django/db/models/ …
agilgur5

1
এটি সঠিক উপায় এবং সঠিক উত্তর হিসাবে উপস্থাপন / সেট করা উচিত।
ফ্লুংগো

7
@ গিভাল: _stateব্যক্তিগত নয়; যেমন _metaক্ষেত্রের নামগুলি নিয়ে বিভ্রান্তি এড়াতে এটি আন্ডারস্কোর দিয়ে উপসর্গযুক্ত। (লক্ষ্য করুন কিভাবে এটি সংযুক্ত ডকুমেন্টেশন ব্যবহৃত।)
Ry-

2
এই হল সর্বোত্তম উপায়। আমি is_new = self._state.addingতখন super(MyModel, self).save(*args, **kwargs)এবং তারপরে ব্যবহার করেছিif is_new: my_custom_logic()
কোটারফা :


39

জন্য চেক self.pk == Noneকরা হয় না যদি বস্তুর সন্নিবেশিত বা ডাটাবেসের মধ্যে আপডেট করা যাচ্ছে তা নির্ধারণ করতে যথেষ্ট।

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

এটি করার কারণ হ'ল কারণ যখন কোনও বস্তু তৈরি হবে তখন আপনাকে পিকে সেট করার অনুমতি দেওয়া হবে। যদিও আপনার প্রাথমিক কীটির জন্য সিকোয়েন্স কলাম রয়েছে সেখানে সাধারণ না হলেও এটি অন্যান্য প্রকারের প্রাথমিক কী ক্ষেত্রের জন্য ধারণ করে না।

আপনি যদি সত্যিই জানতে চান তবে আপনাকে ও / আরএম কী করতে হবে এবং ডাটাবেসে সন্ধান করতে হবে।

অবশ্যই আপনার কোডে একটি নির্দিষ্ট ঘটনাতে আছে এবং যে জন্য এটা বেশ সম্ভবত যে self.pk == Noneআপনি সব আপনাকে জানতে হবে বলে, কিন্তু এটা না একটি সাধারণ সমাধান।


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

1
এটি বিশেষত সত্য যখন আপনি নিজের এবং ডাটাবেসের মাধ্যমে প্রাথমিক কী বরাদ্দ করেন। সেক্ষেত্রে সুনির্দিষ্ট কাজটি হ'ল ডিবিতে বেড়াতে যাওয়া।
কনস্টান্টাইন এম

1
এমনকি যদি আপনার অ্যাপ্লিকেশন কোডটি আপনার পরীক্ষার ক্ষেত্রেগুলির জন্য পিকগুলি স্পষ্টভাবে নির্দিষ্ট করে না তবে p যদিও পরীক্ষাগুলির আগে এগুলি সাধারণত লোড করা হয় এটি কোনও সমস্যা নাও হতে পারে।
রিসাদিনহা

1
এই ব্যবহারের ক্ষেত্রে বিশেষভাবে সত্য UUIDFieldপ্রাথমিক কী হিসাবে: কী ডিবি পর্যায়ে জনবহুল করা নেই, তাই self.pkসর্বদা True
ড্যানিয়েল ভ্যান ফ্লাইম্যান

10

আপনি কেবল পোস্ট_সেভ সিগন্যালে সংযোগ করতে পারেন যা "তৈরি করা" কাওয়ার্গ্স প্রেরণ করে, যদি সত্য হয় তবে আপনার অবজেক্টটি sertedোকানো হয়েছে।

http://docs.djangoproject.com/en/stable/ref/signals/#post-save


8
এটি প্রচুর বোঝা থাকলে সম্ভাব্যভাবে বর্ণের পরিস্থিতি তৈরি করতে পারে। এর কারণ পোস্ট_সেভ সিগন্যালটি সেভ করে প্রেরণ করা হয়েছে তবে লেনদেনটি প্রতিশ্রুতিবদ্ধ হওয়ার আগে। এটি সমস্যাযুক্ত হতে পারে এবং জিনিসগুলি ডিবাগ করা খুব কঠিন করে তুলতে পারে।
আবেল মোহলার

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

7

পতাকা self.idএবং জন্য পরীক্ষা করুন force_insert

if not self.pk or kwargs.get('force_insert', False):
    self.created = True

# call save method.
super(self.__class__, self).save(*args, **kwargs)

#Do all your post save actions in the if block.
if getattr(self, 'created', False):
    # So something
    # Do something else

এটি সুবিধাজনক কারণ আপনার নতুন নির্মিত বস্তুর (স্ব) এটির pkমূল্য রয়েছে


5

আমি এই কথোপকথনের খুব দেরী হয়েছি, তবে আমি যখন সেলফ.পি.কে.র সাথে একটি ডিফল্ট মান যুক্ত হয় তখন এটি জনবহুল হয়ে একটি সমস্যায় পড়েছিলাম।

আমি যেভাবে এটি পেয়েছি তা মডেলটিতে একটি তারিখ_সৃষ্ট ক্ষেত্র যুক্ত করছে

date_created = models.DateTimeField(auto_now_add=True)

এখান থেকে আপনি যেতে পারেন

created = self.date_created is None


4

এমন একটি সমাধানের জন্য যা আপনার কাছে UUIDFieldপ্রাথমিক কী হিসাবে থাকা সত্ত্বেও কার্যকর হয় (যা অন্যরা উল্লেখ করেছেন Noneযে আপনি যদি ওভাররাইড করেন না তবে save), আপনি জ্যাঙ্গোর পোস্ট_সেভ সিগন্যালে প্লাগ করতে পারেন । আপনার এই যোগ models.py :

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

@receiver(post_save, sender=MyModel)
def mymodel_saved(sender, instance, created, **kwargs):
    if created:
        # do extra work on your instance, e.g.
        # instance.generate_avatar()
        # instance.send_email_notification()
        pass

এই কলব্যাকটি saveপদ্ধতিটিকে অবরুদ্ধ করবে , সুতরাং আপনি প্রতিক্রিয়াটি তারের উপর ফিরে প্রেরণের আগে আপনি ট্রিগার বিজ্ঞপ্তি বা মডেলটিকে আরও আপডেট করার মতো জিনিসগুলি করতে পারেন, আপনি ফর্ম ব্যবহার করছেন বা এজাজ কলগুলির জন্য জ্যাঙ্গো আরএসটি ফ্রেমওয়ার্ক framework অবশ্যই, দায়িত্বের সাথে ব্যবহার করুন এবং আপনার ব্যবহারকারীদের অপেক্ষা না করে কাজের ভারে ভারী কাজগুলি অফলোড করুন :)


3

বরং আইডির পরিবর্তে পিকে ব্যবহার করুন :

if not self.pk:
  do_something()

1

এটি করার সাধারণ উপায়।

ডিবিতে প্রথমবার সংরক্ষণ করার সময় আইডি দেওয়া হবে


0

এটি কি উপরের সমস্ত পরিস্থিতিতে কাজ করবে?

if self.pk is not None and <ModelName>.objects.filter(pk=self.pk).exists():
...

এটি একটি অতিরিক্ত ডাটাবেস হিট হতে পারে।
ডেভিড শুমান

0
> def save_model(self, request, obj, form, change):
>         if form.instance._state.adding:
>             form.instance.author = request.user
>             super().save_model(request, obj, form, change)
>         else:
>             obj.updated_by = request.user.username
> 
>             super().save_model(request, obj, form, change)

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

-3

আপনি অবজেক্টটি (ডেটা) আপডেট করছেন বা সন্নিবেশ করছেন কিনা তা জানতে self.instance.fieldnameআপনার ফর্মটি ব্যবহার করুন। আপনার ফর্মটিতে একটি পরিষ্কার ফাংশন সংজ্ঞায়িত করুন এবং বর্তমান মান এন্ট্রি আগেরটির মতো কিনা তা পরীক্ষা করুন, যদি না হয় তবে আপনি এটি আপডেট করছেন।

self.instanceএবং self.instance.fieldnameনতুন মান সঙ্গে তুলনা করুন

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