I'll start by explaining the current scenario of my problem.
Models
There are 5 models for example: Community, User, Membership, Reservation, Item
class User(Model):
name = CharField(max_length=50)
communities = ManyToManyField('Community', through='Membership')
class Community(Model):
name = CharField(max_length=50)
class Membership(Model):
user = ForeignKey('User')
community = ForeignKey('Community')
class Item(Model):
name = CharField(max_length=50)
class Reservation(Model):
item = ForeignKey('Item')
membership = ForeignKey('Membership')
Community is m:m User through Membership.
Reservation is 1:m Membership
Item is 1:m Reservation
ModelSerializer
class ReservationSerializer(ModelSerializer):
class Meta:
model = Reservation
fields = ('membership', 'item')
Problem
What's the best approach to automatically set the User value from request.user, hence the attribute that is required for this ReservationSerializer is just the community and item instead of membership and item?
References
How to create a django User using DRF's ModelSerializer
Return the current user with Django Rest Framework
http://www.django-rest-framework.org/tutorial/4-authentication-and-permissions#associating-snippets-with-users
Django Rest Framework ModelSerializer Set attribute on create
Dynamically limiting queryset of related field
djangorestframework: Filtering in a related field
The role of the serializer is to represent the information in a legible way, not to manipulate such data. You may want to do that on a view: Using the generic ListCreateAPIView available on DRF, you could use the pre_save signal to store that information:
from rest_framework.generics import ListCreateAPIView
class ReservationView(ListCreateAPIView):
def pre_save(self, obj):
obj.membership.user = self.request.user
Related
New to Django and relational DBs. I'm building the classic Doctor appointment booking app and have come to a point where I don't know what to do. I've created the Doctor model pointing to a Clinic, but in my API the Clinic model won't show a list of all Doctors. How could I achieve this?
class Clinic(models.Model):
name = models.CharField(max_length=200)
class Doctor(models.Model):
clinic = models.ManyToManyField(Clinic, related_name="doctors")
class ClinicSerializer(serializers.ModelSerializer):
class Meta:
model = Clinic
fields = '__all__'
class DoctorSerializer(serializers.ModelSerializer):
class Meta:
model = Doctor
fields = '__all__'
class ClinicViewset(viewsets.ModelViewSet):
queryset = Clinic.objects.all()
serializer_class = ClinicSerializer
class DoctorViewset(viewsets.ModelViewSet):
queryset = Doctor.objects.all()
serializer_class = DoctorSerializer
Django will automatically create the link from Clinic to Doctor. You don't need to (shouldn't) define it. From the docs:
Django also creates API accessors for the “other” side of the relationship – the link from the related model to the model that defines the relationship. For example, a Blog object b has access to a list of all related Entry objects via the entry_set attribute: b.entry_set.all().
The related_name argument that you passed to ManyToManyField when you created the clinic field is the name of the relation from Clinic to Doctor. It is optional and if you didn't pass it, it would be the lower-cased named of the model + _set - doctor_set in your case.
Usually you would set it to a plural in the case of ManyToManyField. In your case: doctors.
Because you have related_name="doctor" currently, you can retrieve a clinic's doctors with: clinic.doctor.all().
I wanna change all fields of a json object except 'pk' in DRF. I just need to keep one json data. When adding a new data ,this one should override existing data. Is there a way to do it with django ?
my models.py
class ClientUser2(models.Model):
phone_number = models.CharField(max_length=20,unique=True)
name = models.CharField(max_length=100,blank=True)
status = models.IntegerField(default=1)
class ClientNameSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = ClientUser2
fields = ('url','phone_number','name','status','pk')
my views.py
class ClientViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows messages to be viewed or edited.
"""
queryset = ClientUser2.objects.all()
serializer_class = ClientNameSerializer
and it's my api root
api_root
If you want to be able to only retrieve and update models you can use RetrieveUpdateApiView
Reference : https://www.django-rest-framework.org/api-guide/generic-views/#retrieveupdateapiview
I need to be able to do a post on an api endpoint to save an adgroup model.The model has a many to many field. I know I need to overwrite the create() method.But How is where I am stuck at . The incoming request data will have the id for the other model (creative). This id will already be present in the creative table.
Django creates another table called adgroup_creative to hold this M2M relationship.I need to populate that table when saving this adgroup object.
class AdGroup(models.Model):
adgroup_name = models.CharField(max_length=200, verbose_name="Name")
creative = models.ManyToManyField(Creative, verbose_name="Creative")
class Creative(models.Model):
creative_name= models.CharField(max_length=200, verbose_name="Name", default=0)
ad_type= models.PositiveIntegerField(max_length=1,verbose_name="Ad Type")
class AdGroupSerializer(serializers.ModelSerializer):
class Meta:
model = AdGroup
fields = ('id','adgroup_name','creative')
class CreativeSerializer(serializers.ModelSerializer):
class Meta:
model = Creative
fields = ('id','creative_name')
class AdGroupViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.ListModelMixin, viewsets.GenericViewSet):
queryset = AdGroup.objects.all().order_by('-id')
serializer_class = AdGroupSerializer
https://codereview.stackexchange.com/questions/46160/django-rest-framework-add-remove-to-a-list
Save a many-to-many model in Django/REST?
You should have a look at the serializer relation documentation.
You don't need anything special if you simply use ID to represent a M2M relation with DRF. You'll need to override the create/update methods only if you intend to provide non existing related objects or use nested serializers.
In the current case, you don't need nested serializers because you want to provide related instances' IDs.
How to create a duplicate of the existing User model which display objects only if a condition is satisfied?
Here in this pic, pending users should show all the users with is_active = True:
In the documentation, there was a similar statement:
pendinguser = models.ForeignKey(User, limit_choices_to={'is_staff': True})
How and where to add this to make this work?
See this example:
you have your user model 'User'
Now create a new model and inherit User model like this
class ProxyUser(User):
objects = ProxyUserManagaer()
class Meta:
proxy = True
Now create you custom definition of this Proxy model in manager function:
class ProxyUserManager(models.Manager):
def get_queryset(self):
return super(FeatureManager, self).get_queryset().filter(<add your custom definiton her>)
views.py
I'm creating a queryset that I want to serialize and return as JSON. The queryset looks like this:
all_objects = Program.objects.all()
test_data = serializers.serialize("json", all_objects, use_natural_keys=True)
This pulls back everything except for the 'User' model (which is linked across two models).
models.py
from django.db import models
from django.contrib.auth.models import User
class Time(models.Model):
user = models.ForeignKey(User)
...
class CostCode(models.Model):
program_name = models.TextField()
...
class Program(models.Model):
time = models.ForeignKey(Time)
program_select = models.ForeignKey(CostCode)
...
Question
My returned data has Time, Program, and CostCode information, but I'm unable to query back the 'User' table. How can I get back say the 'username' (from User Table) in the same queryset?
Note: I've changed my queryset to all_objects = Time.objects.all() and this gets User info, but then it doesn't pull in 'CostCode'. My models also have ModelManagers that return the get_by_natural_key so the relevant fields appear in my JSON.
Ultimately, I want data from all four models to appear in my serialized JSON fields, I'm just missing 'username'.
Here's a picture of how the JSON object currently appears in Firebug:
Thanks for any help!
It seems a bit heavyweight at first glance but you could look at using Django REST Framework:
http://www.django-rest-framework.org/api-guide/serializers#modelserializer
You can define and use the serializer classes without having to do anything else with the framework. The serializer returns a python dict which can then be easily dumped to JSON.
To get all fields from each related model as nested dicts you could do:
class ProgramSerializer(serializers.ModelSerializer):
class Meta:
model = Program
depth = 2
all_objects = Program.objects.all()
serializer = ProgramSerializer(all_objects, many=True)
json_str = json.dumps(serializer.data)
To customise which fields are included for each model you will need to define a ModelSerializer class for each of your models, for example to output only the username for the time.user:
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('username', )
class TimeSerializer(serializers.ModelSerializer):
"""
specifying the field here rather than relying on `depth` to automatically
render nested relations allows us to specify a custom serializer class
"""
user = UserSerializer()
class Meta:
model = Time
class ProgramSerializer(serializers.ModelSerializer):
time = TimeSerializer()
class Meta:
model = Program
depth = 1 # render nested CostCode with default output
all_objects = Program.objects.all()
serializer = ProgramSerializer(all_objects, many=True)
json_str = json.dumps(serializer.data)
What you really want is a "deep" serialization of objects which Django does not natively support. This is a common problem, and it is discussed in detail here: Serializing Foreign Key objects in Django. See that question for some alternatives.
Normally Django expects you to serialize the Time, CostCode, Program, and User objects separately (i.e. a separate JSON array for each) and to refer to them by IDs. The IDs can either be the numeric primary keys (PKs) or a "natural" key defined with natural_key.
You could use natural_key to return any fields you want, including user.username. Alternatively, you could define a custom serializer output whatever you want there. Either of these approaches will probably make it impossible to load the data back into a Django database, which may not be a problem for you.