Как обрабатывать параллельные запросы в Django Rest Framework? - PullRequest
0 голосов
/ 25 мая 2018

Я создал API в DRF , который принимает POST-запрос с некоторыми данными, но иногда я чувствую, что одни и те же запросы идут параллельно, что приводит к дублированию данных в БД.

class Feedback(models.Model):
    user = models.ForeignKey(Student)
    message = models.CharField(max_length=255)

Использование может отправить один и тот же отзыв несколько раз.Давайте подумаем, что это открытый API, так что каждый может его использовать, и в чьем-то приложении пользователь нажимает несколько раз на кнопку, и я получил несколько запросов, но данные должны быть сохранены только один раз.

Я попытался добавить BooleanFieldк Student таблице и использовал следующий код, чтобы предотвратить это.Но так как несколько запросов, поступающих параллельно, могут читать одно и то же значение True.

if student.can_submit_feedback:
   student.can_submit_feedback = False
   student.save()
else:   
   # Code for saving feedback
   student.can_submit_feedback = True
   student.save() 

Я хочу обрабатывать только один вызов API для одной и той же конечной точки и одного и того же IP-адреса одновременно.Как мне этого добиться?

Обновлено

Я исследовал и обнаружил, что мы можем добавить блокировку на таблицу или объект, но я ищу предотвращения на уровне запросов

Ответы [ 3 ]

0 голосов
/ 03 июня 2018

Параллельные запросы могут быть предотвращены с помощью регулирования в DRF.Базовая конфигурация:

REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': (
        'rest_framework.throttling.AnonRateThrottle',
        'rest_framework.throttling.UserRateThrottle'
    ),
    'DEFAULT_THROTTLE_RATES': {
        'anon': '100/day', # 100 requests per day, 
        'user': '1000/day'
    }
}

day может быть заменена на second, minute, hour или day согласно требованию.

Если выхотите настроить разные ограничения скорости для разных методов запроса, таких как GET, POST и PUT.Вы можете просто создать свой собственный газ.Вот пример газа для запроса GET.

class CustomBaseThrottle(rest_throttles.SimpleRateThrottle):
    """
    Limits the rate of API calls.

    The IP address, url and request method will be used for make unique key for anonymous user.
    The user id, url and request method will be used for make unique key for authenticated user.
    """
    scope = 'get'

    def get_cache_key(self, request, view):

        if request.method.lower() == self.scope:
            if is_authenticated(request.user):
                return "{}-{}-{}".format(request.user.id, request.path, request.method)
            return "{}-{}-{}".format(self.get_ident(request), request.path, request.method)
        return None

Для получения более подробной информации см. http://www.django -rest-framework.org / api-guide / throttling /

0 голосов
/ 15 марта 2019

Если у вас все еще есть проблемы, вы можете сделать это следующим образом:

from django.db import transaction
import datetime


@transaction.atomic
def my_view_function(student: Student):

    student = Student.objects.filter(
        id=student.id, 
        last_feedback=student.last_feedback
    ).update(
        last_feedback=datetime.datetime.now()
    )

    if student is True:
        # feedback models and rules
        pass

Затем, когда вы store это в базе данных, вы будете делать:

try:
    my_view_function(student)
except:
    print("Unable to issue the feedback as other feedback is just issued")
0 голосов
/ 25 мая 2018

Звучит так, как будто вы хотите усилить уникальность вашей модели.Вы не предоставили никакого кода, но вот модель Student, например:

class Student
    first_name = models.CharField(max_length=20)
    last_name = models.CharField(max_length=20)
    date_of_birth = models.DateField()
    admission_date = models.DateField()

    class Meta:
        unique_together = ['first_name', 'last_name', 'date_of_birth', 'admission_date']

Затем, по вашему мнению, который создает учащегося, вам придется вернуть код ошибки HTTP, еслистудент уже существует:

def create_student(request):
    new_student = Student(first_name=request.POST['first_name'],
                          last_name=request.POST['last_name'],
                          date_of_birth=request.POST['date_of_birth'],
                          admission_date=request.POST['admission_date'])
    try:
        new_student.save()
    except IntegrityError:
        response = HttpResponse("Student already created")
        response.status_code = 409    # code for conflict
        return response

    return HttpResponse("OK, new student created")

ПРИМЕЧАНИЕ. Возможно, вы захотите подумать о своем дизайне, если у вас будет несколько дублирующих учеников, создаваемых параллельно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...