How do I set the lookup_field with a key in JSONField model?
The model:
exchange = models.ForeignKey(StockExchange, on_delete=models.CASCADE, related_name='tickers')
fundamentals = models.JSONField(null=True, blank=True)
The viewset:
class StockCardsV2ViewSet(BaseGetViewSet):
search_fields = ('^fundamentals__General__Name', '^fundamentals__General__Code')
filter_backends = (filters.SearchFilter,)
queryset = Ticker.objects.all()
serializer_class = StockCardsV2Serializer
lookup_value_regex = '[0-9a-zA-Z_.]+'
lookup_field = 'fundamentals__General__Code'
The Serializer:
class Meta:
model = Ticker
fields = ('id', 'url', 'name', 'ticker', 'logo_url', 'currency_symbol', 'sector', 'industry', 'esg_rating',
'weekly_prices', 'monthly_prices', 'yearly_prices', 'two_yearly_prices', 'ad', 'in_watchlist')
lookup_field = 'fundamentals__General__Code'
extra_kwargs = {
'url': {'lookup_field': 'fundamentals__General__Code'},
}
There are no problems with search_fields but I get this error for the lookup_field.
'Ticker' object has no attribute 'fundamentals__General__Code'
Example fundamentals:
"fundamentals": {
"General": {
"CIK": null,
"LEI": null,
"Code": "SATX-WTA",
"ISIN": null,
"Name": "Satixfy Communications Ltd.",
}
},
Related
I've a model:
class ListingPrice(Timestamps):
price = models.ForeignKey("Price", on_delete=models.CASCADE)
location = models.ForeignKey("location", on_delete=models.CASCADE)
class Meta:
unique_together = ["price", "location"]
class Price(Timestamps):
package = models.ForeignKey("products.Package", on_delete=models.CASCADE)
locations = models.ManyToManyField("location", through="ListingPrice")
price = models.DecimalField(max_digits=11, decimal_places=3)
with a serializer:
class LocationSerializer(serializers.ModelSerializer):
name = LocalizedField()
class Meta:
model = location
fields = ['id', 'name']
class PriceSerializer(serializers.ModelSerializer):
locations = LocationSerializer(many=True, read_only=True)
class Meta:
model = Price
fields = ['package', 'locations', 'price']
def create(self, validated_data):
print("validated_data, validated_data)
and viewset:
class PriceViewSet(ModelViewSet):
queryset = Price.objects.all()
serializer_class = PriceSerializer
ordering = ['id']
permissions = {
"GET": ["view_minimum_listing_price", ],
"POST": ["add_minimum_listing_price", ],
'PUT': ['update_minimum_listing_price', ],
'DELETE': ['delete_minimum_listing_price', ],
}
In testing I'mm using the following:
data = {
"price": 15,
}
response = self.client.put(path=self.url, data=data, format='json', args=[1])
I'm trying to update the price in the instance with id 1, but neither put or update is not allowed? How to overcome this and update it?
edit: urls.py
router = SimpleRouter()
router.register('listing_price', PriceViewSet, basename='listing_price')
I want to show only two properties of the model in the list of items, but then in a specific item show all the properties
/api/character <-- show a list with name and id properties
/api/character/30 <-- show all properties of the item with id 30
Code i have in serializer.py:
class CharacterSerializer(serializers.ModelSerializer):
language = LanguageSerializer(read_only=True)
region = RegionSerializer(read_only=True)
realm = RealmSerializer(read_only=True)
faction = FactionSerializer(read_only=True)
race = RaceSerializer(read_only=True)
wow_class = ClassSerializer(read_only=True)
spec = SpecSerializer(read_only=True)
talents = TalentSerializer(many=True, read_only=True)
pvp_talents = PvpTalentSerializer(many=True, read_only=True)
covenant = CovenantSerializer(read_only=True)
soulbind = SoulbindSerializer(read_only=True)
conduits = ConduitSerializer(many=True, read_only=True)
class Meta:
model = Character
fields = ['id', 'name', 'language', 'region', 'realm', 'faction', 'race', 'wow_class', 'spec', 'talents', 'pvp_talents',
'covenant', 'covenant_rank', 'soulbind', 'soulbind_abilities', 'conduits', 'item_level', 'media', 'avatar', 'rating_2v2',
'rating_3v3', 'rating_rbg', 'max_2v2', 'max_3v3', 'max_rbg', 'achievement_points', 'account_achievements', 'seasons',
'alters', 'date_added', 'last_search', 'checked']
code in views.py
class CharacterViewSet(viewsets.ReadOnlyModelViewSet):
serializer_class = CharacterSerializer
permission_classes = []
queryset = Character.objects.all()
filter_backends = [filters.SearchFilter, DjangoFilterBackend]
search_fields = ['name']
filterset_fields = ['language', 'region', 'realm', 'faction', 'race', 'wow_class', 'spec', 'covenant', 'soulbind']
Thx a lot!
Solved.
I have created two serializer for the model one for list and another for detail
class TalentSerializer(serializers.ModelSerializer):
class Meta:
model = Talent
fields = ['id', 'name']
class TalentDetailSerializer(serializers.ModelSerializer):
language = LanguageSerializer(read_only=True)
wow_class = ClassSerializer(read_only=True)
spec = SpecSerializer(many=True, read_only=True)
class Meta:
model = Talent
fields = ['id', 'name', 'language', 'description', 'spell_id', 'talent_id', 'wow_class', 'spec', 'tier_index', 'column_index', 'level', 'icon']
in the viewset I have redefined the get of the class:
class TalentViewSet(viewsets.ReadOnlyModelViewSet):
serializer_class = TalentSerializer
permission_classes = []
queryset = Talent.objects.all()
filter_backends = [filters.SearchFilter, DjangoFilterBackend]
search_fields = ['name']
filterset_fields = ['language', 'spell_id', 'talent_id', 'wow_class', 'spec', 'tier_index', 'column_index', 'level']
def get_serializer_class(self):
if self.action == 'retrieve':
return TalentDetailSerializer
return TalentSerializer
Now works well /api/talent return a list with id and name of items and /api/talent/id return the item with all props of model :)
I am building an api for CRUD operations on a user table which has association with country and state tables as given model definitions:
class Country(models.Model):
""" Model for Country"""
country_abbreviation = models.CharField(max_length=80)
country_name = models.CharField(max_length=80)
is_active = models.SmallIntegerField()
def __str__(self):
return self.country_name
class State(models.Model):
""" model for saving state"""
state_name = models.CharField(max_length=32)
state_abbreviation = models.CharField(max_length=8)
country = models.ForeignKey(Country, related_name='states', on_delete=models.CASCADE)
is_active = models.SmallIntegerField(default=1, blank=True)
def __str__(self):
return self.state_name
class Meta:
""" meta class"""
ordering = ('state_name', )
class User(models.Model):
""" model for saving user information """
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=20)
country = models.ForeignKey(Country, related_name='user_country', on_delete=models.CASCADE)
state = models.ForeignKey(State, related_name='user_state', on_delete=models.CASCADE)
address = models.CharField(max_length=150)
def __str__(self):
return '%d: %s %s' % (self.id, self.first_name, self.last_name)
class Meta:
""" meta class """
ordering = ('first_name', )
I am writing serializers in a way that while I am getting records from user table, for every row in the table there must be available all the country and state info associated with that particular row instead of just their ids respectively:
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'first_name', 'last_name', 'country', 'state', 'address']
Expected response :
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"first_name": "Satish",
"last_name": "Kumar",
"country": {
"id": 23,
"country_name": "India"
},
"state": {
"id": 22,
"state_name": "Delhi"
},
"address": "New Delhi"
}
],
"page_size": 10,
"model_type": "User"
}
I am getting:
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"first_name": "Satish",
"last_name": "Kumar",
"country": 23,
"state": 22,
"address": "New Delhi"
}
],
"page_size": 10,
"model_type": "User"
}
In the views.py the codes look like:
class UserList(generics.ListCreateAPIView):
filter_backends = [filters.SearchFilter, filters.OrderingFilter]
search_fields = ['first_name', 'last_name']
ordering_fields = ['id', 'first_name', 'last_name']
ordering = ['first_name']
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = [permissions.IsAuthenticated]
def list(self, request, *args, **kwargs):
page_size_req = self.request.query_params.get('page_size', None)
if page_size_req is not None:
records_per_page = page_size_req
pagination.PageNumberPagination.page_size = int(page_size_req)
else:
records_per_page = 10
response = super().list(request, args, kwargs)
# Add additional info required:
response.data['page_size'] = records_per_page
response.data['model_type'] = 'User'
return response
Can someone please help me figure out, how I can achieve the desired results in this case? Thanks for your time in advance.
In that case, add depth to your serializer:
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'first_name', 'last_name', 'country', 'state', 'address']
depth = 1
I am newer in Django rest api. My code is bellow:
class PatientViewSet(viewsets.ModelViewSet):
queryset = Patient.objects.all()
serializer_class = PatientSerializer
filter_backends = (DjangoFilterBackend, filters.OrderingFilter)
filterset_fields = ['id', 'email', 'mobile', 'status', 'type', 'gender']
ordering_fields = ['id', 'name']
def get_queryset(self):
queryset = Patient.objects.all()
status = self.request.query_params.get('status')
name = self.request.query_params.get('name')
if not status:
queryset = queryset.exclude(status="DELETE")
if name:
queryset = queryset.filter(name__icontains=name)
return queryset
def retrieve(self, request, pk=None):
queryset = Patient.objects.all()
patient = get_object_or_404(queryset, pk=pk)
serializer = PatientSerializer(patient)
summary = dict()
summary['payment'] = list(PatientPayment.objects.filter(patient_id=pk).aggregate(Sum('amount')).values())[0]
summary['appointment'] = DoctorAppointment.objects.filter(patient_id=pk).count()
d_appoint = DoctorAppointment.objects.filter(patient__id=pk).last()
appoint_data = DoctorAppointmentSerializer(d_appoint)
summary['last_appointment'] = appoint_data
content = {"code": 20000, "data": serializer.data, "summary": summary}
return Response(content)
Here url is:
http://127.0.0.1:8000/api/patients/2/
When I run in postman it getting the error bellow:
TypeError at /api/patients/2/
Object of type 'DoctorAppointmentSerializer' is not JSON serializable
Here problem with the code snippet:
d_appoint = DoctorAppointment.objects.filter(patient__id=pk).last()
appoint_data = DoctorAppointmentSerializer(d_appoint)
My question is how can I getting my result?
DoctorAppointmentSerializer Class:
class DoctorAppointmentSerializer(serializers.HyperlinkedModelSerializer):
patient = PatientSerializer(read_only=True)
patient_id = serializers.IntegerField()
doctor = DoctorSerializer(read_only=True)
doctor_id = serializers.IntegerField()
doc_image = Base64ImageField(
allow_null=True, max_length=None, use_url=True, required=False
)
doc_file = Base64ImageField(
allow_null=True, max_length=None, use_url=True, required=False
)
class Meta:
model = DoctorAppointment
fields = ['id', 'name', 'mobile', 'problem', 'age', 'gender', 'description', 'doctor', 'doctor_id', 'patient',
'patient_id', 'advice', 'doc_image', 'doc_file', 'created_at']
You have to call the .data property of DoctorAppointmentSerializer class
appoint_data = DoctorAppointmentSerializer(d_appoint).data
^^^^^^
I have next models
class User(AbstractUser):
ip_address = models.CharField(max_length=15)
class Statistic(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='statistics')
clicks = models.PositiveSmallIntegerField()
and serializers
class UserListSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'first_name', 'ip_address']
class UserStatisticSerializer(serializers.ModelSerializer):
class Meta:
model = Statistic
How can I get in Response data in following format:
{
'user_data': {
'id': 1, 'first_name': 'name', ...,
'statistics': [
{'id': 1, 'clicks': 100},
{'id': 3, 'clicks': 550}
]
}
I go to the link /api/v1/users/<int:pk>/ and call next function:
class UserDetailStatisticApiView(RetrieveAPIView):
queryset = ???
serializer_class = ???
Thnx for help
View
class UserDetailStatisticApiView(RetrieveAPIView):
queryset = User.objects.all()
serializer_class = UserListSerializer
Serializers
class UserStatisticSerializer(serializers.ModelSerializer):
class Meta:
model = Statistic
fields = '__all__'
class UserListSerializer(serializers.ModelSerializer):
statistics = SerializerMethodField()
class Meta:
model = User
fields = ['id', 'first_name', 'statistics']
def get_statistics(self,obj):
statistics = Statistic.objects.filter(user=obj)
return UserStatisticSerializer(statistics, many=True).data
serializers
class StatisticSerializer(serializers.ModelSerializer):
class Meta:
model = Statistic
fields = ['date', 'clicks', 'page_views']
class UserStatisticSerializer(serializers.ModelSerializer):
statistics = StatisticSerializer(many=True)
class Meta:
model = User
fields = [
'first_name', 'last_name', 'gender', 'ip_address', 'statistics'
]
views
class UserDetailStatisticApiView(RetrieveAPIView):
queryset = User.objects.all()
serializer_class = UserStatisticSerializer