DRF,在多个字段中查找后更新或创建后请求

时间:2020-07-28 08:53:10

标签: django django-rest-framework django-views

我有一个数月模型的DRF API,我需要提供一种方法来创建一个用于创建或更新对象的端点(因此,发布端点或补丁端点)。

我尝试从以下两个答案中举例:

Multiple Lookup fields answer

overriding view's create method for update or create

第二个答案是使用视图而不是序列化器,这是我宁愿保留的行为。

到目前为止,我的代码:

class MultipleFieldLookupMixin:
    def get_object(self):
        queryset = self.get_queryset()
        queryset = self.filter_queryset(queryset)
        filter = {}
        for field in self.lookup_fields:
            if self.kwargs.get(field, None):
                filter['field'] = self.kwargs['field']
        obj = get_object_or_404(queryset, **filter)
        self.check_object_permissions(self.request, obj)
        return obj

class MonthsViewSet(ModelViewSet, MultipleFieldLookupMixin):
    authentication_classes = (TokenAuthentication,)

    def get_queryset(self):
        query_set = Month.objects.all() 
        return query_set

    serializer_class = MonthSerializer
    lookup_fields = ['month', 'year', 'farm']

    def create(self, request, *args, **kwargs):
        kwarg_field: str = self.lookup_url_kwarg or self.lookup_fields
        self.kwargs[kwarg_field] = request.data[self.lookup_fields]
        try:
            return self.update(request, *args, **kwargs)
        except Month.DoesNotExist:
            return super().create(request, *args, **kwargs)

序列化器:

class MonthSerializer(serializers.ModelSerializer):
    class Meta:
        model = Month
        fields = '__all__'

因此,现在尝试创建或更新字段会引发以下错误:

    self.kwargs[kwarg_field] = request.data[self.lookup_fields]
TypeError: unhashable type: 'list'

编辑 我已经将创建方法更改为此:

  def create(self, request, *args, **kwargs):
        request_month = request.data['month']
        year = request.data['year']
        farm = request.data['farm']
        days = request.data['days']
        month, created = Month.objects.update_or_create(month=request_month, year=year, farm_id=farm,
                                                        defaults={'month': request_month, 'year': year,
                                                                  'farm_id': farm, 'days': days})
        if not created:
            serializer = MonthSerializer(month)
            serializer.is_valid(raise_exception=True)
            return Response(serializer.data, status=HTTP_200_OK)
        elif not month:
            serializer = MonthSerializer(created)
            serializer.is_valid(raise_exception=True)
            return Response(serializer.data, status=HTTP_200_OK)

我的模型具有唯一的进一步约束:

class Month(models.Model):
    month = models.IntegerField(null=False)
    year = models.IntegerField(null=False)
    date = models.DateField(null=True, blank=True, default=None)
    days = models.DurationField(default=0, )
    farm = models.ForeignKey(to=Farm, on_delete=models.CASCADE, related_name='months')

    objects = models.Manager()

    def save(self, *args, **kwargs):
        self.date = datetime.date(self.year, self.month, 1)
        super(Month, self).save(*args, **kwargs)

    def __str__(self):
        return f'{self.month},{self.year}'

    class Meta:
        unique_together = ('farm', 'date')

但是由于某种原因,它不是在更新对象,而是试图创建它,然后引发约束冲突。 现在会引发此错误:

tegrityError at /farm_api/months/
duplicate key value violates unique constraint "farm_api_month_farm_id_date_9d276785_uniq"
DETAIL:  Key (farm_id, date)=(1, 2020-08-01) already exists.

1 个答案:

答案 0 :(得分:0)

因为 django documentation 建议您应该使用 UniqueConstraint 而不是 unique_together。所以你模型的 Meta 类应该是:

...

# creating an engine with sqlalchemy
engine = create_engine(database_url, max_overflow=0)

# Using Pandas to read the csv file
df = pd.read_csv('file.csv',sep=',')
df.columns = df.columns.str.replace(' ', '')
columns = list(df.columns)

# Connecting with the engine
with engine.connect() as conn, conn.begin():
    # getting the current column names in the mysql table and storing it as array in header_arr
    headers = list(conn.execute(f"SHOW COLUMNS from tablename"))
    header_arr = []
    for header in headers:
        header_arr.append(header[0])
    # getting the columns in the csv file
    for column in columns:
        if column not in header_arr:
             # create a new column with that 'column' name
             conn.execute(f"ALTER TABLE ExtractedData ADD {column} <type????>") <--- how to figure out which <type> i need to use here??
    df.to_sql('ExtractedData', conn, if_exists='append', index=False)   

然后你可以尝试像这样修改你的创建函数,以便处理更新或创建:

class Meta:
    constraints = [
        models.UniqueConstraint(fields=['farm', 'date'], name="farm-date")
    ]

PD我正在使用 UniqueConstraint 字段来获取模型的实例,因为这些只是进行查询所必需的字段。

相关问题