I am working in django, am planning a database for rides for users.
each Ride can have multiple Users (passengers) on it, and multiple middle-destinations in it. also, each Destination can be in multiple Rides and each User (passenger) can be on multiple Rides (overtime).
Also, for each Ride there will be only one final destination and only one driver (also a User).
This is my code:
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)
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. I want the other Users to add themselves to the ride, so when the Ride is created the User (driver) doesn't have to set the passengers.
How do I go about it? and also, any other suggestions about the models?
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.
You just need a custom Form and handle manually the driver
field. Something like this:
class DriverRideForm(forms.ModelForm):
class Meta:
model = Ride
exclude = ('driver', 'passengers', )
And then in the view
where request.user
is the driver
form = DriverRideForm(request.POST)
if form.is_valid():
ride = form.save(commit=False)
ride.driver = request.user.userprofile
ride.save()
You can but you will probably do not want to exclude the driver
from the serializer
fields. This is because usually only one serializer is used per ViewSet
so you will want to return that field to the consumer of the API.
So you have two options:
Change the driver field to read-only
and hook on 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)
Add the driver
field to the request.data
before executing .create
without changing the serializer.
#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
field?I would probably do it with a custom endpoint (with @detail_route
). Something like this:
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)
This way just POST-ing at url
like /api/rides/<id>/attach/
will add the logged in request.user
to the ride.passengers
.
any other suggestions about the models?
I think your model structure is fine. I can only think of that in the future you may need more meta data about the relations, so it may be a good moment to be prepared with some Intermediate Models
, something like:
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()