Django annotate field with queryset of objects - python

Suppose I have two models:
ModelA and ModelB
How can I annotate a queryset of ModelB with objects from ModelA?
queryset = ModelB.objects.filter(...).annotate(models_a=Subquery(ModelA.objects.filter(...)))
In order to have queryset.models_aas a Queryset of objects ModelA.
Thanks you all!
EDIT:
This are my models:
class Allergen(models.Model):
name = models.CharField(_('Allergen name'), max_length=20, choices=ALLERGENS,
help_text=_('Product allergen. Example: gluten'), unique=True)
def __str__(self):
return self.name
class Meta:
ordering = ['name']
class Product(models.Model):
name = models.CharField(_('Name'), max_length=255, help_text=_('Product name'))
supplier = models.ForeignKey(Supplier, blank=True, null=True, related_name='supplier_products',
on_delete=models.CASCADE)
allergens = models.ManyToManyField(Allergen, blank=True, related_name='product_allergens')
unit = models.CharField(_('Unit'), max_length=20, choices=UNITS, default='g')
price = models.FloatField(_('Sale price'), default=0)
unit_price = models.FloatField(_('Unit price'))
class Meta:
ordering = ['name', ]
indexes = [models.Index(fields=['name', 'supplier']), ]
class Recipe(models.Model):
sections = models.ManyToManyField(Section, related_name='recipes', blank=True)
title = models.CharField(_('Recipe title'), max_length=255, help_text=_('Recipe. Example: american chicken salad'),
blank=True)
unit = models.CharField(_('Unit'), max_length=20, choices=UNITS)
user = models.ForeignKey(User, null=True, on_delete=models.CASCADE, related_name='user_recipes')
class Meta:
ordering = ['title']
indexes = [models.Index(fields=['title'])]
class IngredientRecipe(models.Model):
name = models.CharField(_('Name'), max_length=255)
recipe = models.ForeignKey(Recipe, on_delete=models.CASCADE, related_name='ingredients')
products = models.ManyToManyField(Product, related_name='ingredient_products')
quantity = models.FloatField(_('Quantity'))
class Meta:
ordering = ['-id']
unique_together = ('name', 'recipe')
indexes = [models.Index(fields=['name', 'recipe'])]
I'm trying to include the allergens related with the recipe.

If you are working with just one recipe, you can just add a model property that returns the related allergens of the recipe by using the reverse relations like this:
class Recipe(models.Model):
...
#property # or consider using cached_property
def allergens(self):
return Allergen.objects.filter(
product_allergens__ingredient_products__recipe=self,
)
Then you can access the allergens through the instance:
recipe = Recipe.objects.first()
print(recipe.allergens)

Related

How to set Serializer for displaying parent and children as a list DRF?

I'm making an app which is about News
News have an attribute called Category which can be nested
For example:
Human:
--BodyOrgans:
----Hand
Just to make the issue more clear
We need to prepare a way so when making news when we choose Human category,we can access the child which is "BodyOrgan" and when choosing this, accessing "Hand" or other children it might have
This is my models file:
```
class News(models.Model):
PUBLISH_STATUS = (
('P', 'Published'),
('W', 'Waiting for approval'),
('D', 'Draft'),
)
title = models.CharField(max_length=255)
slug = models.SlugField(null=True, blank=True)
sign_image = models.ImageField(upload_to='images', null=True, blank=True)
summary = models.TextField(null=True, blank=True)
description = models.TextField()
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
publish_status = models.CharField(max_length=1, choices=PUBLISH_STATUS, default='D')
publish_time = models.TimeField(null=True, blank=True, default=None)
publish_date = models.DateTimeField(null=True, blank=True, default=None)
author = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
category = models.ManyToManyField('Category')
tag = models.ManyToManyField('Tag')
def __str__(self):
return self.title
class Category(models.Model):
PUBLISH_CHOICES = (
('A', 'Active'),
('I', 'Inactive'),
)
parent = models.ForeignKey('Category', on_delete=models.PROTECT, null=True, blank=True)
name = models.CharField(max_length=50, null=True)
publish_status = models.CharField(max_length=1, choices=PUBLISH_CHOICES, default='A')
description = models.TextField(null=True, blank=True)
tag = models.ManyToManyField('Tag')
def __str__(self):
return self.name
```
And also Serializer:
class CategorySerializer(ModelSerializer):
class Meta:
model = Category
fields = ['name', 'parent']
list = ListSerializer(
fields=['name', 'parent'],
source='get_parent'
)
#staticmethod
def get_parent(obj):
return obj.parent.name
class NewsSerializer(ModelSerializer):
#staticmethod
def get_title_slug(instance):
return slugify(instance.title)
#staticmethod
def get_user(obj):
return obj.author.username
slug = SerializerMethodField(method_name='get_title_slug', read_only=True)
author = SerializerMethodField(method_name='get_user')
class Meta:
model = News
fields = '__all__'
category = CategorySerializer()
read_only_fields = ['author', 'publish_date', 'publish_time']
I'd be greatful if you could help me out _/_
If you are trying to get categories with their children, first use related_name to access children easier:
parent = models.ForeignKey('Category', on_delete=models.PROTECT, null=True, blank=True, related_name="children")
Then you can access a category children via children key.
Now just use a nested serializer:
class CategoryChildrenSerializer(serializer.ModelSerializer):
class Meta:
model = Category
fields = [...]
class CategorySerializer(ModelSerializer):
children = CategoryChildrenSerializer(many=True)
class Meta:
model = Category
fields = [..., "children"]

Django model organization issue

I'm developing recipe and ingredient models.
models.py:
class Recipe(models.Model):
"""Recipe structure"""
author = models.ForeignKey(
User, on_delete=models.CASCADE
)
title = models.CharField(max_length=40, unique=True)
picture = models.ImageField(blank=True, null=True)
text = models.TextField(max_length=100, blank=True, null=True)
components = models.ManyToManyField('Component')
tag = MultiSelectField(max_length=10, choices=tags)
cooking_time = models.IntegerField(
validators=[MinValueValidator(1, 'Value cannot be lower than 1')]
)
slug = models.SlugField()
def __str__(self):
return self.title
class Meta:
db_table = 'recipes'
verbose_name = 'Рецепт'
verbose_name_plural = 'Рецепты'
class Component(models.Model):
"""Component structure"""
title = models.CharField(max_length=50, unique=True)
unit = models.CharField(max_length=10, choices=units)
def __str__(self):
return self.title
class Meta:
db_table = 'components'
verbose_name = 'Ингредиент'
verbose_name_plural = 'Ингредиенты'
class Component_quantity(models.Model):
"""Table linking quantity with recipe and component together"""
recipe = models.ForeignKey(Recipe, on_delete=models.CASCADE)
component = models.ForeignKey(Component, on_delete=models.CASCADE)
quantity = models.DecimalField(
max_digits=5,
decimal_places=1,
verbose_name='Количество',
validators=[MinValueValidator(1)]
)
class Meta:
db_table = 'quantity_and_recipe_linking_table'
unique_together = ('recipe', 'component')
verbose_name = 'Ингредиент в рецепте'
verbose_name_plural = 'Ингредиенты в рецепте'
The problem is to link the recipe and the component in the Component_quantity model so that in the component field it is possible to select only those entities that are specified in the recipe itself. Is it possible to do this?
I would recommend to put the quantity field directly into the Component model. Another way to do it is to add a quantity foreignkey to the Component model and then remove the recipe and component foreignkey from the Component_quantity model.

What relation should i create in models so that one user can create only one comments for Product?

This is my models. What is the best approach?
OneToOneField allows to create only one comments for all time.
class Person(models.Model):
first_name = models.CharField(
max_length=512,
blank=True,
null=True,
)
last_name = models.CharField(
max_length=512,
blank=True,
null=True,
)
class Product(models.Model):
slug = SlugField()
name = NameField()
description = DescriptionField()
class Comment(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
person = models.OneToOneField(Person, on_delete=models.CASCADE)
text = models.TextField(null=True, blank=True)
# You can use 'unique_together' feature of model
class Product(models.Model):
slug = SlugField()
name = NameField()
description = DescriptionField()
class Comment(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
person = models.ForeignKey(Person, on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
text = models.TextField(null=True, blank=True)
class Meta:
unique_together = ("person", "product")
What you want is multiple comments per User, and multiple comments per Product. However, you need to ensure uniqueness for users and products inside comments. This can be achieved using unique_together (see https://docs.djangoproject.com/en/2.2/ref/models/options/#unique-together):
class Comment(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
person = models.ForeignKey(Person, on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
text = models.TextField(null=True, blank=True)
class Meta:
unique_together = ['person', 'product']
I believe you need to add Product to Comment as well:
class Comment(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
person = models.ForeignKey(Person, on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
text = models.TextField(null=True, blank=True)
class Meta:
unique_together = ['person', 'product']

DjangoTables2 Add column from another model

I have DjangoTable for this model:
class Mark(models.Model)
id_mark = models.AutoField(primary_key=True, verbose_name='Id запису')
id_student = models.ForeignKey(Student, blank=False, null=False, default=None, on_delete=models.CASCADE,verbose_name='Студент')
id_subject = models.ForeignKey(Subject, blank=False, null=False, default=None, on_delete=models.CASCADE,verbose_name='Предмет')
mark = models.DecimalField(decimal_places=3, max_digits=5, blank=False, null=False, default=None, verbose_name='Оцінка')
class Meta:
verbose_name = 'Оцінка'
verbose_name_plural = 'Оцінки'
def __str__(self):
return "{} {} {}".format(self.id_student, self.id_subject, self.mark)
Table:
class Mark_Table(tables.Table):
class Meta:
model = Mark
exclude = ('id_mark',)
attrs = {'class': 'paleblue'}
I want to add column with values from this model:
class Subject(models.Model)
id_subject = models.AutoField(primary_key=True, verbose_name='Id предмету')
id_teacher = models.ForeignKey(Teacher, blank=False, null=False, default=None, on_delete=models.CASCADE,verbose_name='Вчитель')
name = models.CharField(max_length=32, blank=False, null=False, default=None, verbose_name='Назва предмету')
class Meta:
verbose_name = 'Предмет'
verbose_name_plural = 'Предмети'
def __str__(self):
return "{}".format(self.name)
Now I have fields Student Subject Mark, I want to add filed id_teacher from another model, and relationship must remain.
You can add foreign key value in table using table.Coulmn() and specifying accessor
like below:
id_teacher = tables.Column(accessor='id_subject.id_teacher')
So your Mark_Table will look like:
class Mark_Table(tables.Table):
# Define all the custom fields here including any override or adding other fields and include it in fields in meta class
id_teacher = tables.Column(accessor='id_subject.id_teacher')
class Meta:
model = Mark
fields = ['mark', 'id_teacher'] # specify all the fields you want to display here
attrs = {'class': 'paleblue'}
Read more about adding custom field at docs

How to sort django list filter by alphanumeric

I have used default django filter but it not show record by sorting i.e alphanumeric
following is my code
class VoteAdminModel(admin.ModelAdmin):
list_filter = ('business__poll__town__parent')
models
class Business(models.Model):
poll = models.ForeignKey('Poll')
business_name = models.CharField(max_length=256, blank=True,null=True)
class Poll(models.Model):
town = models.ForeignKey('Town', verbose_name="Survey")
category = models.ForeignKey(Category)
class Vote(models.Model):
business = models.ForeignKey(Business)
vote_year = models.IntegerField(verbose_name="Year")
gender = models.CharField(max_length=10)
class Town(models.Model):
town_name = models.CharField(max_length=256, verbose_name="Survey")
parent = models.ForeignKey('self', db_column='parent', blank=True, null=True, verbose_name="Survey")

Categories

Resources