我有一个数月模型的DRF API,我需要提供一种方法来创建一个用于创建或更新对象的端点(因此,发布端点或补丁端点)。
我尝试从以下两个答案中举例:
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.
答案 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 字段来获取模型的实例,因为这些只是进行查询所必需的字段。