Django Form. Overwrite model field - django-forms

I've a Model
MODEL
from django.conf.global_settings import LANGUAGES
class Book(models.Model):
title = models.CharField(max_length=120)
language = models.CharField(max_length=56, choices=LANGUAGES, blank=True)
And Form
FORM
class SearchForm(forms.ModelForm):
class Meta:
model = Book
fields = ["title", "language"]
I use crispy to render the form and the problem is that I get label and required inherited from Book model. So I need to somehow inhertit the max_length form model fields and set new labels value.
MY APPROACH
class SearchForm(forms.ModelForm):
title = forms.CharField(
widget=forms.TextInput(attrs={"placeholder": "Title"}), required=False, label=""
)
language = forms.CharField(
widget=forms.TextInput(attrs={"placeholder": "Language"}), label=""
)
class Meta:
model = Book
fields = ["title","language"]
Now there are no labels and title is no required but there is no length limit on title and LANGUAGES choices inherited from Book model.
How to solve that?

Few seconds after post an idea came to my mind.
class Meta:
model = Book
fields = ["title", "language"]
labels = {
"title": "",
"language": ""
}
widgets = {
'title': forms.TextInput(attrs={'placeholder': 'Title'}),
'language': forms.Select(attrs={'option': 'Language'}),
}
Now the only question I've is how to set the first value for language field. At the moment is just -------------.

Related

Django rest framework depth serializer only in to_representation

I have a model with many foreing keys. I want to do a POST with only ids and recieve a response with depth 1. When I set depth=1 it´s doesn´t work.
class State(models.Model):
name = models.CharField(max_length=255)
class City(models.Model):
state = models.ForeingKey(State, on_delete=models.PROTECT)
name = models.CharField(max_length=255)
class CitySerializer(serializers.ModelSerializer):
class Meta:
model = City
fields = '__all__'
I wanna post some like this
{
"state":1,
"name":"City Name"
}
And get
{
"id":1,
"name":"City Name",
"state":{
"id":1,
"name": "State Name"
}
}
Did you try to make a StateSerializer and use it in CitySerializer?
class StateSerializer(serializers.ModelSerializer):
class Meta:
model = State
fields = '__all__'
class CitySerializer(serializers.ModelSerializer):
state = StateSerializer(read_only=True)
class Meta:
model = City
fields = '__all__'
Check the doc here.

Django Rest Framework - Updating a ForeignKey Field entry in the view

In my Django Rest Framework project, I have a ForeignKey relationship between two models:
class Book(models.Model):
...
category = models.ForeignKey(Category, on_delete=models.CASCADE, blank=True, null=True)
...
class Category(models.Model):
name = models.CharField(max_length=100, blank=False)
As you can see, a Book can belong to a Category but it does not have to. That means the 'category' field could be null.
So, in my views.py, any Book instance can be updated/patched if the user wants to assign a certain Book to a particular Category. That views.py update method looks like this:
class UpdateBooksCategory(generics.GenericAPIView):
'''
Class-based view to update the 'category' field of a Book instance.
'''
serializer_class = BookSerializer
permission_classes = [IsAuthenticated]
def patch(self, request,*args, **kwargs):
# get the Book instance first
book = Book.objects.get(pk=request.data.get('bookId'))
# if it is not assigned to a Category, then assign it
if book and not book.category:
book.category = Category.objects.get(name=request.data.get('categoryName'))
book.save()
serializer = self.get_serializer(book, context={"request": request})
return Response(serializer.data)
# otherwise, return a generic response
return Response({'response': "You have already put the selected Book in a Category."})
If you can see, first I get the Book instance that the user wants to update by using the Book's ID. If its Category field is not already filled, I get a Category instance using the given category name and assign it.
For the sake of completeness, here are my serializer classes:
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = ['id', 'name']
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ['id', /*some other fields*/,..., 'category']
So, finally my question: I wanted to know if this is the preferred way of updating a ForeingKey field like this? I mean looking at the UpdateBooksCategory class-based view, is this the right way of doing it? The code works ( I tested it with PostMan) but since I am new to DRF I wanted to know if such an updating process is correct.
You can change your BookSerializer:
class BookSerializer(serializers.ModelSerializer):
category_id = serializers.IntegerField(write_only=True)
category = CategorySerializer(read_only=True)
class Meta:
model = Book
fields = [
'id',
# some other fields,
'category',
'category_id',
]
category will be a nested data that is read only, then setting the category will be by including the category_id in your requests.

DRF How to parse text field and serialize result to set of models

I have next models in models.py
class Rule(models.Model):
name = models.CharField(max_length=30)
description = models.TextField()
class Question(models.Model):
question = models.TextField(default='')
answer = models.TextField(default='')
rules = models.TextField(default='') # here I decided to store rules names only, separated by coma
I have next serializers in serializers.py
class RuleSerializer(serializers.ModelSerializer):
class Meta:
model = Rule
fields = ['name', 'description']
class QuestionSerializer(serializers.ModelSerializer):
class Meta:
model = Question
fields = ['question', 'answer', 'rules']
as result output I have next JSON
[
{
"question": "How are you?",
"answer": "fine",
"rules": "rule 1, rule 2, rule 3"
}
]
but how can I convert rules string to objects? I found one solution, but it is means I should convert/serialize Rule manually
class RuleSerializer(serializers.ModelSerializer):
class Meta:
model = Rule
fields = ['name', 'description']
class QuestionSerializer(serializers.ModelSerializer):
rules = serializers.SerializerMethodField()
class Meta:
model = Question
fields = ['question', 'answer', 'rules']
def get_rules(self, obj):
names = [name.strip() for name in obj.rules.split(",")]
rules = Rule.objects.all().filter(name__in=names)
return [{
"name": rule.name,
"description": rule.description,
} for rule in rules]
And of course I can do it manually, but how to do it with already existing serializer?
def get_rules(self, obj):
names = [name.strip() for name in obj.rules.split(",")]
rules = Rule.objects.all().filter(name__in=names)
serializer = RuleSerializer(rules)
serializer.is_valid() # Mandatory
return serializer.data

Custom Nested serializer and lookups

I have a Category model and a Menu Model and I want to display the JSON data as follows:
{
"category":{
"category": "Something",
"menu": [
{
"id": 1,
"dish": "Sample Dish",
"price": 150,
"restaurant": 1
},
{
"id": 1,
"dish": "Sample Dish",
"price": 150,
"restaurant": 1
},
}
}
Here are the models:
class Menu(models.Model):
dish = models.CharField(max_length=250)
category = models.ForeignKey('Menu_Category',on_delete=models.CASCADE,related_name='menu')
price = models.IntegerField()
restaurant = models.ForeignKey('Restaurant',on_delete=models.CASCADE,related_name='menu')
def __str__(self):
return self.dish
class Menu_Category(models.Model):
category = models.CharField(max_length=255,default='')
def __str__(self):
return self.category
class Meta:
verbose_name = 'Menu Category'
verbose_name_plural = 'Menu Categories'
and here is the seriailizer:
class MenuSerializer(serializers.Serializer):
class Meta:
model = Menu
fields =['dish','price','restaurant']
class MenuCategorySerializer(serializers.Serializer):
menu = MenuSerializer(read_only=True,many=True)
class Meta:
model = Menu_Category
fields = ['category','menu']
I have tried building up some custom nested serializers as well and cant seem to get the JSON data right.
You should be able to do this by creating the property on the category model that returns it's related menus. Just FYI(You can also use self.menu_set.all()). See below for the model change
class Menu_Category(models.Model):
category = models.CharField(max_length=255,default='')
def __str__(self):
return self.category
class Meta:
verbose_name = 'Menu Category'
verbose_name_plural = 'Menu Categories'
#property
def menu(self):
return Menu.objects.filter(category=self)
In the serializer, change the serializer inheritence to ModelSerializer. You shouldn't need to change anything else unless your property name in models.py is different to the serializer fieldname
Sources in Rest framework serializers
class MenuCategorySerializer(serializers.ModelSerializer):
menu = MenuSerializer(read_only=True,many=True, source='menu') # -- Source must be the same as declared in models.py property
class Meta:
model = Menu_Category
fields = ['category','menu']
You have to add id to MenuSerializer fields and you can use reverse relation menu_set with source parameter in serializer like below
class MenuSerializer(serializers.Serializer):
class Meta:
model = Menu
fields =['id', 'dish','price','restaurant']
class MenuCategorySerializer(serializers.Serializer):
menu = MenuSerializer(read_only=True,many=True, source='menu_set')
class Meta:
model = Menu_Category
fields = ['category','menu']

Django - combining form fields with modelform fields

Using Django 1.8, I'm trying to render a form where some of the fields come from the database like the many-to-many field below and some other fields are not in the database at all:
models.py
class Transcript(models.Model):
name = models.CharField(max_length=65, unique=True)
forms.py
class SummaryForm(forms.Form):
size = forms.CharField(label='size', max_length=50, required=False)
transcripts = models.ManyToManyField(Transcript, blank=True)
class Meta:
widgets = {
'transcript': autocomplete.ModelSelect2Multiple(url='tr-autocomplete'),
}
Why on my template page I do not see transcripts rendered and how to render it?
This worked:
transcripts = forms.MultipleChoiceField(label='Transcript', required=False)

Resources