Django: How to create object which has ManyToManyField in shell? - django

I think that showing code is much easier than explanation.
models.py
class Product(TimeStampedModel):
name = models.CharField(max_length=120, unique=True)
slug = models.SlugField(null=True, blank=True)
description = models.TextField(max_length=400, blank=True)
is_active = models.BooleanField(default=True)
place_category = models.ForeignKey(
"PlaceCategory",
related_name="products_by_place", # category.products_by_place.all()
)
subject_category_set = models.ManyToManyField(
"SubjectCategory",
related_name="products_by_subject", # category.products_by_subject.all()
)
objects = ProductManager()
class Meta:
ordering = ('-created',)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse(
"products:product_detail",
kwargs={
"slug": self.slug,
}
)
class Category(TimeStampedModel):
name = models.CharField(max_length=25, unique=True)
is_active = models.BooleanField(default=True)
class Meta:
abstract = True
def __str__(self):
return self.name
class PlaceCategory(Category):
class Meta:
verbose_name = "Place Category"
verbose_name_plural = "Place Categories"
class SubjectCategory(Category):
class Meta:
verbose_name = "Subject Category"
verbose_name_plural = "Subject Categories"
This is what I'm trying to do in shell.
# place category
self.place_category = PlaceCategory.objects.create(name="학교")
# subject category
self.subject_category1 = SubjectCategory.objects.create(name="사람")
self.subject_category2 = SubjectCategory.objects.create(name="꽃병")
# product
self.product = Product.objects.create(
name="product name1",
place_category=self.place_category,
subject_category_set=(
self.subject_category1,
self.subject_category2,
)
)
But it doesn't work. Any idea?
What I could think of is moving ManyToManyField from Product to SubjectCategory.
But I want know as in my code. Thanks.

You need to add subject category to your product.
So do it like this:
# place category
self.place_category = PlaceCategory.objects.create(name="학교")
# subject category
self.subject_category1 = SubjectCategory.objects.create(name="사람")
self.subject_category2 = SubjectCategory.objects.create(name="꽃병")
# product
self.product = Product.objects.create(
name="product name1",
place_category=self.place_category,
)
self.product.subject_category_set.add(self.subject_category1)
self.product.subject_category_set.add(self.subject_category2)
or you can make something like this
list_of_subject_categories = [self.subject_category1, self.subject_category2]
self.product.subject_category_set.add(*list_of_subject_categories)

Related

django slick report and nested categories

I am using in django the following models.py:
class Expense(models.Model):
name = models.CharField(max_length=50)
date = models.DateField(unique=False, blank=False)
slug = models.SlugField(unique=True, null=True, default='')
price = models.DecimalField(default=0.0, blank=True, max_digits = 20, decimal_places = 2)
category = models.ForeignKey(
'Category',
related_name="Expense",
on_delete=models.CASCADE
)
account = models.ForeignKey(Account, on_delete=models.CASCADE, verbose_name=u"Account", help_text=u"account")
def __str__(self):
return '{},{},{}'.format(self.name, self.date, self.price)
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
super(Expense,self).save(*args, **kwargs)
def get_absolute_url(self):
return self.slug
class Category(MPTTModel):
name = models.CharField(max_length=200)
slug = models.SlugField(unique=True, null=True, default='')
parent = TreeForeignKey(
'self',
blank=True,
null=True,
related_name='child',
on_delete=models.CASCADE
)
class Meta:
unique_together = ('slug', 'parent',)
verbose_name_plural = "categories"
def __str__(self):
full_path = [self.name]
k = self.parent
while k is not None:
full_path.append(k.name)
k = k.parent
return ' -> '.join(full_path[::-1])
The TreeForeignKey allows me to define nested categories, such as Home -> Electricity and so on.
I am using the following Slick Report view.py:
class TotalExpenses(SlickReportView):
report_model = Expense
date_field = 'date'
group_by = 'category'
columns = ['name', SlickReportField.create(method=Sum, field='price', name='price__sum', verbose_name=('Total category $'))]
charts_settings = [
{
'type': 'bar',
'data_source': 'price__sum',
'title_source': 'name',
},
]
It works but I would like to sum only level 1 categories. Do you know how this might be possible?

get() returned more than one Designated -- it returned 4

I am a student who is learning Django. You tried to insert the designated_code on Views.py, but the following error occurs: I don't know how to solve it at all. How can we solve this?
The element.designed_code part of join_create seems to be the problem.
I'd be really happy if you could help me solve the problem. I know that there are 4 products in the designated code, but I want to add the designated code that corresponds to the value of the selected value code.
Error:
get() returned more than one Designated -- it returned 4!
Models.py
class Value(models.Model):
value_code = models.AutoField(primary_key=True)
option_code = models.ForeignKey(Option, on_delete=models.CASCADE, db_column='option_code')
product_code = models.ForeignKey(Product, on_delete=models.CASCADE, db_column='product_code')
name = models.CharField(max_length=32)
extra_cost = models.IntegerField()
def __str__(self):
return self.name
class Meta:
ordering = ['value_code']
class Designated(models.Model):
designated_code = models.AutoField(primary_key=True)
product_code = models.ForeignKey(Product, on_delete=models.CASCADE, db_column='product_code')
price = models.IntegerField()
rep_price = models.BooleanField(default=True)
class Meta:
ordering = ['designated_code']
def __str__(self):
return str(self.designated_code)
class Element(models.Model):
element_code = models.AutoField(primary_key=True)
designated_code = models.ForeignKey(Designated, on_delete=models.CASCADE, db_column='designated_code')
value_code = models.ForeignKey(Value, on_delete=models.CASCADE, db_column='value_code', null=True, blank=True)
class Meta:
ordering = ['element_code']
def __str__(self):
return str(self.element_code)
class Join(models.Model):
join_code = models.AutoField(primary_key=True)
username = models.ForeignKey(Member, on_delete=models.CASCADE, db_column='username')
product_code = models.ForeignKey(Product, on_delete=models.CASCADE, db_column='product_code')
part_date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return str(self.join_code)
class Meta:
ordering = ['join_code']
Views.py
def join_create(request, id):
current_category = None
designated = Designated.objects.all()
designated_object = Designated.objects.filter(rep_price='True')
value_p = Value.extra_cost
element = Element.objects.all()
value_object = Value.objects.all()
categories = Category.objects.all()
products = Product.objects.all()
if not request.user.is_authenticated:
return HttpResponseRedirect(reverse('zeronine:login'))
if request.method == "POST":
product = Product.objects.get(product_code=id)
join = Join()
join.product_code = product
join.username = request.user
join.save()
if request.method == "POST":
form = ElementForm(request.POST)
if form.is_valid():
for value_code2 in request.POST.getlist('value_code2'):
element = Element()
element.designated_code = Designated.objects.get(product_code=id)
element.value_code = get_object_or_404(Value, pk=value_code2)
element.save()
else:
element = Element()
element.designated_code = Designated.objects.get(product_code=id)
element.value_code = None
element.save()
Forms.py
class ElementForm(forms.Form):
value_code2 = forms.ModelChoiceField(error_messages={'required': "옵션을 선택하세요."}, label="옵션", queryset=Value.objects.all())

Django ORM Count Without Duplicate Column

I have a table called Reading History. I want to find the average number of reads in this table. I wrote the following method for this, but I can't get the right result. Records are made in the table once (student-book records with the same values). When the same record comes, the counter value is increased by one.
For example, suppose that two different students read two different books. I expect total reads / 2 but the result I get is total reads / 4 because there are 4 rows in the table. How can I calculate this? For example, if a student reads 4 different books once, the average will be 1, but the average should be 4.
I tried to use distinct and values but I couldn't get the result I wanted. Maybe I didn't manage to use it correctly. Also I tried to use Avg. When avg didn't give the correct result, I tried to break it down and get the values myself. Normally, Avg was written in Sum.
Serializer
class ClassReadingHistoryReportSerializer(ModelSerializer):
instructor = InstructorForClassSerializer(source="instructor.user")
students = StudenListReadingHistoryReportSerializer(many=True,
source="student_list_class")
avg_read_book = serializers.SerializerMethodField()
class Meta:
model = Class
exclude = [
"created_at",
"updated_at",
"school",
]
def get_avg_read_book(self, obj):
sum_read_book = Class.objects.filter(id = obj.id).aggregate(sum_read=Sum('student_list_class__child__child_reading_history__counter'))
count_child_record = Class.objects.filter(id = obj.id).aggregate(count_child=Count('student_list_class__child__child_reading_history'))
return None
Models
class ChildProfile(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
primary_key=True,
verbose_name=AccountStrings.ChildProfileStrings.user_verbose_name,
related_name="user_child")
city = models.ForeignKey(
"country.City",
on_delete=models.SET_NULL,
null=True,
blank=True,
verbose_name=AccountStrings.ChildProfileStrings.city_verbose_name,
related_name="city_child_profiles")
hobbies = models.CharField(
max_length=500,
null=True,
blank=True,
verbose_name=AccountStrings.ChildProfileStrings.hobbies_verbose_name)
class Meta:
verbose_name = AccountStrings.ChildProfileStrings.meta_verbose_name
verbose_name_plural = AccountStrings.ChildProfileStrings.meta_verbose_name_plural
#property
def get_full_name(self):
return f"{self.user.first_name} {self.user.last_name}"
def __str__(self):
return self.get_full_name
def clean(self) -> None:
"""
This method will check if the user type is a child during creation.
"""
if self.user.user_type != 2:
raise ValidationError(AccountStrings.ChildProfileStrings.user_type_error)
class School(AbstractSchoolBaseModel):
city = models.ForeignKey(
"country.City",
on_delete=models.DO_NOTHING,
related_name="city_schools",
verbose_name=SchoolStrings.SchoolStrings.city_verbose_name)
name = models.CharField(
max_length=250,
verbose_name=SchoolStrings.SchoolStrings.name_verbose_name)
address = models.CharField(
max_length=250,
verbose_name=SchoolStrings.SchoolStrings.address_verbose_name)
website = models.CharField(
max_length=250,
verbose_name=SchoolStrings.SchoolStrings.website_verbose_name)
class Meta:
verbose_name = SchoolStrings.SchoolStrings.meta_verbose_name
verbose_name_plural = SchoolStrings.SchoolStrings.meta_verbose_name_plural
def __str__(self):
return self.name
class Class(AbstractSchoolBaseModel):
school = models.ForeignKey(
"school.School",
on_delete=models.CASCADE,
related_name="classes_school",
verbose_name=SchoolStrings.ClassStrings.school_verbose_name)
instructor = models.ForeignKey(
"account.InstructorProfile",
on_delete=models.CASCADE,
related_name="instructors_school",
verbose_name=SchoolStrings.ClassStrings.instructor_verbose_name)
name = models.CharField(
max_length=50,
verbose_name=SchoolStrings.ClassStrings.name_verbose_name)
grade = models.IntegerField(
verbose_name=SchoolStrings.ClassStrings.grade_verbose_name)
class Meta:
verbose_name = SchoolStrings.ClassStrings.meta_verbose_name
verbose_name_plural = SchoolStrings.ClassStrings.meta_verbose_name_plural
ordering = ["name", "grade"]
def __str__(self):
return f"{self.school.name} - {self.name} - Grade: {self.grade}"
def clean(self) -> None:
"""
This method checks whether the teacher trying to be assigned to the class is working in that school.
"""
if self.instructor.school != self.school:
raise ValidationError(SchoolStrings.ClassStrings.instructor_not_working_at_this_school_error)
class StudentList(AbstractSchoolBaseModel):
school_class = models.ForeignKey(
"school.Class",
on_delete=models.CASCADE,
related_name="student_list_class",
verbose_name=SchoolStrings.StudentListStrings.school_class_verbose_name
)
child = models.ForeignKey(
"account.ChildProfile",
on_delete=models.CASCADE,
related_name="student_list_children",
verbose_name=SchoolStrings.StudentListStrings.child_verbose_name)
class Meta:
verbose_name = SchoolStrings.StudentListStrings.meta_verbose_name
verbose_name_plural = SchoolStrings.StudentListStrings.meta_verbose_name_plural
def __str__(self):
return f"{self.school_class.name} : {self.child.user.first_name} {self.child.user.last_name}"
def clean(self) -> None:
result = StudentList.objects.filter(school_class = self.school_class, child = self.child)
if not self.pk and result.exists():
raise ValidationError(SchoolStrings.StudentListStrings.child_already_added_to_this_class_error)
class ReadingHistory(AbstractBookBaseModel):
IS_FINISHED = ((False,
BookStrings.ReadingHistoryStrings.is_finished_false),
(True, BookStrings.ReadingHistoryStrings.is_finished_true))
book = models.ForeignKey(
"book.Book",
on_delete=models.CASCADE,
related_name="book_reading_history",
verbose_name=BookStrings.ReadingHistoryStrings.book_verbose_name)
child = models.ForeignKey(
"account.ChildProfile",
on_delete=models.CASCADE,
related_name="child_reading_history",
verbose_name=BookStrings.ReadingHistoryStrings.child_verbose_name)
is_finished = models.BooleanField(
choices=IS_FINISHED,
verbose_name=BookStrings.ReadingHistoryStrings.is_finished_verbose_name
)
counter = models.PositiveIntegerField(
verbose_name=BookStrings.ReadingHistoryStrings.counter_verbose_name,
default=0)
class Meta:
verbose_name = BookStrings.ReadingHistoryStrings.meta_verbose_name
verbose_name_plural = BookStrings.ReadingHistoryStrings.meta_verbose_name_plural
def __str__(self):
return f"{self.child.user.first_name} {self.child.user.last_name} - \"{self.book.name}\" "
def clean(self) -> None:
result = ReadingHistory.objects.filter(child=self.child,
book=self.book)
if not self.pk and result.exists():
raise ValidationError(
BookStrings.ReadingHistoryStrings.exists_error)
I forgot to add the counter column in the BookReadingHistory table to the diagram. Diagram and Table data are shown in the images below.
Table
Diagram

Get a list of all the field values from a Foreign Key Table in Django

am new to Django and currently trying the Foreign Key concept. I have three models as shown below.
class Basket(models.Model):
basket_name = models.CharField(max_length=5, unique=True)
def __str__(self):
return self.basket_name
class Product(models.Model):
Grams = 'GM'
Kilograms = 'KG'
WeightBased = 'WPG'
QuantityBased = 'CPG'
PRODUCT_UNIT_WT_CHOICES=[
(Grams, 'Grams'),
(Kilograms, 'Kilograms')
]
PRODUCT_TYPE_CHOICES =[
(WeightBased, 'Weight Based Product'),
(QuantityBased, 'Quantity Based Product')
]
product_name = models.CharField(max_length=30, unique=True)
product_description = models.TextField(max_length=300)
product_price = models.DecimalField(max_digits=5, decimal_places=2)
product_unit_weight = models.DecimalField(max_digits=5, decimal_places=2)
product_unit_weight_units = models.CharField(max_length=2, choices=PRODUCT_UNIT_WT_CHOICES, default=Grams)
product_type = models.CharField(max_length=3, choices=PRODUCT_TYPE_CHOICES, default=QuantityBased)
product_image = models.ImageField(upload_to=imageUploadPath, null=True, blank=True)
def __str__(self):
return self.product_name
class BasketProductMapping(models.Model):
basket_reference = models.ForeignKey(Basket, on_delete=models.CASCADE)
product_reference = models.ForeignKey(Product, on_delete=models.CASCADE)
mapped_basket_name = models.CharField(max_length=5,null=False, blank=False)
mapped_product_name = models.CharField(max_length=30, null=False, blank=False)
Here are my serializers:
class ProductSerializer(serializers.ModelSerializer):
product = serializers.CharField(read_only=True)
class Meta:
model = Product
fields = ['id', 'product_name', 'product_description', 'product_price', 'product_unit_weight',
'product_unit_weight_units', 'product_type', 'product_image']
class BasketSerializer(serializers.ModelSerializer):
basket = serializers.CharField(read_only=True)
class Meta:
model = Basket
fields = ('id', 'basket_name')
class BasketProductMappingSerializer(serializers.ModelSerializer):
basket_reference = serializers.CharField(source ='basket.basket_name', read_only=True)
product_reference = serializers.CharField(source='product.product_name', read_only=True)
class Meta:
model = BasketProductMapping
fields = ['id', 'basket_reference', 'product_reference', 'mapped_basket_name', 'mapped_product_name']
What I am trying to achieve is get a list of all the values in 'basket_name' and 'product_name' when I call the BasketProductMappingSerializer. But the output I am getting is this:
{
"status": 1,
"message": "Basket Product Mapping List",
"data": [
{
"id": 1,
"mapped_basket_name": "A1",
"mapped_product_name": "XYZ"
}
]
}
This is my views.py code:
class BasketProductViewSet(APIView):
def get(self, request):
if request.GET.get('id'):
print('Basket Product Mapping Details')
basketProductMappingData = BasketProductMapping.get(id = request.GET.get('id'))
serializer = BasketProductMappingSerializer(basketProductMappingData)
else:
basketProductMappingData = BasketProductMapping.objects.all().values('id', 'basket_reference__basket_name', 'product_reference__product_name', 'mapped_basket_name', 'mapped_product_name')
serializer = BasketProductMappingSerializer(basketProductMappingData, many=True)
response = {'status':1, 'message':"Basket Product Mapping List", 'data':serializer.data}
Where am I going wrong? Sorry if my question is very trivial. Thanks for your help in advance.
i see that there is an error in your views BasketProductMapping.get(id = request.GET.get('id')) should be BasketProductMapping.objects.get(id = request.GET.get('id'))
i don't know if it gonna work but can you try
basket_reference = serializers.ReadOnlyField(source ='basket.basket_name')
product_reference = serializers.ReadOnlyField(source='product.product_name')
instead of
basket_reference = serializers.CharField(source ='basket.basket_name', read_only=True)
product_reference = serializers.CharField(source='product.product_name', read_only=True)

KeyError Post DjangoRestFramework

I'm new on Django Rest Framework and when I want to POST data I get a error: KeyError: 'id_area' I do not know what I'm doing wrong. Here's my code:
in my models.py
class Area(models.Model):
id_area = models.AutoField(primary_key=True)
APM = 'apm'
BUSINESS = 'business'
DESARROLLO = 'desarrollo'
SISTEMAS = 'sistemas'
ATENTUSIANOS_CHOICES = (
(APM, 'Apm'),
(BUSINESS, 'Business'),
(DESARROLLO, 'Desarrollo'),
(SISTEMAS, 'Sistemas'),
)
nombre = models.CharField(max_length=255, choices=ATENTUSIANOS_CHOICES)
class Meta:
verbose_name = 'Área'
verbose_name_plural = 'Áreas'
def __str__(self):
return self.nombre
class Atentusiano(models.Model):
id_atentusiano = models.AutoField(primary_key=True)
nombre = models.CharField(max_length=255, blank=False, null=False)
apellido = models.CharField(max_length=255, blank=False, null=False)
correo = models.CharField(max_length=255, blank=False, null=False, unique=True)
anexo = models.CharField(max_length=255, blank=True, null=True)
area = models.ForeignKey(Area, related_name='areas', on_delete=models.CASCADE)
class Meta:
verbose_name = 'Atentusiano'
verbose_name_plural = 'Atentusianos'
ordering = ['nombre']
def __str__(self):
return self.nombre + ' ' + self.apellido
in my serializers.py
class AreaSerializer(serializers.ModelSerializer):
areas = serializers.CharField(read_only=True)
class Meta:
model = Area
fields = ('id_area', 'nombre', 'areas')
class AtentusianoSerializer(serializers.ModelSerializer):
atentusianos = serializers.CharField(read_only=True)
area = serializers.CharField(source='area.nombre', read_only=True)
id_area = serializers.CharField(source='area.id_area')
class Meta:
model = Atentusiano
fields = ['id_atentusiano', 'nombre', 'apellido', 'correo', 'anexo', 'id_area', 'area', 'atentusianos']
def create(self, validated_data):
area_data = validated_data.pop('id_area')
area = models.Area.objects.create(**area_data)
atentusiano = models.Atentusiano.objects.create(area=area, **validated_data)
return atentusiano
And in my views.py
class AtentusianoView(viewsets.ModelViewSet):
queryset = Atentusiano.objects.all()
serializer_class = AtentusianoSerializer
class AreaView(viewsets.ModelViewSet):
queryset = Area.objects.all()
serializer_class = AreaSerializer
The problem is that when I want to Post data, for example:
{
"nombre": "name",
"apellido": "lastname",
"correo": "email#gmail.com",
"anexo": "1364",
"id_area": "1"
}
i got this error area_data = validated_data.pop('id_area')
KeyError: 'id_area'
I need help please
you should pop like this,
class AtentusianoSerializer(serializers.ModelSerializer):
.....
.....
class Meta:
model = Atentusiano
fields = ['id_atentusiano', 'nombre', 'apellido', 'correo', 'anexo', 'id_area', 'area', 'atentusianos']
def create(self, validated_data):
id_area = validated_data.pop('area')['id_area'] # here the correction
area = Area.objects.create(id_area=id_area) # an additional correction
atentusiano = Atentusiano.objects.create(area=area, **validated_data)
return atentusiano
EDIT: As id_area value, you are passing a string instead of an integer which will through another error. Also not,
area = models.Area.objects.create(**area_data)
it should be,
area = Area.objects.create(id_area=id_area)