How to make required filling in a form field with a many-to-many relationship in django admin - django-models

I have a Recipes model with an ingredients field with a many-to-many relationship. I have an intermediate Ingredient amount model associated with the ingredients field via through. I want to prohibit the creation of a recipe in django admin without ingredients. I'm trying to solve this problem by creating my own class inherited from BaseInlineFormSet and redefining the clean() method. It doesn't work out yet, I need help, what am I doing wrong?
admin.py
class IngredientsAmountInlineFormset(BaseInlineFormSet):
def clean_ingredients(self):
if len(self.cleaned_data['ingredients']) < 1:
return 'Укажите хотя бы один ингредиент в рецепте'
return self.cleaned_data['ingredients']
class IngredientsAmountInline(admin.TabularInline):
model = IngredientsAmount
formset = IngredientsAmountInlineFormset
extra = 0
#admin.register(Recipes)
class RecipesAdmin(admin.ModelAdmin):
list_display = ('name', 'author', 'favorites_count',)
list_filter = ('name', 'author', 'tags',)
search_fields = ('name', 'author', 'tags',)
empty_value_display = '-пусто-'
inlines = (IngredientsAmountInline,)
models.py
class Ingredients(models.Model):
name = models.CharField(max_length=200, unique=True)
measurement_unit = models.CharField(max_length=200)
...
class Recipes(models.Model):
...
ingredients = models.ManyToManyField(Ingredients,
through='IngredientsAmount',
related_name='recipes',
verbose_name='Ингредиенты',
)
...
class IngredientsAmount(models.Model):
ingredients = models.ForeignKey(Ingredients,
on_delete=models.CASCADE,
related_name='amount',
verbose_name='Ингредиенты',
)
recipes = models.ForeignKey(Recipes,
on_delete=models.CASCADE,
related_name='amount',
verbose_name='Рецепты', )
amount = models.IntegerField()

obiviously clean should raise ValidationException:
class IngredientsAmountInlineFormset(BaseInlineFormSet):
def clean_ingredients(self):
value = self.cleaned_data['ingredients']
if value:
return value
raise ValidationError(_('Укажите хотя бы один ингредиент в рецепте'))
by the way:
Try don't use the direct text message:
'Укажите хотя бы один ингредиент в рецепте'
Wrap your text in gettext/gettext_lazy, like this:
from django.utils.translation import gettext_lazy as _
_('Укажите хотя бы один ингредиент в рецепте')
It help you in future collect those messages together, and translate it if you need.

Related

abstract data from two models with one to many relationship in django

models file
class Posting(models.Model):
company = models.CharField(max_length=250)
recruiter = models.CharField(max_length=250)
image = models.ImageField(upload_to='postings/%Y/%m/%d/', null=True)
description = models.TextField()
position_title = models.CharField(max_length=150)
## Based on LinkedIn
# Auto adds creation date
creation_date = models.DateTimeField(auto_now_add=True)
# If 0, unpaid; if more than 0, paid (can be used to diffrentiate in postings frontend)
pay_range = models.CharField(max_length=250)
location = models.CharField(max_length=1000)
# Number of current applicants (can be used to encourage people)
num_applicants = models.IntegerField(default=0)
def __str__(self):
return self.position_title
class Question(models.Model):
qTypes=[('T','text'),('TA','textarea'),('C','choice')]
question=models.CharField(max_length=10000)
type=models.CharField(max_length=10,choices=qTypes)
post=models.ForeignKey(Posting,on_delete=models.CASCADE)
choices=models.TextField(null=True,blank=True)
serializer
class QuestionSerializer(serializers.ModelSerializer):
class Meta:
model = Question
fields = ('id','type','question','post')
class PostingSerializer(serializers.ModelSerializer):
question=QuestionSerializer(many=False)
class Meta:
model = Posting
fields = ('id', 'company', 'recruiter', 'image', 'description', 'creation_date', 'pay_range', 'location', 'num_applicants', 'position_title','question')
i want to retrieve the post with it's questions like this i could retrieve the data of the question with its post but i dont want that

Django Post request for many to many field ValueError

I am working on a post request in which the user chooses from a list of tags and makes combinations of tags. The combination of tags should then be posted. Nothing should get changed in the Tag table.
These are the models:
models.py
class Tag(models.Model):
name = models.CharField(max_length=256)
language = models.CharField(max_length=256)
objects = models.Manager()
def __str__(self):
"""Return a human readable representation of the model instance."""
return self.name or ''
#property
def tags(self):
tags = self.tagging.values('tag')
return tags.values('tag_id', 'tag__name', 'tag__language')
class Combination(models.Model):
user = models.ForeignKey(CustomUser, on_delete=models.SET_NULL, null=True)
gameround = models.ForeignKey(Gameround, on_delete=models.CASCADE, null=True)
resource = models.ForeignKey(Resource, on_delete=models.CASCADE, null=True)
tag_id = models.ManyToManyField(Tag, null=True)
created = models.DateTimeField(editable=False)
score = models.PositiveIntegerField(default=0)
objects = models.Manager()
def __str__(self):
return str(self.tag_id) or ''
This is the serializer for Combination.
serializers.py
class CombinationSerializer(serializers.ModelSerializer):
tag_id = TagWithIdSerializer(many=True, required=False, write_only=False)
resource_id = serializers.PrimaryKeyRelatedField(queryset=Resource.objects.all(),
required=True,
source='resource',
write_only=False)
gameround_id = serializers.PrimaryKeyRelatedField(queryset=Gameround.objects.all(),
required=False,
source='gameround',
write_only=False)
user_id = serializers.PrimaryKeyRelatedField(queryset=CustomUser.objects.all(),
required=False,
source='user',
write_only=False)
class Meta:
model = Combination
depth = 1
fields = ('id', 'user_id', 'gameround_id', 'resource_id', 'tag_id', 'created', 'score')
def create(self, validated_data):
user = None
request = self.context.get("request")
if request and hasattr(request, "user"):
user = request.user
score = 0
tag_data = validated_data.pop('tag_id', None)
combination = Combination(
user=user,
gameround=validated_data.get("gameround"),
resource=validated_data.get("resource"),
created=datetime.now(),
score=score
)
combination.save()
for tag_object in tag_data[0]:
combination.tag_id.add(tag_object)
return combination
def to_representation(self, instance):
rep = super().to_representation(instance)
rep['tag_id'] = TagWithIdSerializer(instance.tag_id.all(), many=True).data
return rep
I have tried posting the following JSON object to the database:
{
"gameround_id": 2015685170,
"resource_id": 327888,
"tag_id": [{"id": 2014077506, "name": "corwn","language": "en"}]
}
I am getting a ValueError: Field 'id' expected a number but got 'name'.
How can I fix this issue?
you need to provide tag id for each tag not all tag data,
Try like this
{
"gameround_id": 2015685170,
"resource_id": 327888,
"tag_id": [2014077506,2014077507]
}

How to add check constraint validator in serializer in django rest framework?

I have a model defined as follows :
class Order(models.Model):
qty = models.FloatField()
pending_qty = models.FloatField(default=0)
class Meta:
constraints = [
models.CheckConstraint(check=models.Q(
pending_qty__gte=0), name='pending_qty__gte_0')
]
The serializer for this models is as follows:
class NewOrderSz(serializers.ModelSerializer):
class Meta:
model = Order
fields = '__all__'
I want to add a validator in the serializer to validate for the 'pending_qty__gte_0' CheckConstraint in the model. How can I do that ?
View for creating an entity is :
class NewOrder(generics.CreateAPIView):
queryset = models.Order.objects.none()
serializer_class = serializers.NewOrderSz
Just define your pending_qty with FloatField with a min_value constraint
and you should be fine
class NewOrderSz(serializers.ModelSerializer):
pending_qty = serializers.FloatField(min_value=0)
class Meta:
model = Order
fields = '__all__'
class NewOrderSz(serializers.ModelSerializer):
class Meta:
model = Order
fields = '__all__'
def validate_pending_qty(self, value):
if value < 0:
raise serializers.ValidationError("Pending Qty Less Than Zero!")
return value
https://www.django-rest-framework.org/api-guide/serializers/#field-level-validation

How to create model objects via ModelForm ForeignKey?

I have a model for Classroom and Student as shown below
class Classroom(models.Model):
COURSE_NAME = (
('MA8', 'Math 8'),
('SC10', 'Science 10'),
('PH11', 'Physics 11'),
('PH12', 'Physics 12'),
)
BLOCK_NUMBER = (
('11', 'Block 1-1'),
('12', 'Block 1-2'),
('13', 'Block 1-3'),
('14', 'Block 1-4'),
('21', 'Block 2-1'),
('22', 'Block 2-2'),
('23', 'Block 2-3'),
('24', 'Block 2-4'),
)
class_list = models.TextField()
course_name = models.CharField(max_length=20, choices=COURSE_NAME)
course_block = models.CharField(max_length=10, choices=BLOCK_NUMBER)
class Student(models.Model):
classroom = models.ForeignKey(Classroom, on_delete=models.CASCADE)
nickname = models.CharField(default='JohnS', max_length=31)
attend = models.BooleanField(default=True)
I created a form for Classroom.class_list and TextField is where the user copy/pastes a list of names. I want to then parse the class_list and save each individual name as nickname. I first tried the following but this doesn't seem to save the Student objects.
forms.py
class ClassroomForm(ModelForm):
class Meta:
model = Classroom
fields = ['course_name', 'course_block','class_list']
views.py
class ClassroomCreateView(CreateView):
model = Classroom
form_class = ClassroomForm
def form_valid(self, form):
classroom = form.save(commit=False)
s = Student()
for line in classroom.class_list:
s.nickname = line
s.save()
classroom.save()
return super(ClassroomCreateView, self).form_valid(form)
def get_success_url(self):
return reverse('classroom:submitted')
I also tried creating StudentForm which allows a user to choose course_name and course_block (which corresponds to a particular class_list). The form or view would then create the individual Student objects and display them. I read about ModelChoiceField but I can't figure out how to implement this.
How and where do I (auto) create Students objects from a ForeignKey field?
I solved my question with the help of this answer. Here is the modified code I used for models.py. My view is just a standard CreateView from the ModelForm.
class Classroom(models.Model):
... dictionary stuff ..
class_list = models.TextField()
course_name = models.CharField(max_length=20, choices=COURSE_NAME)
course_block = models.CharField(max_length=10, choices=BLOCK_NUMBER)
group_size = models.IntegerField(default=3)
def __str__(self):
return self.get_course_block_display()
def save(self, *args, **kwargs):
super(Classroom, self).save(*args, **kwargs)
# overrides the default save function to parse the class list
studentList = []
studentList = self.class_list.split('\n')
for line in studentList:
line = line.strip('\r')
s = Student.objects.create(nickname = line, classroom = self)

Updating rows in database using Django RESTAPI and AngularJS

I am trying to make it so that I can POST and update database rows from my angularJS app but I seem to be having trouble adding new entries to my database.
Things are posted without error but when I go and check the database then all added data is "None".
I have written this method to save Notes with a corresponding Lecture ID, where Lecture is an attribute of Notes.
saveNotes: function(notes, lecture_id, callback) {
$http({
method: 'POST',
url: apiRoute + 'notes/',
data: {
"notes": notes,
"lecture_id": lecture_id
}
}).success(callback);
}
I have written these views:
class LectureViewSet(viewsets.ModelViewSet):
serializer_class = LectureSerializer
def get_queryset(self):
course_id = self.request.query_params.get('course',False)
if course_id:
lectures = Lecture.objects.filter(course=course_id)
else:
lectures = Lecture.objects.all()
return lectures
class NotesViewSet(viewsets.ModelViewSet):
queryset = Notes.objects.all()
serializer_class = NotesSerializer
And these serializers:
class LectureSerializer(serializers.ModelSerializer):
class Meta:
model = Lecture
fields = ('id', 'lecture_no', 'title', 'youtubeLink', 'course', 'keywords')
class NotesSerializer(serializers.ModelSerializer):
lecture = LectureSerializer(read_only=True, many=True)
class Meta:
model = Notes
fields = ('id', 'notes', 'lecture')
Can anyone spot the error that is causing this addition of "None" values? Also, is there a way to make these fields update instead of post new ones?
Thanks!
Included models:
class Lecture(models.Model):
lecture_no = models.IntegerField(null=True)
title = models.CharField(max_length=128, unique=True, null=True)
youtubeLink = models.CharField(max_length=128, unique=True, null=True)
course = models.ForeignKey(Course, null=True)
keywords = models.TextField(max_length=300, null=True)
#Could add Next Rerun Date & Time
def __str__(self):
return self.title
class Notes(models.Model):
notes = models.TextField(null=True)
lecture = models.ForeignKey(Lecture, null=True)
def __str__(self):
return str(self.notes)

Resources