I'm getting an error when I try to serialize a many-to-many relationship
The error description that is shown to me in the console is this:
AttributeError: Got AttributeError when attempting to get a value for field produto on serializer Ped_ProSerializer.
The serializer field might be named incorrectly and not match any attribute or key on the Produto instance.
Original exception text was: 'Produto' object has no attribute 'produto'.
The models involved in the relationship are written like this:
class Produto(models.Model):
valor_unitario = models.DecimalField(max_digits=10, decimal_places=2, default=0.00)
nome = models.CharField(max_length=75)
descricao = models.TextField()
genero = models.CharField(max_length=10, default="Indefinido")
qtd_estoque = models.IntegerField()
cor = models.ForeignKey(Cor, on_delete=models.PROTECT, related_name="produtos")
tamanho = models.ForeignKey(
Tamanho, on_delete=models.PROTECT, related_name="produtos"
)
marca = models.ForeignKey(Marca, on_delete=models.PROTECT, related_name="produtos")
class Pedido(models.Model):
endereco_entrega = models.ForeignKey(
Endereco, on_delete=models.PROTECT, null=True, related_name="pedidos"
)
forma_pagamento = models.ForeignKey(
Forma_Pagamento, on_delete=models.PROTECT, null=True, related_name="pedidos"
)
usuario_dono = models.ForeignKey(
get_user_model(), on_delete=models.PROTECT, related_name="pedidos"
)
data_entrega = models.DateField()
data_pedido = models.DateField(default=date.today)
finalizado = models.BooleanField(default=False)
qtd_parcela = models.IntegerField()
valor_parcela = models.DecimalField(max_digits=10, decimal_places=2, default=0.00)
preco_total = models.DecimalField(max_digits=10, decimal_places=2, default=0.00)
itens = models.ManyToManyField(Produto, related_name="pedidos", through="Ped_Pro")
class Ped_Pro(models.Model):
produto = models.ForeignKey(
Produto, on_delete=models.PROTECT, related_name="ped_pros"
)
pedido = models.ForeignKey(
Pedido, on_delete=models.PROTECT, related_name="ped_pros"
)
qtd_produto = models.IntegerField(default=1)
data_entrada = models.DateTimeField(default=datetime.now)
The serializers:
class ProdutoSerializer(ModelSerializer):
class Meta:
model = Produto
fields = "__all__"
class Ped_ProSerializer(ModelSerializer):
class Meta:
model = Ped_Pro
fields = "__all__"
class PedidoSerializer(ModelSerializer):
itens = Ped_ProSerializer(many=True, read_only=True)
class Meta:
model = Pedido
fields = "__all__"
Could you help me find a way to the solution?
Project link on Github
In class ped pro you have 2 times the same related name: ped_pros
Related
Will you help me to figure out why Django raises this error?
SolutionsForLanguagesApp.LanguageLevel: (fields.E336) The model is
used as an in termediate model by
'SolutionsForLanguagesApp.UserProfile.languages', but it does not
have a foreign key to 'UserProfile' or 'Language'.
I'm confused because, as you can see, there is a foreign key to Language in LanguageLevel already:
class LanguageLevel(models.Model):
language = models.ForeignKey(Language)
level = models.ForeignKey(Level)
class Meta:
unique_together = (('level', 'language'),)
Do you know what to do?
EDIT - Added UserProfile:
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='userprofile')
date_of_birth = models.DateField(null=True, blank=True)
telephone = models.CharField(max_length=40, null=True, blank=True)
IBAN = models.CharField(max_length=40, null=True, blank=True)
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
MARITAL_STATUS_CHOICES = (
('single', 'Single'),
('married', 'Married'),
('separated', 'Separated'),
('divorced', 'Divorced'),
('widowed', 'Widowed'),
)
marital_status = models.CharField(max_length=40, choices=MARITAL_STATUS_CHOICES, null=True, blank=True)
HOW_DO_YOU_KNOW_ABOUT_US_CHOICES = (
('coincidence', u'It was coincidence'),
('relative_or_friends', 'From my relatives or friends'),
)
how_do_you_know_about_us = models.CharField(max_length=40, choices=HOW_DO_YOU_KNOW_ABOUT_US_CHOICES, null=True,
blank=True)
# TRANSLATOR ATTRIBUTES
is_translator = models.BooleanField(default=False)
# language_tuples = models.ManyToManyField(LanguageTuple,blank=True)
languages = models.ManyToManyField(Language, through='LanguageLevel')
rating = models.IntegerField(default=0)
number_of_ratings = models.BigIntegerField(default=0)
def __unicode__(self):
return '{} {}'.format(self.user.first_name, self.user.last_name)
def __str__(self):
return '{} {}'.format(self.user.first_name, self.user.last_name)
Your LanguageLevel model is missing a ForeignKey to the UserProfile:
class LanguageLevel(models.Model):
language = models.ForeignKey(Language)
level = models.ForeignKey(Level)
# Add Foreign Key to UserProfile
userprofile = models.ForeignKey(UserProfile)
class Meta:
unique_together = (('level', 'language'),)
Also I'm not sure that the unique_together constraint is what you want - it will mean that only one user can have any one combination of language/level. A more likely constraint would be ('userprofile', 'language') so that a language can only be mapped to a user once.
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)
I followed Dennis Ivy proshop Tutorial He used the same approach as the code is
class ReviewSerializer(serializers.ModelSerializer):
class Meta:
model = Review
fields = '__all__'
class ProductSerializer(serializers.ModelSerializer):
reviews = serializers.SerializerMethodField(read_only=True)
class Meta:
model = Product
fields = '__all__'
def get_reviews(self, obj):
reviews = obj.review_set.all()
serializer = ReviewSerializer(reviews, many=True)
return serializer.data
Now I need a Blog for the eCommerce Project and I created another app named blog and Created the models as
class BlogPost(models.Model):
_id = models.AutoField(primary_key=True, editable=False)
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
title = models.CharField(max_length=200, null=True, blank=True, help_text="Like How To Treat Hypertension etc")
image = models.ImageField(null=True, blank=True,
default='/placeholder.png')
rating = models.DecimalField(
max_digits=7, decimal_places=2, null=True, blank=True)
numReviews = models.IntegerField(null=True, blank=True, default=0)
createdAt = models.DateTimeField(auto_now_add=True)
youtubeVideoLink = models.CharField(max_length=1000, null=True , blank=True)
def __str__(self):
return str(self.createdAt)
class BlogPostReview(models.Model):
blogpost = models.ForeignKey(BlogPost, on_delete=models.SET_NULL, null=True)
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
name = models.CharField(max_length=200, null=True, blank=True)
rating = models.IntegerField(null=True, blank=True, default=0)
comment = models.TextField(null=True, blank=True)
createdAt = models.DateTimeField(auto_now_add=True)
_id = models.AutoField(primary_key=True, editable=False)
def __str__(self):
return str(self.rating)
But when I serialize them via same approach as mentioned above....
class BlogPostReviewSerializer(serializers.ModelSerializer):
class Meta:
model = BlogPostReview
fields = '__all__'
class BlogPostSerializer(serializers.ModelSerializer):
blog_post_reviews = serializers.SerializerMethodField(read_only=True)
class Meta:
model = BlogPost
fields = '__all__'
def get_blog_post_reviews(self, obj):
blog_post_reviews = obj.review_set.all()
serializer = BlogPostReviewSerializer(blog_post_reviews, many=True)
return serializer.data
This error comes
in get_blog_post_reviews
blog_post_reviews = obj.review_set.all()
AttributeError: 'BlogPost' object has no attribute 'review_set'
How to solve this problem or what I'm doing wrong and what need to be fixed. What would be another apporach obv there would be.... And I don't know why Dennis Ivy used review_set in his code. If someone know why we use _set and what are the circumstances please let me know.
The simplest solution is to update your get_blog_post_reviews method:
def get_blog_post_reviews(self, obj):
blog_post_reviews = obj.blogpostreview_set.all() # <- this line has changed
serializer = BlogPostReviewSerializer(blog_post_reviews, many=True)
return serializer.data
The original worked because there was a model named Review, so the automatically created reverse name was review_set. Your model is named BlogPostReview, so the reverse is blogpostreview_set.
More information about reverse relationships in the docs.
i'm trying to post a transaction via django rest framework, however it shows error in django log as below:
IntegrityError at /api/item_trans/
NOT NULL constraint failed: chemstore_itemtransaction.bin_code_id
it has no problem if I post the same data from the Django admin web.
therefore I suppose the problem has happened at DRF
any help is welcome, thank you
models.py
class BinLocation(models.Model):
bin_code = models.CharField(max_length=10, unique=True)
desc = models.CharField(max_length=50)
def __str__(self):
return self.bin_code
class Meta:
indexes = [models.Index(fields=['bin_code'])]
class ItemMaster(models.Model):
item_code = models.CharField(max_length=20, unique=True)
desc = models.CharField(max_length=50)
long_desc = models.CharField(max_length=150, blank=True)
helper_qty = models.DecimalField(max_digits=10, decimal_places=4)
unit = models.CharField(max_length=10, blank=False)
def __str__(self):
return self.item_code
class Meta:
verbose_name = "Item"
verbose_name_plural = "Items"
indexes = [models.Index(fields=['item_code'])]
class ItemTransaction(models.Model):
# trace_code YYMMDDXXXX where XXXX is random generated
trace_code = models.CharField(max_length=20, unique=False)
item_code = models.ForeignKey(
ItemMaster, on_delete=models.CASCADE, related_name='+', blank=False, null=False)
datetime = models.DateTimeField(auto_now=False, auto_now_add=False)
qty = models.DecimalField(max_digits=10, decimal_places=4)
unit = models.CharField(max_length=10, blank=False)
action = models.CharField(
max_length=1, choices=ACTION, blank=False, null=False)
bin_code = models.ForeignKey(
BinLocation, related_name='+', on_delete=models.CASCADE, blank=False, null=False)
remarks = models.TextField(blank=True)
def __str__(self):
return f"{self.trace_code} {self.datetime} {self.item_code} {dict(ACTION)[self.action]} {self.qty} {self.unit} {self.bin_code}"
serializers.py
class ItemMasterSerializer(serializers.ModelSerializer):
class Meta:
model = ItemMaster
fields = '__all__'
class ItemTransactionSerializer(serializers.ModelSerializer):
item_code = serializers.SlugRelatedField(
slug_field='item_code',
read_only=True
)
bin_code = serializers.SlugRelatedField(
slug_field='bin_code',
read_only=True,
allow_null=False
)
class Meta:
model = ItemTransaction
fields = '__all__'
You might need to use 2 fields, one for reading data and the other for creating and updating your data with its source to the main. In your case you could try this:
class ItemTransactionSerializer(serializers.ModelSerializer):
item_code_id = ItemMasterSerializer(read_only=True)
item_code = serializers.PrimaryKeyRelatedField(
queryset=ItemMaster.objects.all(),
write_only=True,
source='item_code_id'
)
bin_code_id = BinLocationSerializer(read_only=True
bin_code = serializers.PrimaryKeyRelatedField(
queryset= BinLocation.objects.all(),
write_only=True,
source='bin_code_id'
)
Since you have null=False in both of your ForeignKeys, DRF expects the corresponding ID. You seem to be getting the error NOT NULL constraint because you are not passing the ID in DRF. So you need to fix that for both bin_code_id and the item_code_id.
this is my code above.
model.py
class Produto(models.Model):
usuario = models.ForeignKey(User, null=True, blank=True)
nome = models.CharField(max_length=255)
descricao = models.TextField(null=True, blank=True, verbose_name="Descrição")
slug = models.SlugField()
class Categoria(MPTTModel):
produto = models.ManyToManyField(Produto, null=True, blank=True)
parent = TreeForeignKey('self', null=True, blank=True, related_name='children',verbose_name="Categoria Pai")
nome = models.CharField(max_length=255)
descricao = models.CharField(max_length=255, null=True, blank=True)
slug = models.SlugField()
ativo = models.BooleanField(default=True)
mostra_menu = models.BooleanField(default=False)
ordem_menu = models.IntegerField(default=0)
admin.py
class CategoriaProdutoInline(admin.TabularInline):
model = Categoria.produto.through
class ProdutoAdmin(admin.ModelAdmin):
list_display = ('__unicode__','sku','descricao_curta', 'preco', 'preco_desconto', 'ativo', 'categorias', 'link')
inlines = [CategoriaProdutoInline, ImagemInLine, TagInLine]
search_fields = ('nome', 'sku', 'categoria__nome')
list_filter = ('preco', 'created_at')
prepopulated_fields = {"slug": ('nome',)}
readonly_fields = ['link']
fields = ('usuario','nome','descricao','ativo','preco','preco_desconto','slug')
Actually, the product update admin looks like this.
Insert Product Admin Page
I´ve tried to use some implementations like TreeNodeChoiceField as seem here but not works