Ich möchte einen Fehler auslösen, wenn ein Benutzer versucht, ein Objekt zu löschen, wenn einige andere Benutzer in der update_object Ansicht aktiv sind. Ich fühle, dass eine Art Mutex-ähnlicher Verriegelungsmechanismus dafür benötigt wird. Hast du irgendwelche Vorschläge?Was ist der einfachste Weg, um ein Objekt in Django zu sperren
Antwort
So, es gibt eine Handvoll Möglichkeiten zu tun, was Sie fragen. Aber eine gute Anzahl von ihnen wird nicht implementierungsunabhängig sein: Sie könnten Sperren oder Rlocks verwenden, aber sie werden wirklich nur auf Servern mit 100% Threads funktionieren und wahrscheinlich überhaupt nicht in einer Fork/Pre-Fork-Implementierung.
Das bedeutet mehr oder weniger, dass die Sperrimplementierung Ihnen überlassen wird. Zwei Ideen:
.lock
Datei auf dem Dateisystemlocked
Eigenschaft in Ihrer Modellklasse
In beiden Fällen müssen Sie manuell das Sperrobjekt auf Update eingestellt und überprüfen dagegen auf Löschen . Versuchen Sie etwas wie:
def safe_update(request,model,id):
obj = model.objects.get(id)
if obj.locked:
raise SimultaneousUpdateError #Define this somewhere
else:
obj.lock()
return update_object(request,model,id)
# In models file
class SomeModel(models.Model):
locked = models.BooleanField(default = False)
def lock(self):
self.locked = True
super(models.Model,self).save()
def save(self):
# overriding save because you want to use generic views
# probably not the best idea to rework model code to accomodate view shortcuts
# but I like to give examples.
self.locked = False
# THIS CREATES A DIFFERENT CRITICAL REGION!
super(models.Model,self).save()
Dies ist in der Tat eine plumpe Implementierung, die Sie aufräumen müssen. Sie sind vielleicht nicht mit der Tatsache vertraut, dass eine andere kritische Region erstellt wurde, aber ich sehe nicht, wie Sie viel besser machen würden, wenn Sie die Datenbank als Implementierung verwenden, ohne die Implementierung viel komplizierter zu machen. (Eine Option wäre, die Sperren zu getrennten Objekten zu machen. Dann könnten Sie sie aktualisieren, nachdem die Methode save() aufgerufen wurde. Aber ich habe keine Lust, das zu programmieren.) Wenn Sie wirklich eine dateibasierte Sperre verwenden wollen System, das würde auch das Problem lösen. Wenn Sie eine Datenbank-Treffer-Paranoid sind, könnte dies die Sache für Sie sein. Etwas wie:
class FileLock(object):
def __get__(self,obj):
return os.access(obj.__class__+"_"+obj.id+".lock",os.F_OK)
def __set__(self,obj,value):
if not isinstance(value,bool):
raise AttributeError
if value:
f = open(obj.__class__+"_"+obj.id+".lock")
f.close()
else:
os.remove(obj.__class__+"_"+obj.id+".lock")
def __delete__(self,obj):
raise AttributeError
class SomeModel(models.Model):
locked = FileLock()
def save(self):
super(models.Model,self).save()
self.locked = False
Wie auch immer, vielleicht gibt es eine Möglichkeit, diese Vorschläge nach Ihrem Geschmack zu mischen und anzupassen?
Ich würde vorschlagen, eine einfache Schreib-Lese-Sperre, wie Sie Benutzer nicht gleichzeitig Zugriff auf das Objekt (nur aus der Bearbeitung) blockieren wollen.
Eine allgemeine Vorgehensweise dabei wäre, eine Funktion zu erstellen, die die Anzahl der aktiven Leser beibehält. Wenn Sie in dieses Objekt schreiben müssen, würden Sie eine weitere Funktion erstellen, die verhindert, dass neue Leser Zugriff erhalten (denken Sie an eine Wartungsseite), und möglicherweise vorhandene Leser umleiten. Sobald keine weiteren Leser mehr vorhanden sind, können Sie den Schreibvorgang abschließen und das Objekt entsperren.
Da Ihr Bereich auf Löschvorgänge beschränkt ist, und nicht auch auf Aktualisierungen, wäre eine Option, die Idee eines "Löschens" als Aktion "Nicht veröffentlichen" zu überdenken. Nehmen Sie zum Beispiel das folgende Modell:
class MyManager(models.Manager):
def get_query_set(self):
super(MyManager, self).get_query_set().filter(published=True)
class MyModel(models.Model):
objects = MyManager()
published = models.BooleanField(default=True)
... your fields ...
def my_delete(self):
self.published = False
super(MyModel, self).save()
def save(self):
self.published = True
super(MyModel, self).save()
Auf diese Weise, wenn ein Bearbeitungs begangen wird, ist es für alle Benutzer sichtbar ... aber andere sind noch freie Elemente zu löschen. Ein Vorteil dieser Technik besteht darin, dass Sie keine zusätzliche Logik zum Sperren von Elementen und zum Anzeigen einer anderen Benutzeroberfläche für den Benutzer benötigen. Nachteile sind zusätzlicher Speicherplatz in der db-Tabelle und die seltenen Umstände, unter denen ein gelöschtes Objekt "magisch" wieder erscheint.
(Dies ist wahrscheinlich nur ein Ausgangspunkt. Wenn Sie diesen Weg nehmen, dann würden Sie wahrscheinlich eine Variante dieser Idee je nach Anwendungsfall. Tun wollen)
Ich mag die "Unpublish" Idee, aber es ist eine Arbeit statt eine Lösung. Ich werde es im Hinterkopf behalten und es versuchen, wenn ich mit etwas anderem nicht zurechtkomme. Vielen Dank! – kokeksibir
Da die Zugabe von select_for_update gibt es eine einfache Möglichkeit, eine Sperre für ein Objekt zu erhalten, sofern Ihre Datenbank dies unterstützt.Postgresql, Oracle und Mysql, zumindest, unterstützen es, nach den Django-Dokumenten.
Beispielcode:
import time
from django.contrib.auth import get_user_model
from django.db import transaction
User = get_user_model()
target_user_pk = User.objects.all()[0].pk
with transaction.atomic():
print "Acquiring lock..."
to_lock = User.objects.filter(pk=target_user_pk).select_for_update()
# Important! Queryset evaluation required to actually acquire the lock.
locked = to_lock[0]
print locked
while True:
print "sleeping {}".format(time.time())
time.sleep(5)
- 1. Was ist der einfachste Weg, um SUMPRODUCT
- 2. Was ist der einfachste Weg, um MNS-Schema zu aktualisieren?
- 3. Was ist der einfachste Weg, um mit TensorFlow zu beginnen?
- 4. Was ist der einfachste Weg, um Java-Objekte zu erhalten?
- 5. Was ist einfachste Weg, um ein Video in einem Media
- 6. Was ist der einfachste Weg in Java zu tun?
- 7. Was ist der einfachste Weg, um dieses XML-Dokument in mein Objekt zu konvertieren?
- 8. Was ist der Django-Weg, um einen Subselect zu machen?
- 9. Was ist der einfachste Weg, um ERRORLEVEL auf Null zurückzusetzen?
- 10. Was ist der einfachste Weg, ein veränderbares Scala-Objekt tief zu klonen (zu kopieren)?
- 11. Der einfachste Weg, um Zahlen zu überprüfen
- 12. Welcher ist der einfachste Weg, um ein Captcha zu einer Django-Site hinzuzufügen?
- 13. Was ist der einfachste Weg, XML in C++ zu generieren?
- 14. Was ist der einfachste Weg, um Objekt-Detektor auf C++ mit Fast/Faster-RCNN zu machen?
- 15. Was ist der einfachste Weg, um eine Verbindung zu einem .NET-Remote-Server-Objekt herzustellen
- 16. Was ist der einfachste Weg, um ein Datum in asp.net C# zu validieren?
- 17. Was ist der einfachste Weg, um einen Ordner voller PNG-Bilder in ein Videoformat zu konvertieren?
- 18. Was ist der einfachste Weg, um eine ArrayList umzukehren?
- 19. Was ist der einfachste Weg, Einstellungsdateien in Java zu machen?
- 20. Was ist der einfachste Weg, mehrere Webanfragen hintereinander zu tätigen?
- 21. Was ist der einfachste Weg, um das angegebene Objekt zu erkennen, ist der Wert oder Referenztyp in .net?
- 22. Was ist der einfachste Weg, um Liniensegmente zu zeichnen, um die Ausgabe eines Algorithmus zu visualisieren?
- 23. Was ist der einfachste Weg, um kleine Datenmengen (Objekte) in Android zu speichern?
- 24. Was ist der einfachste Weg, um über ein Array von Arrays zu iterieren?
- 25. Was ist der einfachste Weg, um ein Array von Strukturen zu erstellen?
- 26. Was ist der einfachste Weg, um ein Projekt von Pinax 0.5.1 auf 0.7beta3 zu verschieben?
- 27. Was ist der einfachste Weg, um ein Bildfeld mit dem Inhalt einer Datei zu aktualisieren
- 28. Was ist der einfachste Weg, um eine optionale C-Erweiterung für ein Python-Paket zu machen?
- 29. Der einfachste Weg, um Einheit zu lernen
- 30. Was ist der einfachste Weg, einen Webservice zu klonen?
+1 für ausführliche Beispiele und Beschreibung –
ich vorhatte, so etwas zu machen, aber auf der Suche nach einem integrierten Weg zuerst. Da es keinen Hinweis auf ein eingebautes Schloss gibt, akzeptiere ich deine Antwort. Vielen Dank! – kokeksibir