New Relational Fields Added wont appear on DjangoRestFramework API - python

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.

Related

How to force fill field to Inline Models in Django

We added the model named Comment as inlines in the Course model. We want to make it mandatory to fill in the fields in the Inlines model when the Save button is clicked.
# models.py
class Course(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
...
updated_at = models.DateTimeField(auto_now=True))
class Comment(models.Model):
CHOICES=[(1,'Approved'),
(0,'Rejected')]
course = models.ForeignKey(Course, on_delete=models.PROTECT)
opinion = models.IntegerField(choices=CHOICES)
comment = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
# admin.py
class CommentInline(admin.StackedInline):
model = Comment
max_num = 1
radio_fields={'opinion':admin.HORIZONTAL}
#admin.register(Course)
class CourseAdmin(admin.ModelAdmin):
list_display = ('title', 'category', 'reviewer', 'created_at',)
inlines = [CommentInline,]

How to create a graphql mutation with a relation in Django

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

Django: Model does not appear on admin panel

This is the model that I want to show on the admin panel. I'm registering the model via admin.py file with admin.site.register(Ad). I tried to re-write the register line twice, and an exception appeared that the model is already registered.
class Ad(AdModel):
plate = models.CharField(max_length=50, unique=True)
description = models.TextField(max_length=500)
ad_type = models.CharField(
max_length=255,
choices=AdTypes.get_choices(),
default=AdTypes.OFFERING,
)
price = models.PositiveIntegerField(
default=0,
help_text='In cents'
)
location = models.CharField(
max_length=255,
choices=AdLocations.get_choices(),
default=AdLocations.VILNIUS,
)
user = models.ForeignKey(User, on_delete=models.PROTECT)
approved_date = models.DateField(null=True, blank=True)
approved_by = models.ForeignKey(
User, on_delete=models.PROTECT, related_name='approved_by', null=True
)
The two base models:
class UUIDBaseModel(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
uuid = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
class Meta:
abstract = True
class AdModel(UUIDBaseModel):
expires_at = models.DateTimeField(null=True)
is_draft = models.BooleanField(default=False)
is_active = models.BooleanField(default=False)
class Meta:
abstract = True
This is really strange, maybe that could be the problem because of the naming 'Ad'? I have a serializer for this model and everything works just fine, but the admin panel doesn't want to display it.
views.py
class AdCreateViewSet(ModelViewSet, CreateModelMixin):
serializer_class = AdCreateSerializer
permission_classes = (AllowAny,)
filter_backends = [DjangoFilterBackend]
search_fields = ('plate', 'description', 'user__email')
queryset = Ad.objects.select_related('user')
def perform_create(self, serializer):
user = User.objects.first()
serializer.save(user=user) # self.request.user)
serializers.py
class AdCreateSerializer(CustomAdSerializer):
class Meta:
model = Ad
exclude = ['expires_at']
read_only_fields = ('user',)

Django API ManyToMany on existing databse not working

at the moment I try to get recipes from my API. I have a Database with two tables one is with recipes and their ids but without the ingredients, the other table contains the ingredients and also the recipe id. Now I cant find a way that the API "combines" those. Maybe its because I added in my ingredient model to the recipe id the related name, but I had to do this because otherwise, this error occurred:
ERRORS:
recipes.Ingredients.recipeid: (fields.E303) Reverse query name for 'Ingredients.recipeid' clashes with field name 'Recipe.ingredients'.
HINT: Rename field 'Recipe.ingredients', or add/change a related_name argument to the definition for field 'Ingredients.recipeid'.
Models
from django.db import models
class Ingredients(models.Model):
ingredientid = models.AutoField(db_column='IngredientID', primary_key=True, blank=True)
recipeid = models.ForeignKey('Recipe', models.DO_NOTHING, db_column='recipeid', blank=True, null=True, related_name='+')
amount = models.CharField(blank=True, null=True, max_length=100)
unit = models.CharField(blank=True, null=True, max_length=100)
unit2 = models.CharField(blank=True, null=True, max_length=100)
ingredient = models.CharField(db_column='Ingredient', blank=True, null=True, max_length=255)
class Meta:
managed = False
db_table = 'Ingredients'
class Recipe(models.Model):
recipeid = models.AutoField(db_column='RecipeID', primary_key=True, blank=True) # Field name made lowercase.
title = models.CharField(db_column='Title', blank=True, null=True, max_length=255) # Field name made lowercase.
preperation = models.TextField(db_column='Preperation', blank=True, null=True) # Field name made lowercase.
images = models.CharField(db_column='Images', blank=True, null=True, max_length=255) # Field name made lowercase.
#ingredients = models.ManyToManyField(Ingredients)
ingredients = models.ManyToManyField(Ingredients, related_name='recipes')
class Meta:
managed = True
db_table = 'Recipes'
When there is no issue it has to be in the serializer or in the view.
Serializer
class IngredientsSerializer(serializers.ModelSerializer):
# ingredients = serializers.CharField(source='ingredients__ingredients')
class Meta:
model = Ingredients
fields = ['ingredient','recipeid']
class FullRecipeSerializer(serializers.ModelSerializer):
ingredients = IngredientsSerializer(many=True)
class Meta:
model = Recipe
fields = ['title','ingredients']
View
class FullRecipesView(generics.ListCreateAPIView):
serializer_class = FullRecipeSerializer
permission_classes = [
permissions.AllowAny
]
queryset = Recipe.objects.all()
This is at the moment my output
But I want e.g. the recipe with id 0 and all the ingredients which have also recipe id 0.
I really hope that you can help me. Thank you so much!
Rename ingredients to some other name in FullRecipeSerializer. It conflicts with ingredients in Recipe model. This should solve your issue. For example
class FullRecipeSerializer(serializers.ModelSerializer):
ingredients_recipe = IngredientsSerializer(many=True, source= 'ingredientid')
class Meta:
model = Recipe
fields = ['title','ingredients_recipe']

How to update a list of instance by counting the related item upon list?

I want to update a list of instances with the total number of books links to the category.
The response is as mentioned below. I have some books link to 'History' for example. How do I update the total number on the list whenever I call it?
[
{
"id": 1,
"category_name": "History",
"category_code": "his",
"is_tab": true,
"add_time": "2020-03-02T15:56:58.469917Z",
"total_number": 0
},
{
"id": 2,
"category_name": "Romance",
"category_code": "ROM",
"is_tab": true,
"add_time": "2020-05-22T17:02:47.919479Z",
"total_number": 0
},
{
"id": 3,
"category_name": "Sci-fic",
"category_code": "S-F",
"is_tab": true,
"add_time": "2020-05-22T17:04:57.896846Z",
"total_number": 0
}
]
serializer.py
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = BookCategory
fields = ('id', 'category_name', 'category_code', "is_tab", 'add_time', 'total_number')
view.py
class BookCategoryDetailView(ListCreateAPIView, RetrieveModelMixin):
queryset = BookCategory.objects.all()
serializer_class = CategorySerializer
model.py
class BookCategory(models.Model):
category_name = models.CharField(default="", max_length=30, verbose_name='Category name')
category_code = models.CharField(default="", max_length=30, verbose_name='Category code')
is_tab = models.BooleanField(default=False, verbose_name='is Navigate')
add_time = models.DateTimeField(auto_now_add=True, verbose_name='Added time')
total_number = models.BigIntegerField(default=0, verbose_name='Total Number', editable=False)
class Meta:
verbose_name = 'Type Category'
verbose_name_plural = verbose_name
db_table = 'Book Genre'
def __str__(self):
return self.category_name
book model
class Book(models.Model):
BOOK_STATUS = (
('Ongoing', u'Ongoing'),
('Completed', u'Completed')
)
book_name = models.CharField(default="", max_length=30, verbose_name='Book name', unique=True)
book_image = models.ImageField(default="", max_length=30, verbose_name='Book image')
book_status = models.CharField(choices=BOOK_STATUS, default='Ongoing', verbose_name='Book Status', max_length=150,
null=True)
book_author = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.SET_NULL,
verbose_name='author',
related_name='author',
null=True)
book_type = models.ForeignKey(BookCategory,
on_delete=models.CASCADE,
verbose_name='book type',
related_name='book_type',
null=True)
book_short_description = models.TextField(verbose_name='Short description', default='')
book_description = models.TextField(verbose_name='Book Description', default='')
# non-editable values
total_words = models.IntegerField(verbose_name='Total_words', default=0, editable=False)
chapter_count = models.IntegerField(verbose_name='Chapter Count', default=0, editable=False)
total_vote = models.IntegerField(verbose_name='Total vote', default=0, editable=False)
weekly_vote = models.IntegerField(verbose_name='Weekly vote', default=0, editable=False)
total_click = models.IntegerField(verbose_name='Total Click', default=0, editable=False)
fav_num = models.IntegerField(verbose_name='Total favorite number', default=0, editable=False)
added_time = models.DateTimeField(verbose_name='Added time', auto_now_add=True, editable=False)
last_update = models.DateTimeField(verbose_name='last update', auto_now=True, editable=False)
def get_chapter_number(self):
chapter_count = Chapter.objects.filter(self.id).count()
return chapter_count
def get_book_name(self):
return self.book_name
class Meta:
db_table = 'Books'
verbose_name = 'Novel'
verbose_name_plural = verbose_name
Any help would be much appreciated!
A common misconception is to give th related_name=… parameter [Django-doc] the same name as the relation itself. The related_name is the name of the relation in reverse, so the relation Django creates to obtain the Books from a given BookCategory for example. Therefore you can rename these to:
class Book(models.Model):
# …
book_author = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.SET_NULL,
verbose_name='author',
related_name='authored_books',
null=True
)
book_type = models.ForeignKey(
BookCategory,
on_delete=models.CASCADE,
verbose_name='book type',
related_name='books',
null=True
)
# …
It is also better not to store duplicated (aggregate) data in the database, so storing the number of books is usually not a good idea. It turns out that keeping data in sync, even on the same database, is harder than one would expect. It means that if you create a book, delete a book, or change the category of a book, you need to update the count. Furthermore some removals will be triggered by other removals (cascading deletes), or by another tool than through the Django ORM, so that will only make the problem more complicated.
Therefore it is better to remove that field:
class BookCategory(models.Model):
category_name = models.CharField(default="", max_length=30, verbose_name='Category name')
category_code = models.CharField(default="", max_length=30, verbose_name='Category code')
is_tab = models.BooleanField(default=False, verbose_name='is Navigate')
add_time = models.DateTimeField(auto_now_add=True, verbose_name='Added time')
# no total_number
class Meta:
verbose_name = 'Type Category'
verbose_name_plural = 'Type categories'
db_table = 'Book Genre'
def __str__(self):
return self.category_name
You can obtain the number of books per BookCategory by annotating:
from django.db.models import Count
BookCategory.objects.annotate(
total_number=Count('books')
)
This means that the BookCategorys that arise from this queryset will have an extra attribute .total_number that contains the number of related Book objects.
Next we can update the serialzier to work with this total_number:
class CategorySerializer(serializers.ModelSerializer):
total_number = serializers.IntegerField(read_only=True)
class Meta:
model = BookCategory
fields = ('id', 'category_name', 'category_code', "is_tab", 'add_time', 'total_number')
and finally in the BookCategoryDetailView we pass the annotated queryset:
from django.db.models import Count
class BookCategoryDetailView(RetrieveModelMixin, ListCreateAPIView):
queryset = BookCategory.objects.annotate(total_number=Count('books'))
serializer_class = CategorySerializer

Categories