Django REST 框架自定义更新方法



我的应用程序具有以下结构:

models.py

class EventHost(models.Model):
hostid = models.ForeignKey(Host, on_delete=models.PROTECT)
eventid = models.ForeignKey(Event, on_delete=models.CASCADE)
someparam = models.CharField(max_length=100, blank=True, null=True)
...
class Meta:
unique_together = ("hostid", "event")

class Host(models.Model):
hostid = models.IntegerField(primary_key=True)
hostname = models.CharField(max_length=100)
...

class Event(models.Model):
eventid = models.AutoField(primary_key=True)
eventname = models.CharField(max_length=100)
...
hosts = models.ManyToManyField(Host, through='EventHost')

views.py

class EventViewSet(viewsets.ModelViewSet):
queryset = Event.objects.order_by('-date')
serializer_class = EventSerializer
class HostViewSet(viewsets.ModelViewSet):
queryset = Host.objects.order_by('-hostid')
serializer_class = HostSerializer
class EventHostViewSet(viewsets.ModelViewSet):
queryset = EventHost.objects.all()
serializer_class = EventHostSerializer

目前要更新事件主机表,我正在执行 http 放置在我的 url 中提供 id(这是主键(。

我希望能够更新提供主机名和事件名称(将在 url 中传递(而不是 id 的事件主机。

使用 SQL,它看起来像这样:

update eventhost set someparam='somevalue' from eventhost as a, event as b, host as c where b.id = a.eventid and c.hostid = a.hostid and b.eventname='myevent' and c.hostname='myhost';

从文档中,我了解到我需要修改视图集的默认更新方法或/和修改查询集。任何想法应该如何实现?

您可以覆盖get_object方法并使用从 url 提供的参数,如下所示:

class EventHostViewSet(viewsets.ModelViewSet):
queryset = EventHost.objects.all()
serializer_class = EventHostSerializer
def get_object(self):
return EventHost.objects.get(hostid=self.kwargs['hostid'],eventid=self.kwargs['eventid'])

这样,您必须管理此查询方案是否没有记录,作为自定义

假设您已经正确构造了URL。

编辑EventHostViewSet.get_object方法:

class EventHostViewSet(viewsets.ModelViewSet):
...
lookup_field = 'eventname'
def get_object(self):
queryset = self.filter_queryset(self.get_queryset())
filter_kwargs = {'hostid__hostname': self.kwargs.get('hostname'),
'eventid__eventname': self.kwargs.get('eventname')}
obj = get_object_or_404(queryset, **filter_kwargs)
self.check_object_permissions(self.request, obj)
return obj

事件主机视图集注册:

router.register(rf'event-hosts/(?P<hostname>[.]+)', EventViewSet)

关于您的问题的一些评论:

  • 当系统中存在两个具有相同hostid__hostname和eventid__event的事件主机时,您将遇到问题,因为查询集获取方法应仅返回一条记录
  • 在DRF PUT方法中需要在请求数据中提供所有字段,如果要更新所选字段,则应使用PATCH方法或覆盖更新视图集方法(将部分设置为True(

再次编辑

这真的很糟糕的设计,你不应该那样做(不知何故你应该使用 id/也许@action装饰器来构建特定的 url 来像那样更新(。

最新更新