0

こんにちは、私はハードウェア インベントリ アプリケーションを作成しています。新しい部品が入力されるたびに、将来のステータスの変更や更新とともにログを記録したいと考えています。

モデル

class Part(models.Model):
    type = models.ForeignKey(PartType, blank=False)
    bar_code = models.CharField(max_length=50, blank=False, unique=True)
    serial_number = models.CharField(max_length=50, blank=False)
    status = models.ForeignKey(Status, blank=False)

class PartLog(models.Model):
    part = models.ForeignKey(Part, blank=False)
    time_stamp = models.DateTimeField(blank=False, auto_now_add=True)
    old_status = models.ForeignKey(Status, related_name='old_status_related', blank=False)
    new_status = models.ForeignKey(Status, related_name='new_status_related', blank=False)

class Status(models.Model):
    current_status = (
     ("EN", "Entered Database"),
     ("CO", "Checked out"),
     ("CI", "Checked in"),
     ("RM", "Returned for RMA"),
     ("IU", "Currently in use"),     
                    )
    status = models.CharField(max_length=2, choices=current_status)

    def __unicode__(self):
        return unicode(self.status)

信号

@receiver(post_save, sender=Part)
def add_to_partLog(sender, instance, signal, created, *args, **kwargs):

    if created:
        print "Since a new entry has been created, setting old and new status for partlog entry!"
        # Automatically changing status from Entered state to Checked In state
        # Part Table
        instance.status=Status(3)
        instance.save()

        # Setting Old and New status for the first (new) partLog entry for the new added part
        # Part Log table
        oldStatus = Status(1)
        newStatus = Status(3)
        partobj = Part.objects.get(id=instance.pk)
        PartLog.objects.create(part=partobj,old_status=oldStatus, new_status=newStatus)
    else:
        print "Entry already exists!"
        # Retreiving the old status of the Part() record

        oldStatus = ???
        newStatus = instance.status
        partobj = Part.objects.get(id=instance.pk)
        PartLog.objects.create(part=partobj,old_status=oldStatus,new_status=newStatus)

ビュー

def check_in_part(request):
    err_list=[]
    c = {}
    c.update(csrf(request))

    if request.method == 'POST':
        form = PartForm(request.POST)
        print "form object is created."
        if form.is_valid():  
            form.save()  
            return http.HttpResponseRedirect('/current_count/')    
    else:        
        form = PartForm(initial={'status':1L})
    return render(request,'add_part.html',{
                                           'title':'Add Item',
                                           'form':form
                                           })


# Checking out a part    
def check_out_part(request):
   errlst = []
   c = {}
   c.update(csrf(request))
   # ADD check against DB with the appropriate status "CO" or 3
   if request.method == 'POST':
       form = ModifyPartForm(request.POST)
       if form.is_valid():
           bar_code_form = form.cleaned_data['bar_code']
           try:
               bar_code_model= Part.objects.get(bar_code=bar_code_form)
           except Part.DoesNotExist:
               #FIXME: need to get errlst to user
               errlst.append("Part with bar_code %s does not exist." % bar_code_form)
           else:
                #bar_code_model.check_out()
               bar_code_model.status_id=2L
               bar_code_model.save()
               return http.HttpResponseRedirect('/current_count/')
   else:
       form = ModifyPartForm()
       # Adding default status to Check Out or "CO"
   return render(request, 'remove_part.html',{
                                           'title':'Remove Item',
                                           'form': form,
                                           'errors': errlst,
                                           })

問題は、シグナルの else 節にあります。if の最初の部分は問題なく動作します。※保存前の「ステータス」へのアクセス方法と、保存後の利用方法がわかりません。*現在、1 つのビューで、新しいパーツをチェックインすると、初期状態が "EN" になり、自動的に "CI" に変更されます。現在、check_out ビューでは、バーコードで Part() を検索し、両方のテーブルを適切に更新してログに記録したいと思います。最終的には、ドロップダウンにリストされている他のステータスから選択できるようにしたいと考えています。メニュー、しかしそれは後で=)

4

2 に答える 2

2

ここにステータスオブジェクトをキャッシュすることになったのが私の答えです。

#Signals.py
@receiver(post_save, sender=Part)
def log_entry(sender, instance, created, raw, *args, **kwargs):
    # Using the statuses from the above method to create a PartLog entry. 
    newStatus = instance.status

    if not created:
        # Get old status from current state
        oldStatus = instance._state.old_status
        PartLog.objects.create(part=instance,
                               old_status=oldStatus,
                               new_status=instance.status)
        instance._state.old_status = newStatus
    else:
        PartLog.objects.create(part=instance, old_status=Status(1), new_status=Status(3))

#Models.py

class Part(models.Model):
    type = models.ForeignKey(PartType, blank=False)
    bar_code = models.CharField(max_length=50, blank=False, unique=True)
    serial_number = models.CharField(max_length=50, blank=False)
    status = models.ForeignKey(Status, blank=False)

    def __init__(self, *args, **kwargs):
        super(Part, self).__init__(*args, **kwargs)
        # Caching the existing Part object's status
        if self.pk:
            self._state.old_status = self.status

    def __unicode__(self):
        return unicode(self.bar_code)
于 2012-08-06T17:50:36.910 に答える
0

post_saveモデルはフィールドの前後の値を追跡しないため、信号段階でフィールドの前の値を知る方法はありません。次の 2 つのオプションがあります。

  1. __init__()モデルのステータスフィールドと、場合によっては新しい値をキャッシュし、save()それらをチェックしますpost_save
  2. シグナルの現在の値のデータベース ルックアップを実行し、pre_saveそれをオブジェクトにキャッシュして、保存の完了後に参照できるようにします。

私は最初のアプローチを使用し、データベース クエリを避ける傾向があります。事前にフィールドをキャッシュすると、クエリでそのフィールドに明示的にアクセスしているため、クエリでそのフィールドを延期できなくなることに注意する必要があります。__init__

次のようになります。

class Part(models.Model):
    ...
    def __init__(self, *args, **kwargs):
        super(Part, self).__init__(*args, **kwargs)
        self._status_old_cached = self.status 


@receiver(post_save, sender=Part)
def add_to_partLog(sender, instance, created, *args, **kwargs):
    ...
    else:
        oldStatus = instance._status_old_cached

これにより、フィールドの検索がすぐに強制されるため、select_related事前にクエリでこのフィールドを確認してください。

Part.objects.select_related('status').all()

ステータス オブジェクトが実際には必要なく、 だけが必要な場合はid、モデルが実際に id を保存するため、おそらくルックアップを節約できます。

self._status_id_old_cached = self.status_id
于 2012-07-31T22:02:29.370 に答える