Django 管理中是否发生竞争条件(丢失更新或写入倾斜)?

2024-01-01

In Django 视图, 我们可以用select_for_update() https://docs.djangoproject.com/en/4.1/ref/models/querysets/#select-for-update阻止竞争条件(丢失更新或写入偏差) so 竞争条件不会发生在Django 视图 with select_for_update() https://docs.djangoproject.com/en/4.1/ref/models/querysets/#select-for-update。 *我用了姜戈 3.2.16.

但是,即使我用谷歌搜索,我也找不到任何信息说"in Django 管理员,竞争条件不会发生或者select_for_update() https://docs.djangoproject.com/en/4.1/ref/models/querysets/#select-for-update用于防止竞争条件".

So, in Django 管理员,竞争条件会发生吗?

  • 如果有的话有什么方法可以预防竞争条件 in Django 管理员?

  • 如果不是,则为select_for_update() https://docs.djangoproject.com/en/4.1/ref/models/querysets/#select-for-update或用于防止的其他方式竞争条件 in Django 管理员?我可以查看我的代码吗?


默认情况下Django 管理员, 丢失更新 or 写倾斜引起的竞争条件可能会发生,因为select_for_update()未使用。 *我的答案 https://stackoverflow.com/questions/27826714/lost-update-vs-write-skew/73847878#73847878解释丢失更新 and 写倾斜.

所以,我用以下代码编写了示例代码select_for_update()阻止丢失更新 or 写倾斜 in Django 管理员如下所示。 *我用了姜戈 3.2.16 and PostgreSQL:

<丢失更新>

例如,您创建store_product table with id, name and stock with models.py如下所示:

store_product table:

id name stock
1 Apple 10
2 Orange 20
# "store/models.py"

from django.db import models

class Product(models.Model):
    name = models.CharField(max_length=30)
    stock = models.IntegerField()

然后,您需要覆盖获取查询集() https://github.com/django/django/blob/main/django/contrib/admin/options.py#L412 with select_for_update() in ProductAdmin():如下所示:

# "store/admin.py"

from django.contrib import admin
from .models import Product

@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):

    def get_queryset(self, request):
        qs = super().get_queryset(request)
        
        last_part_of_referer = request.META.get('HTTP_REFERER').split('/')[-2]
        last_part_of_uri = request.build_absolute_uri().split('/')[-2]

        if (last_part_of_referer == "change" and last_part_of_uri == "change"):
            qs = qs.select_for_update()
        
        return qs

然后,如果你改变(更新)product如下所示:

SELECT FOR UPDATE and UPDATE queries正在运行交易根据PostgreSQL 查询日志如下所示。 *您可以检查如何记录 PostgreSQL 查询 https://stackoverflow.com/questions/54780698/postgresql-database-log-transaction/73432601#73432601:

而且,如果你不重写get_queryset() in ProductAdmin():如下所示:

# "store/admin.py"

from django.contrib import admin
from .models import Product

@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
    pass

SELECT and UPDATE queries运行如下图所示:

<写入倾斜>

例如,您创建store_doctor table with id, name and on_call with models.py如下所示:

store_doctor table:

id name on_call
1 John True
2 Lisa True
# "store/models.py"

from django.db import models

class Doctor(models.Model):
    name = models.CharField(max_length=30)
    on_call = models.BooleanField()

然后,您需要覆盖响应_更改() https://docs.djangoproject.com/en/4.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.response_change with select_for_update() and 保存模型() https://docs.djangoproject.com/en/4.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.save_model in DoctorAdmin():如下所示。 *至少一名医生必须待命:

# "store/admin.py"

from django.contrib import admin
from .models import Doctor
from django.db import connection

@admin.register(Doctor)
class DoctorAdmin(admin.ModelAdmin):

    def response_change(self, request, obj):
        qs = super().get_queryset(request).select_for_update().filter(on_call=True)
        obj_length = len(qs)

        if obj_length == 0:
            obj.on_call = True
        obj.save()

        return super().response_change(request, obj)

    def save_model(self, request, obj, form, change):
        last_part_of_path = request.path.split('/')[-2]

        if last_part_of_path == "add":
            obj.save()

然后,如果你改变(更新)doctor如下所示:

SELECT FOR UPDATE and UPDATE queries正在运行交易但我不知道如何删除the 1st SELECT query浅蓝色如下图:

而且,如果你不重写response_change() and save_model() in DoctorAdmin():如下所示:

# "store/admin.py"

from django.contrib import admin
from .models import Doctor

@admin.register(Doctor)
class DoctorAdmin(admin.ModelAdmin):
    pass

SELECT and UPDATE queries运行如下图所示:

例如对于write skew再次,你创造了store_event table with id, name and user with models.py如下所示:

store_event table:

id name user
1 Make Sushi John
2 Make Sushi Tom
# "store/models.py"

from django.db import models

class Event(models.Model):
    name = models.CharField(max_length=30)
    user = models.CharField(max_length=30)

然后,您需要覆盖response_add() with select_for_update() and save_model() in EventAdmin():如下所示。 *只有3位用户可以加入“制作寿司”活动:

# "store/admin.py"

from django.contrib import admin
from .models import Event
from django.db import connection

@admin.register(Event)
class EventAdmin(admin.ModelAdmin):

    def response_add(self, request, obj, post_url_continue=None):
        qs = super().get_queryset(request).select_for_update() \
                                          .filter(name="Make Sushi")
        obj_length = len(qs)

        if obj_length < 3:
            obj.save()

        return super().response_add(request, obj, post_url_continue)

    def save_model(self, request, obj, form, change):
        last_part_of_path = request.path.split('/')[-2]

        if last_part_of_path == "change":
            obj.save()

然后,如果你添加event如下所示:

SELECT FOR UPDATE and INSERT queries正在运行交易如下所示:

而且,如果你不重写响应_添加() https://docs.djangoproject.com/en/4.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.response_add and save_model() in EventAdmin():如下所示:

# "store/admin.py"

from django.contrib import admin
from .models import Event

@admin.register(Event)
class EventAdmin(admin.ModelAdmin):
    pass

Only INSERT query运行如下图所示:

您还可以查看我下面的帖子选择更新在姜戈中:

  • 在 Django Admin 中添加数据时如何运行“SELECT FOR UPDATE”而不是“SELECT”? https://stackoverflow.com/questions/74831244/how-to-run-select-for-update-instead-of-select-when-adding-data-in-django-ad

  • 在 Django Admin 中更改和删除数据时,如何运行“SELECT FOR UPDATE”而不是“SELECT”? https://stackoverflow.com/questions/74807372/how-to-run-select-for-update-instead-of-select-when-changing-and-deleting-da

  • 如何在 Django 管理操作中为默认“删除所选”运行“SELECT FOR UPDATE”? https://stackoverflow.com/questions/74857394/how-to-run-select-for-update-for-the-default-delete-selected-in-django-admin

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Django 管理中是否发生竞争条件(丢失更新或写入倾斜)? 的相关文章

随机推荐