django - 多对多关系问题

django - Many To Many relationship issue

我在 django 工作,正在为用户规划一个游乐设施数据库。

每个行程可以有多个用户(乘客),以及多个中间目的地 在里面。 此外,每个 Destination 可以在多个 Rides 中,每个 User (乘客)可以在多个 乘车(加班)。

此外,对于每个 行程,只有一个 最终目的地,并且只有一个 driver(也是 用户).

这是我的代码:

def get_image_path(models.Model):
    return os.path.join('photos',str(instance.id),filename)


class UserProfile(models.Model):
    user=models.OneToOneField(User)
    phone_number=models.CharField(max_length=12)
    profile_picture=models.ImageField(upload_to=get_image_path, black=True, null=True)

class Ride(models.Model):
    driver=models.ForeignKey(UserProfile, related_name="r_driver")
    destination=models.ForeignKey(Destination, related_name="r_final_destination")
    leaving_time=models.DateTimeField()
    num_of_spots=models.IntergerField()
    passengers=models.ManyToMany(UserProfile, related_name="r_passengers")
    mid_destinations=models.ManyToMany(Destination, related_name="r_mid_destinations")

class Destination(models.Model):
    name=models.CharField(max_length=30)

问题是 - 当用户添加行程时,我想要driver、目的地和mid_destinations 和由 User 设置的其余字段(driver 是 User 添加行程),Except passengers 字段。我希望其他 Users 将自己添加到行程中,因此在创建行程时,用户 (driver) 不必设置乘客。

我该怎么做?还有关于模型的其他建议?

关于问题的第一部分

The Issue is - when a User adds a Ride, I want the driver, destination and mid_destinations and the rest of the fields to be set by the User (the driver is the User adding the Ride), Except for the passengers field.

django.forms方式

您只需要一个自定义表单并手动处理 driver 字段。像这样:

class DriverRideForm(forms.ModelForm):
    class Meta:
        model = Ride
        exclude = ('driver', 'passengers', )

然后在 viewrequest.user 是 driver

form = DriverRideForm(request.POST)
if form.is_valid():
    ride = form.save(commit=False)
    ride.driver = request.user.userprofile
    ride.save()

django-rest-framework 方式

可以,但您可能不想从 serializer 字段中排除 driver。这是因为通常每个 ViewSet 只使用一个序列化程序,因此您需要 return 那个字段给 API 的消费者。

所以你有两个选择:

  • 将 driver 字段更改为 read-only 并勾选 perform_create:

    class RideSerializer(serializers.ModelSerializer):
        class Meta:
            model = Ride
            read_only_fields = ('driver', 'passengers')
    
    
    #inside your RideViewSet
    def perform_create(self, serializer): 
         serializer.save(driver=self.request.user.userprofile)
    
  • 在不更改序列化器的情况下执行.create之前将driver字段添加到request.data

    #inside your RideViewSet
    def create(self, request, *args, **kwargs):
        request.data['driver'] = self.request.user.userprofile
        return super(RideViewSet, self).create(request, *args, **kwargs)
    

用户如何使用 read-only passengers 字段添加自己?

我可能会使用自定义端点(@detail_route)。像这样:

class RideViewSet(...):

    #...

    @detail_route(methods=['post'])
    def attach(self, request, pk=None):
        ride = self.get_object()
        ride.passengers.add(request.user.userprofile)
        return Response(self.get_serializer(ride).data)

这样 POST-ing 在 url 就像 /api/rides/<id>/attach/ 将把登录的 request.user 添加到 ride.passengers.

关于问题的第二部分

any other suggestions about the models?

我觉得你的模型结构很好。我只能想到,将来你可能需要更多关于关系的元数据,所以现在可能是准备一些 Intermediate Models 的好时机,比如:

class Ride(models.Model):
    # ...
    passengers=models.ManyToMany(UserProfile, through='RideSeat', related_name="r_passengers")
    mid_destinations=models.ManyToMany(Destination, through='RideMidDestination', related_name="r_mid_destinations")


class RideSeat(models.Model):
    ride = models.ForeignKey(Ride)
    passenger = models.ForeignKey(UserProfile)
    seat_number = models.IntegerField()


class RideMidDestination(models.Model):
    ride = models.ForeignKey(Ride)
    destination = models.ForeignKey(Destination)
    arrival_time = models.DateTimeField()