django - 多对多关系问题

时间:2015-04-30 05:52:18

标签: python django database many-to-many

我在django工作,正计划为用户提供数据库。

每个 Ride 上可以有多个用户(乘客),其中包含多个中间目的地。 此外,每个目的地可以在多个游乐设施中,每个用户(乘客)可以在多个游乐设施(加班) )。

此外,对于每个 Ride ,只有一个最终目的地,只有一个驱动程序(也是用户)。

这是我的代码:

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)

问题 - 当用户添加Ride时,我希望驱动程序,目标和mid_destinations以及其他字段由设置用户(驱动程序为用户添加Ride), 乘客字段。我希望其他用户将自己添加到骑行中,因此当创建骑行时,用户(驾驶员)不必设置乘客。

我该如何解决?还有关于模型的任何其他建议吗?

1 个答案:

答案 0 :(得分:0)

关于问题的第一部分

  

问题是 - 当用户添加骑行时,我想要驱动程序,目的地   和mid_destinations以及用户设置的其余字段   (司机是用户添加乘车),乘客除外   字段。

django.forms方式

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

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

然后在view request.user是驱动程序

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

django-rest-framework方式

您可以,但您可能不希望从driver字段中排除serializer。这是因为通常每ViewSet只使用一个序列化程序,因此您需要将该字段返回给API的使用者。

所以你有两个选择:

  • 将驱动程序字段更改为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)
    
  • 在执行driver之前将request.data字段添加到.create,而不更改序列化程序。

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

用户如何使用只读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)

这样只需在url /api/rides/<id>/attach/进行发布,就会将登录的request.user添加到ride.passengers

关于问题的第二部分

  

有关模特的其他建议吗?

我认为你的模型结构很好。我只能想到将来你可能需要更多关于这种关系的元数据,所以这可能是准备一些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()