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
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
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]
}
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
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)
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)