How to create a graphql mutation with a relation in Django - python

I have a problem with creating mutations in graphql that contain a relation. I don't know where to start.
For example - three classes of models:
class HotelGuests(models.Model):
id = models.UUIDField(primary_key=True,
default=uuid.uuid4,
editable=False)
name = models.CharField(max_length=46, default='noname')
lastname = models.CharField(max_length=46, default='noname')
email = models.EmailField(max_length=254)
tel_number = models.CharField(max_length=12, blank=True, null=True)
class Rooms(models.Model):
room_number = models.PositiveSmallIntegerField()
min_vacancy = models.PositiveSmallIntegerField(default=1)
max_vacancy = models.PositiveSmallIntegerField(default=7)
class Reservations(models.Model):
BOOKING_STATUS = {
(0, 'Do zatwierdzenia'),
(1, 'Zatwierdzona'),
(2, 'Zrealizowana'),
(3, 'Anulowana'),
}
price = models.FloatField(default=0)
prepayment_price = models.FloatField(default=0, blank=True, null=True)
number_of_guests = models.PositiveSmallIntegerField()
date_from = models.DateField(default=now)
date_to = models.DateField(default=now)
description = models.TextField(blank=True, null=True)
booking_status = models.PositiveSmallIntegerField(default=0, choices=BOOKING_STATUS)
hotel_guest = models.ForeignKey(HotelGuests, on_delete=models.CASCADE)
room = models.ForeignKey(Rooms, on_delete=models.SET_NULL, blank=True, null=True)
Three classes of graphql types:
class HotelGuestType(DjangoObjectType):
class Meta:
model = HotelGuests
fields = ('id', 'name', 'lastname', 'email', 'tel_number')
class RoomType(DjangoObjectType):
class Meta:
model = Rooms
fields = ('id', 'room_number', 'min_vacancy', 'max_vacancy')
class ReservationType(DjangoObjectType):
class Meta:
model = Reservations
fields = ('id',
'price',
'prepayment_price',
'number_of_guests',
'date_from',
'date_to',
'description',
'booking_status',
'hotel_guest',
'room',)
And three classes of node:
class HotelGuestNode(DjangoObjectType):
class Meta:
model = HotelGuests
filter_fields = ['id',
'name',
'lastname',
'email',
'tel_number']
interfaces = (relay.Node, )
class RoomNode(DjangoObjectType):
class Meta:
model = Rooms
filter_fields = ['id',
'room_number',
'min_vacancy',
'max_vacancy']
interfaces = (relay.Node, )
class ReservationNode(DjangoObjectType):
in_room = relay.ConnectionField(RoomNode, description='InRoom')
booked_by = relay.ConnectionField(HotelGuestNode, description='BookedBy')
#resolve_only_args
def resolve_in_room(self):
return self.in_room.all()
class Meta:
model = Reservations
filter_fields = ['id',
'price',
'prepayment_price',
'number_of_guests',
'date_from',
'date_to',
'description',
'booking_status']
interfaces = (relay.Node,)
How could I make a mutation out of this in which I would create a reservation object connected to a hotel guest and a room?

when you declare your hotel_guest and room fields inside your Reservations Model you can create a related_name like this:
hotel_guest = models.ForeignKey(HotelGuests, on_delete=models.CASCADE, related_name="hotel_reservation")
room = models.ForeignKey(Rooms, on_delete=models.SET_NULL, blank=True, null=True, related_name="hotel_room")
Then you can access it in your HotelGuestType or your RoomType using the respective related_name.
This allows you to use them in your Query

Related

DRF display nested JSON

I have my DRF app. In my case, one wallet can have many entries such as income or expense. When I call my endpoint (viewset) I get data in this format:
[
{
"id": "d458196e-49f1-42db-8bc2-ee1dba438953",
"owner": 1,
"viewable": [],
"entry": []
}
]
How can I get the content of "entry" variable?.
class Category(models.Model):
name = models.CharField(max_length=20, unique=True)
def __str__(self):
return self.name
class BudgetEntry(models.Model):
STATE= [
('income','income'),
('expenses','expenses'),
]
amount = models.IntegerField()
entry_type = models.CharField(max_length=15, choices=STATE, null=True)
entry_category = models.ForeignKey(Category, null=True, blank=True, on_delete=models.SET_NULL)
class WalletInstance(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, unique=True)
owner = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='owner', on_delete=models.CASCADE)
viewable = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='can_view', blank=True)
entry = models.ManyToManyField(BudgetEntry, related_name='BudgetEntry', blank=True)
Serializers.py:
class BudgetEntrySerializer(serializers.ModelSerializer):
class Meta:
model = BudgetEntry
fields = '__all__'
class WalletInstanceSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.id')
class Meta:
model = WalletInstance
fields = '__all__'
Views.py:
class WalletViewset(viewsets.ModelViewSet):
permission_classes = [IsAuthenticated]
serializer_class = WalletInstanceSerializer
def get_queryset(self):
user_id = self.request.user.id
available = WalletInstance.objects.filter(
Q(owner=user_id)
)
return available
Change your serializer like this:
class WalletInstanceSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.id')
entry = BudgetEntrySerializer(many=True, read_only=True)
class Meta:
model = WalletInstance
fields = '__all__'

How build a category model after building legacy model in Django REST Framework

Hello, I have a question about improving legacy models.
The Material model is old model, and i want to make category by using new model 'type'. But i have a little problem with when i use admin site. In admin site, i hope to choose the 'type' first, and upload data .. how can i make better
models
# new model
class MaterialType(BaseModel):
type = models.CharField(choices=MaterialTypeChoice.choices, max_length=50, null=True, blank=True)
def __str__(self):
return self.type
# old model
class Material(models.Model):
type = models.ForeignKey(MaterialType, verbose_name=, null=True, blank=True, on_delete=models.SET_NULL)
name = models.CharField max_length=50, null=True, blank=True)
size = models.CharField(max_length=50, null=True, blank=True)
unit = models.CharField(max_length=5, null=True, blank=True)
price_unit = models.IntegerField(null=True, blank=True)
def __str__(self):
return self.name
serializers
# new
class MaterialTypeListSerializer(serializers.ModelSerializer):
class Meta:
model = MaterialType
fields = ["type"]
# old
class MaterialListSerializer(serializers.ModelSerializer):
class Meta:
model = Material
fields = ["id", "type", "name", "size", "unit", "price_unit"]
views
# new
class MaterialTypeList(ListCreateAPIView):
queryset = MaterialType.objects.all()
serializer_class = MaterialTypeListSerializer
# old
class MaterialList(ListAPIView):
queryset = Material.objects.all()
filter_class = MaterialFilter
serializer_class = MaterialListSerializer
admin
#admin.register(Material)
class MaterialAdmin(ImportExportModelAdmin):
list_display = ["name", "size", "unit", "price_unit"]
list_display_links = ("name",)
list_filter = ("type",)
list_per_page = 10
# list_editable = ('type',)
search_fields = ("name", "size")
resource_class = MaterialResource
#admin.register(MaterialType)
class MaterialTypeAdmin(ImportExportModelAdmin):
list_display = ["type"]
list_filter = ("type",)
list_per_page = 10
# list_editable = ('type',)

ValueError when trying to create through Django REST Framework

I get a ValueError Cannot assign "[]": "Match.stats" must be a "Stats" instance. when I try and create a match through the browsable API but can create one through the shell just fine.
If I remove the HyperlinkedRelatedField from the MatchSerializer it can create just fine.
models.py
class Player(models.Model):
name = models.CharField(max_length=30)
account = models.IntegerField()
place = models.CharField(max_length=30)
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='players')
def __str__(self):
return self.name
class Match(models.Model):
game = models.IntegerField()
length = models.IntegerField()
win = models.BooleanField()
player = models.ForeignKey(Player, on_delete=models.CASCADE, related_name='matches')
def __str__(self):
return str(self.game)
class Stats(models.Model):
goals = models.IntegerField()
assists = models.IntegerField()
time = models.IntegerField()
match = models.OneToOneField(Match, on_delete=models.CASCADE, related_name='stats')
def __str__(self):
return '{} {}'.format(str(self.goals), str(self.match))
class Team(models.Model):
possession = models.IntegerField()
goals = models.IntegerField()
assists = models.IntegerField()
extra = models.BooleanField(default=False)
match = models.OneToOneField(Match, on_delete=models.CASCADE, related_name='teams')
def __str__(self):
return '{} - {}'.format(str(self.possession), str(self.match))
serializer.py
class UserSerializer(serializers.ModelSerializer):
players = serializers.HyperlinkedRelatedField(many=True, view_name='players-detail', queryset=Player.objects.all())
class Meta:
model = User
fields = ('id', 'username', 'email', 'first_name', 'last_name', 'players')
class PlayerSerializer(serializers.ModelSerializer):
user = serializers.ReadOnlyField(source='user.username')
matches = serializers.HyperlinkedRelatedField(many=True, view_name='matches-detail', queryset=Match.objects.all())
class Meta:
model = Player
fields = ('id', 'name', 'account', 'place', 'user', 'matches')
class MatchSerializer(serializers.ModelSerializer):
player = serializers.ReadOnlyField(source='player.name')
stats = serializers.HyperlinkedRelatedField(many=True, view_name='stats-detail', queryset=Stats.objects.all())
teams = serializers.HyperlinkedRelatedField(many=True, view_name='teams-detail', queryset=Team.objects.all())
class Meta:
model = Match
fields = ('id', 'game', 'length', 'win', 'player', 'stats', 'teams')
class StatsSerializer(serializers.ModelSerializer):
match = serializers.ReadOnlyField(source='match.game')
class Meta:
model = Stats
fields = ('id', 'goals', 'assists', 'time', 'match')
class TeamSerializer(serializers.ModelSerializer):
match = serializers.ReadOnlyField(source='match.game')
class Meta:
model = Team
fields = ('id', 'possession', 'goals', 'assists', 'extra', 'match')
I can go into python manage.py shell and create a match just fine.
>>>m = Match(game=12345, length=5674, win=True, player=player1) # a previously queried player
>>>m.save()
I'm just a little confused what is going
By default, HyperlineRelatedField allow both read and write operation, so I think you need make it read-only true:
class MatchSerializer(serializers.ModelSerializer):
player = serializers.ReadOnlyField(source='player.name')
stats = serializers.HyperlinkedRelatedField(view_name='stats-detail', read_only=True)
teams = serializers.HyperlinkedRelatedField(view_name='teams-detail', read_only=True)
class Meta:
model = Match
fields = ('id', 'game', 'length', 'win', 'player', 'stats', 'teams')
Also, you don't need to add many=True, because both teams and stats are OneToOne relations. So one entry for both tables will be created for each match.

django rest use relation model field in objects filter

hi i have 3 model name product, category, and categoryassin i want get 10 row from product object where category title is develop .
i did like this but it not work and i get error
class GetWebProductAPiView(APIView):
def get(self,request):
obj = Product.objects.filter(category__title = "develop")
serializer = ProductSerializer(instance=obj,many=True,context={'request': request})
return Response(serializer.data)
err:
Related Field got invalid lookup: title
how can in fix it?
this is my models
class Product(models.Model):
product_id = models.AutoField(primary_key=True)
author = models.ForeignKey(User, on_delete=models.CASCADE, db_index=True)
title = models.CharField(max_length=200)
video_length = models.CharField(max_length=20, null=True, blank=True)
mini_description = models.CharField(max_length=1000, null=True, blank=True)
full_description = models.TextField(null=True, blank=True)
you_need = models.CharField(max_length=1000, null=True)
you_learn = models.CharField(max_length=2000, null=True)
price = models.CharField(max_length=50, null=True, blank=True)
free = models.BooleanField(default=False)
video_level = models.CharField(max_length=100, null=True, blank=True)
created_date = models.DateTimeField(auto_now_add=True)
updated_date = models.DateTimeField(auto_now=True)
publish = models.BooleanField(default=False)
draft = models.BooleanField(default=False)
slug = models.SlugField(allow_unicode=True, null=True, blank=True)
image = models.FileField(upload_to=upload_to_custom_p, null=True, blank=True)
class Category(models.Model):
parent_id = models.IntegerField(null=True, blank=True)
title = models.CharField(max_length=200)
class CategoryAssin(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE, to_field='product_id', related_name='category')
cat_id = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='categoryid')
and this is related serilizers
class CategorySerializer(ModelSerializer):
class Meta:
model = Category
fields = [
'id',
'parent_id',
'title',
]
read_only_fields = ['id']
class CategoryAssinSeralizer(ModelSerializer):
product = serializers.SerializerMethodField()
def get_product(self, obj):
return obj.product.title
cat_name = serializers.SerializerMethodField()
def get_cat_name(self, obj):
return obj.cat_id.title
class Meta:
model = CategoryAssin
fields = [
'cat_id',
'cat_name',
'product',
]
read_only_fields = ['id']
# product
class ProductSerializer(ModelSerializer):
product_ratings = ProductRatingsSerializer(many=True, read_only=True)
product_discount = ProductDiscountControllSerializer(read_only=True)
product_video = ProductWithoutVideoSerializer(many=True, read_only=True)
author = serializers.SerializerMethodField()
base64_image = serializers.SerializerMethodField(read_only=True, allow_null=True)
def get_author(self, obj):
return obj.author.first_name + ' ' + obj.author.last_name
category = CategoryAssinSeralizer(many=True)
url = main_page_post
class Meta:
model = Product
fields = [
'product_id',
'url',
'author',
'title',
'mini_description',
'you_learn',
'you_need',
'full_description',
'price',
'free',
'video_level',
'video_length',
'created_date',
'updated_date',
'product_ratings',
'product_discount',
'product_video',
'image',
'slug',
'draft',
'publish',
'category',
'base64_image',
]
read_only_fields = ['product_id',
'created_date',
'updated_date',
'author',
'base64_image',
'product_ratings',
'product_discount',
]
Add this in you view:
prod_ids = CategoryAssin.objects.filter(cat_id__title='develop').values_list('product', flat=True)
obj = Product.objects.filter(product_id__in=prod_ids)

New Relational Fields Added wont appear on DjangoRestFramework API

I have some issue here about the relational field (herd/herd_id) added to my model. it wont appear in the API as fields of my Animal model and AnimalSerializer djangorestframework
Here is my Animal model and serializer:
models.py
class Animal(models.Model):
this_id = models.CharField(max_length=25)
name = models.CharField(max_length=25)
species_type = models.CharField(max_length=25)
breed = models.CharField(max_length=25)
date_of_birth = models.DateField()
birth_weight = models.IntegerField()
sex = models.CharField(max_length=7)
sibling_order = models.IntegerField()
sire_id = models.CharField(max_length=20)
sire_name = models.CharField(max_length=25)
dam_id = models.CharField(max_length=25)
dam_name = models.CharField(max_length=25)
rf_id = models.CharField(max_length=25)
comment = models.TextField(max_length=250, null=True)
herd = models.ForeignKey(Herd, related_name='animals', on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True, editable=False)
updated_at = models.DateTimeField(auto_now=True, editable=False)
class Meta:
ordering = ('name',)
serializers.py
class AnimalSerializer(serializers.ModelSerializer):
class Meta:
model = Animal
fields = (
'this_id',
'name',
'species_type',
'breed',
'date_of_birth',
'birth_weight',
'sibling_order',
'sex',
'sire_id',
'sire_name',
'dam_id',
'dam_name',
'rf_id',
'comment',
'herd_id', // <--- this field wont appear in the djangorestframework UI.
'created_at',
'updated_at',
)
read_only_fields = ('id', 'created_at', 'updated_at')
Here is the image. and look for the herd_id field it wont appear. Please help
I just change the herd_id to herd column name so django will recognize the matching serialization name.

Categories