Как пропустить существующий экземпляр объекта при создании ресурсов в массовом Python - PullRequest
0 голосов
/ 11 января 2019

Я пытаюсь создать ресурсы навалом. Пока ресурсы созданы у меня matric_no должно быть уникальным. Если значение существующего matric_no загружено вместе с некоторыми новыми записями, я получаю ошибку целостности 500, потому что значение уже существует, и оно останавливает создание остальных значений. Как я могу просмотреть эти значения, а затем проверить, существует ли это значение, а затем пропустить, чтобы заполнить остальные? Вот мой код:

**models.py**

from django.db import models
from django.utils.encoding import python_2_unicode_compatible

@python_2_unicode_compatible
class Undergraduate(models.Model):

    id = models.AutoField(primary_key=True)
    surname = models.CharField(max_length=100)
    firstname = models.CharField(max_length=100)
    other_names = models.CharField(max_length=100, null=True, blank=True)
    card = models.CharField(max_length=100, null=True, blank=True)
    matric_no = models.CharField(max_length=20, unique=True)
    faculty = models.CharField(max_length=250)
    department_name = models.CharField(max_length=250)
    sex = models.CharField(max_length=8)
    graduation_year = models.CharField(max_length=100)
    mobile_no = models.CharField(max_length=150, null=True, blank=True)
    email_address = models.CharField(max_length=100)
    residential_address = models.TextField(null=True, blank=True)
    image = models.CharField(max_length=250, 
    default='media/undergraduate/default.png', null=True, blank=True)

    def __str__(self):
        return "Request: {}".format(self.matric_no)


***serializers.py***

from .models import Undergraduate
from .models import Undergraduate

class UndergraduateSerializer(serializers.ModelSerializer):
    class Meta:
        model = Undergraduate
        fields ='__all__'


class CreateListMixin:    
    """Allows bulk creation of a resource."""    
    def get_serializer(self, *args, **kwargs):

        if isinstance(kwargs.get('data', {}), list):
            print(list)
            kwargs['many'] = True

        return super().get_serializer(*args, **kwargs)

**api.py**

from .models import Undergraduate

from rest_framework.viewsets import ModelViewSet

from .serializers import CreateListMixin,UndergraduateSerializer


class UndergraduateViewSet(CreateListMixin, ModelViewSet):

    queryset = Undergraduate.objects.all()
    serializer_class = UndergraduateSerializer
    permission_classes = (permissions.IsAuthenticated,)

**urls.py**

from rest_framework.routers import DefaultRouter
from .api import UndergradMassViewSet 
router=DefaultRouter() 

router.register(r'ug', UndergradMassViewSet) 

Это обновленный serializer.py

class UndergraduateSerializer(serializers.ModelSerializer):

    class Meta:
        model = Undergraduate
        fields = ('id', 'surname', 'firstname', 'other_names', 'card','matric_no', 'faculty', 'department_name', 'sex', 'graduation_year', 'mobile_no', 'email_address', 'residential_address')

        def create(self, validated_data):
            created_ids = []
            for row in validated_data:
                try:
                    created = super().create(row)
                    created_ids.append(created.pk)
                except IntegrityError:
                    pass
            return Undergraduate.objects.filter(pk__in=[created_ids])

Вот так я и перенес это Seriliazers.py

class UndergraduateSerializer(serializers.ModelSerializer):
    def create(self, validated_data):
        created_ids = []
        for row in validated_data:
            try:
                created = super().create(row)
                created_ids.append(created.pk)
            except IntegrityError:
            pass
        return Undergraduate.objects.filter(pk__in=[created_ids])

class Meta:
    model = Undergraduate
    fields = ('id', 'surname', 'firstname', 'other_names', 'card','matric_no', 'faculty', 'department_name', 'sex', 'graduation_year', 'mobile_no', 'email_address', 'residential_address')
    read_only_fields = ('id',)

Когда отправленный список имеет существующее matric_no, он возвращает 500 ListSeriaizer не повторяется

1 Ответ

0 голосов
/ 11 января 2019

Вам определенно необходимо реализовать собственный метод create() в вашем сериализаторе для обработки такого случая, когда метод создания по умолчанию сериализатора ожидает один объект.

Тем не менее, здесь есть пара проектных решений, которые следует учитывать:

  1. Вы можете использовать bulk_create , но в нем есть много предостережений, перечисленных в документах, и это все равно вызовет ошибку целостности, поскольку вставки выполняются за один коммит. Единственным преимуществом здесь является скорость
  2. Вы можете зацикливаться на каждом объекте и создавать их по отдельности. Это решит проблему целостности, так как вы можете поймать исключение целостности и двигаться дальше. Здесь вы потеряете скорость в 1
  3. Вы также можете проверить наличие проблем целостности в методе validate, даже не переходя к созданию. Таким образом, вы можете немедленно вернуть клиенту ответ об ошибке с информацией о нарушающем ро. Если все в порядке, вы можете использовать 1 или 2 для создания объектов.

Лично я бы выбрал 2 (и, возможно, 3). Предполагая, что вы тоже решили это выбрать, вот как должен выглядеть метод создания вашего сериализатора:

def create(self, validated_data):
    created_ids = []
    for row in validated_data:
        try:
            created = super().create(row)
            created_ids.append(created.pk)
        except IntegrityError:
            pass
    return Undergraduate.objects.filter(pk__in=[created_ids])

Таким образом, в этом случае только созданные объекты будут возвращены в качестве ответа

...