Django many to many field add with through model fields - django

I have the models below, and I want to add a member to a group in a view. How could I do this, also adding the date_joined and invite_reason correctly. I am using forms without the generics views.
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=128)
def __str__(self):
return self.name
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership')
def __str__(self):
return self.name
class Membership(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)

To create the reltationship you have to base your form on the relationship model:
class MembershipForm(ModelForm):
class Meta:
fields = ['person', 'group', 'date_joined']
model = Membership
This form will be composed of a select for the persons, a select for the group and a datefield for the date_joined

Related

How to display all child category from parent category in django-rest-framework

I'm trying to show my all children category from parent category. I want to just hit one API end and show all tables which is related to that item. I want to hit "Master-Category" and show all releated "Category","Sub-Category" and "Root-Item" in Hierarchy form. I display all the data but cannot in Hierarchy form. Can anyone please give me the solution for this problem.
Model.py
from django.db import models
from django.contrib.auth.models import User
class MasterCategory(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True,
verbose_name="Created By")
title = models.CharField(max_length=100, null=False, blank=False)
description = models.TextField(default='')
def __str__(self):
return str(self.title)
#property
def category(self):
data = NewCategory.objects.filter(master_category__id=self.id).values
return data
#property
def sub_category(self):
data = NewSubcategory.objects.filter(category__id=self.id).values
return data
#property
def root_item(self):
data = Rootitem.objects.filter(sub_category__id=self.id).values
return data
class NewCategory(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True,
verbose_name="Created By")
title = models.CharField(max_length=100, null=False, blank=False)
description = models.TextField(default="")
master_category = models.ForeignKey(
MasterCategory, on_delete=models.CASCADE, null=True, blank=True)
def __str__(self):
return str(self.title)
class NewSubcategory(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True,
verbose_name="Created By")
title = models.CharField(max_length=100, null=False, blank=False)
description = models.TextField(default="")
category = models.ForeignKey(NewCategory, on_delete=models.CASCADE, null=True,
blank=True)
def __str__(self):
return str(self.title)
class Rootitem(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True,
verbose_name="Created By")
title = models.CharField(max_length=100, null=False, blank=False)
description = models.TextField(default="")
sub_category = models.ForeignKey(NewSubcategory, on_delete=models.CASCADE,
null=True, blank=True)
def __str__(self):
return str(self.title)
Serializers.py
I add #property function name in MasterCategorySerializer fields, "category", "sub_category", "root_item"
from .models import MasterCategory, NewCategory, NewSubcategory, Rootitem
from rest_framework import serializers
class MasterCategorySerializer(serializers.ModelSerializer):
class Meta:
model = MasterCategory
fields = ["title", 'category', 'sub_category', 'root_item']
class NewCategorySerializer(serializers.ModelSerializer):
class Meta:
model = NewCategory
fields = "__all__"
class NewSubcategorySerializer(serializers.ModelSerializer):
new_cat = NewCategorySerializer(source='category',read_only=True, many=True)
class Meta:
model = NewSubcategory
fields = "__all__"
class RootitemSerializer(serializers.ModelSerializer):
class Meta:
model = Rootitem
fields = "__all__"
**Viewset.py**
from API_app.models import MasterCategory
from API_app.serializers import MasterCategorySerializer
from rest_framework import viewsets
class MasterCategoryViewSet(viewsets.ModelViewSet):
queryset = MasterCategory.objects.all()
serializer_class = MasterCategorySerializer
My Desired Output, what i want.
{
Electronics <---- Master-Category
{
Smart-Phone <---- Category
{
Samsung <---- Sub-Category
{
Samsung S20 Ultra <---- Root-Item
}
}
}
}
Change your serializers as below. For this nested structure you don't need properties. As tables are connected with foreign key you can define related name between models and assign to its serializer. Default related name between table is tablename_set.
class RootitemSerializer(serializers.ModelSerializer):
class Meta:
model = Rootitem
fields = "__all__"
class NewSubcategorySerializer(serializers.ModelSerializer):
rootitem_set = RootitemSerializer(many=True)
class Meta:
model = NewSubcategory
fields = "__all__"
class NewCategorySerializer(serializers.ModelSerializer):
newsubcategory_set = NewSubcategorySerializer(many=True)
class Meta:
model = NewCategory
fields = "__all__"
class MasterCategorySerializer(serializers.ModelSerializer):
newcategory_set = NewCategorySerializer(many=True)
class Meta:
model = MasterCategory
fields = "__all__"
We have relationship between MasterCategory and NewCategory. As you don't define related_name therefore related name is newcategory_set and its response is NewCategorySeralizer. Make many=True because they are related with foreign key as there can be multiple newcategory related to mastercategory. Other relations are same as above explanation.
If you want to change this default related name then look at related_name, you can define it inside models.ForeignKey()

Django one parent and two children relationship

I am new in Django and Django-Rest-framework. I am following one Youtube Tutorial. He used static Django Template but I want to use React as my frontend. So I have create multiple api endpoints. In this particular Youtube episode I am stuck to display what kind of products specific customer bought. Short summary of my project is: I have four models: order, customer, product and tags(Product and tags have many to many relationships). In the order model I have two foreign key one is product and another one is customer. This is my order models [Looks like]. I don't know how to query and display what kind of products specific customer(by using id) bought.
This is my models
from __future__ import unicode_literals
from django.db import models
class Tag(models.Model):
name= models.CharField(max_length=200, null=True)
def __str__(self):
return self.name
class Product(models.Model):
CATEGORY=(
('Indoor', 'Indoor'),
('Outdoor', 'Outdoor'),
)
name= models.CharField(max_length=200, null=True)
price= models.FloatField(null=True)
category=models.CharField(max_length=200,null=True, choices=CATEGORY)
description= models.CharField(max_length=200,null=True, blank= True)
date_created=models.DateTimeField(auto_now_add=True, null=True)
tags= models.ManyToManyField(Tag)
def __str__(self):
return self.name
class Customer(models.Model):
name = models.CharField(max_length=200, null= True)
email = models.CharField(max_length=20, null=True)
phone = models.CharField(max_length=20, null=True)
date_created= models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
class Order(models.Model):
STATUS =(
('Pending', 'Pending'),
('Out of delivery', 'Out of delivery'),
('Delivered', 'Delivered'),
)
status= models.CharField(max_length=200, null=True,choices= STATUS)
date_created=models.DateTimeField(auto_now_add=True, null=True)
customer= models.ForeignKey(Customer, null= True, on_delete= models.SET_NULL)
product= models.ForeignKey(Product, null= True, on_delete= models.SET_NULL)
This is serializes
from rest_framework import serializers
from .models import *
class TagSerializer(serializers.ModelSerializer):
class Meta:
model = Tag
fields = ["name"]
class ProductSerializer(serializers.ModelSerializer):
tags = TagSerializer(many=True)
class Meta:
model = Product
fields = '__all__'
class CustomerSerializer(serializers.ModelSerializer):
products: ProductSerializer(many=True)
class Meta:
model = Customer
fields = '__all__'
class OrderSerializer(serializers.ModelSerializer):
customer = CustomerSerializer()
product = ProductSerializer()
class Meta:
model = Order
fields = '__all__'
class CustomerSerializer(serializers.ModelSerializer):
products: ProductSerializer(many=True)
orders: OrderSerializer(many=True)
class Meta:
model = Customer
fields = '__all__'

Django - Models category error in Admin: “Select a valid choice. That choice is not one of the available choices”

So I am trying to build a recipe field in django-admin. I have a Model category called Meals and I have categories to chose from on the admin page but as soon as I try to save my entry, I get the Select a valid choice. Breakfast is not one of the available choices & prevents me from saving anything.
I've tried moving the daily_meals value from Recipe Field into Meal Category and uncommenting the first meal and commenting the second value in Recipe Field.
How do I create new meals in the meals category, just like the food category, while already having pre-saved meals in the list?
Meal categories
admin error after save
Here is my code:
Models.py
from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone
# Food Category
class Category(models.Model):
name = models.CharField(max_length=250)
slug = models.SlugField(max_length=250, unique=True)
class Meta:
ordering = ('name',)
verbose_name = 'category'
verbose_name_plural = 'categories'
def __str__(self):
return self.name
# Meal Category
class Meal(models.Model):
name = models.CharField(max_length=250)
slug = models.SlugField(max_length=250, unique=True)
class Meta:
ordering = ('name',)
verbose_name = 'meal'
verbose_name_plural = 'meals'
def __str__(self):
return self.name
# Recipe Field
class Recipe(models.Model):
title = models.CharField(max_length=200)
category = models.ForeignKey(Category, on_delete=models.CASCADE,)
daily_meals = (
('Breakfast','Breakfast'),
('Brunch','Brunch'),
('Elevenses','Elevenses'),
('Lunch','Lunch'),
('Tea','Tea'),
('Supper','Supper'),
('Dinner','Dinner'),
)
# meal = models.CharField(max_length=100, choices = daily_meals)
meal = models.ForeignKey(Meal, choices = daily_meals, on_delete=models.CASCADE,)
ingredients = models.TextField(blank=True)
directions = models.TextField(blank=True)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.title
Admin.py
from django.contrib import admin
from .models import Recipe, Category, Meal
class CategoryAdmin(admin.ModelAdmin):
list_display = ('name', 'slug')
prepopulated_fields = {'slug': ('name',)}
admin.site.register(Category, CategoryAdmin)
class MealAdmin(admin.ModelAdmin):
list_display = ('name', 'slug')
prepopulated_fields = {'slug': ('name',)}
admin.site.register(Meal, MealAdmin)
class RecipeAdmin(admin.ModelAdmin):
readonly_fields = ('created',)
admin.site.register(Recipe, RecipeAdmin)
ForeignKey fields do not typically use choices. The choices are generated from what is in the database. If you construct choices yourself, choice[0] must be a valid primary key of the Meal table. That being said, you can use the limit_choices_to parameter if you want restrict the choices to certain instances:
daily_meals = ['Breakfast', 'Brunch', 'Elevenses', 'Lunch', 'Tea', 'Supper', 'Dinner']
# ...
meal = models.ForeignKey(Meal, limit_choices_to={'name__in': daily_meals}, on_delete=models.CASCADE,)

Create multiple related objects in Django Admin

I am using Django 2.0
I have two models
class Chapter(models.Model):
course = models.ForeignKey(Course, on_delete=models.CASCADE)
name = models.CharField(max_length=250, blank=False)
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
class META:
verbose_name_plural = 'chapters'
db_table = 'chapters'
def __str__(self):
return self.name
class ChapterQuestion(models.Model):
chapter = models.ForeignKey(Chapter, on_delete=models.CASCADE)
word = models.CharField(max_length=250)
definition = models.CharField(max_length=250)
class META:
verbose_name_plural = 'chapter questions'
db_table = 'chapter_questions'
def __str__(self):
return self.word
Since Each ChapterQuestion belongs to only one Chapter, I think it could be Many-to-one relation.
My admin.py contain only
admin.site.register(Chapter)
admin.site.register(ChapterQuestion)
I want to be able to add/edit multiple questions while creating/editing chapter using Django Admin.
But Django Admin is showing only chapter fields
Also, I want created_by column to be field automatically by logged in user and remove from form.
You need to use inline forms
class ChapterQuestionInline(admin.StackedInline):
model = ChapterQuestion
#admin.register(Chapter)
class ChapterAdmin(admin.ModelAdmin):
list_display = ["course","name","created_by"]
inlines = [ChapterQuestionInline]

Access intermediary model values Django

I have a simple question. using the example from django above. How can i get for example the invite_reason from Person on a Group ? or all joined dates to all groups from that person ? thanks.
class Person(models.Model):
name = models.CharField(max_length=128)
def __unicode__(self):
return self.name
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership')
def __unicode__(self):
return self.name
class Membership(models.Model):
person = models.ForeignKey(Person)
group = models.ForeignKey(Group)
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)
You'll need to query your Membership model for that, like so:
memberships = Membership.objects.filter(person=person, group=group)
for membership in memberships:
membership.invite_reason
Alternately, you could query it based on the relation:
memberships = person.membership_set.filter(group=group)
for membership in memberships:
membership.invite_reason