How can I set values on to a ManyToManyField which specifies an intermediary model?
In the models.py
class BookUser(models.Model):
email = models.EmailField()
class Book(models.Model):
author_id= models.CharField(max_length=255)
send_to = models.ManyToManyField(BookUser, through='BookUserRelationship')
book_id = models.AutoField(primary_key=True)
file_size = models.CharField(null=True)
class BookUserRelationship(models.Model):
book = models.ForeignKey(Book, on_delete=models.CASCADE)
user = models.ForeignKey(BookUser, on_delete=models.CASCADE)
shared_date = models.DateTimeField(auto_now_add=True,null=True,blank=True)
Tried to update in serializers.py
class BookSerializer(serializers.ModelSerializer):
send_to = BookUserSerializer(many=True, read_only=True)
class Meta():
model = Book
fields = ('book_id', 'author_id','file_size','send_to')
class BookUserSerializer(serializers.ModelSerializer):
model = BookUser
fields = ('email')
In the views.py for listing the books by passing the book_id as query params
class BookListView(generics.ListCreateAPIView):
serializer_class = serializers.BookSerializer
def get(self, request, *args, **kwargs):
user = self.request.user
book_id = self.request.query_params.get('book_id', None)
if book_id:
book = models.Book.objects.filter(book_id=book_id)
return Response(serializers.BookSerializer(book[0]).data)
You don't need to do anything at all. You have already set the relevant data in your for loop, by creating the BookUserRelationship instances. That is the many-to-many relationship; you should just remove the instance.send_to.set(emails) line.
Related
Let us imagine that I have two models.
First model contains curse details and user that created this course
class Course(models.Model):
course_name = models.CharField(max_length=100, null=False)
description = models.CharField(max_length=255)
user_profile = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
and my second model is:
class Lesson(models.Model):
course = models.OneToOneField(Course, on_delete=models.CASCADE) #
# inside the course I want my APIVIEW to list only the courses that current user created.
# OnetoOne relationship does not solve the problem.
status = models.CharField(choices=STATUS, null=False, default=GOZLEMEDE,max_length=20)
tariffs = models.FloatField(max_length=5,null=False,default=0.00)
continues_off = models.CharField(max_length=2)
user_profile = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
My serializers for both Models:
class LessonSerializer(serializers.ModelSerializer):
class Meta:
model = models.Lesson
fields = ('course', 'status', 'tariffs', 'continues_off', 'user_profile')
def create(self, validated_data):
lesson = models.Lesson.objects.create(
course = validated_data['course'],
status = validated_data['status'],
tariffs=validated_data['tariffs'],
continues_off=validated_data['continues_off'],
user_profile=validated_data['user_profile']
)
return lesson
class CourseSerializer(serializers.ModelSerializer):
"""Serializers Course content"""
class Meta:
model = models.Course
fields = '__all__'
def create(self,validated_data):
course = models.Course.objects.create(
course_name = validated_data['course_name'],
description=validated_data['description'],
user_profile=validated_data['user_profile']
)
return course
My Viewset:
class LessonViewset(viewsets.ModelViewSet):
model = models.Lesson
serializer_class = serializers.LessonSerializer
authentication_classes = (SessionAuthentication,)
permission_classes = (IsAuthenticated,BasePermission,)
def get_queryset(self):
user_current = self.request.user.id
return models.Lesson.objects.filter(user_profile=user_current)
How can I get the desired result. I want to get the courses for the current user and show them as a dropdown list in my API view. Just only the courses that user created should be in the dropdown list not all.
OnetoOne relationship gives all results of course table.
i think change your view code to :
def get_queryset(self,id):
return model.objects.filter(user_profile=id)
#You do not need to call it again when you put the Lesson on the model
\
I have two models:
class Restaurant(models.Model):
adress = models.CharField(max_length=240)
name = models.CharField(max_length=140)
class RestaurantReview(models.Model):
review_author = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
restaurant = models.ForeignKey(Restaurant, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
I use DRF and front-end I need the values of the fields to use in Vue.je templates. Here is my serializer:
class RestaurantReviewSerializer(serializers.ModelSerializer):
restaurant_name = serializers.CharField(source='restaurant.name')
restaurant_adress = serializers.CharField(source='restaurant.adress')
created_at = serializers.SerializerMethodField()
review_author = serializers.StringRelatedField(read_only=True)
class Meta:
model = RestaurantReview
fields = ('id','restaurant_name','restaurant_adress','created_at','review_author')
def get_created_at(self, instance):
return instance.created_at.strftime("%d %B, %Y")
I get the right data I need but my problem is now I can't update/create new models. As suggested I added ('read_only'=True) but the result is the same.
Should I use to_representation to get the same CRUD posibilities than with:
class RestaurantReviewSerializer(serializers.ModelSerializer):
class Meta:
model = RestaurantReview
field = fields = '__all__'
But with the benefit to have for exemple 'restaurant' named after its name and not its ID so I can use it in my template?
Follow to comment above.
Use single viewset and override get_serializer_class. No other thing to change.
class RestaurantReviewViewSet(viewsets.ModelViewSet):
queryset = RestaurantReview.objects.all()
def get_serializer_class(self):
if self.request.method == 'GET':
return RestaurantReviewGETSerializer # your above serializer
else:
return RestaurantReviewSerializer # default serializer
The "Brand" object is foreign key of "company",they are ManytoMany relationship,and Brand object exists the field "company_Group"
the models are as follows:
class Brand(models.Model):
Company_Group = models.ManyToManyField(Company)
Brand_Group = models.CharField(u'Brand Group',max_length=255, default="")
Pref_Brand_Name_Flg = models.CharField(u'Preferred Name Flag',max_length=255, default="")
Pref_Brand_Name = models.CharField(u'Preferred Name',max_length=255, default="")
PrimaryContact = models.ForeignKey(UserRole, null=True, blank=True)
class Company(models.Model):
Pref_Company_Name_Flg = models.CharField(u'Preferred Name Flag',max_length=255, default="")
Pref_Company_Name = models.CharField(u'Preferred Name',max_length=255, default="")
Company_Type = models.CharField(u'Company Type',max_length=255, default="")
serializers
class BrandSerializer(serializers.ModelSerializer):
class Meta:
model = Brand
fields = '__all__'
the Serializer as follows ,data_export_setting.Company_form_stand is the field as
class CompanySerializer(serializers.HyperlinkedModelSerializer):
Brand = BrandSerializer(source='brand', read_only=True)
class Meta:
model = Company
Company_form_stand=['id', 'Brand', 'Company_Type','Company_Name','company_Name_SC']
fields = data_export_setting.Company_form_stand
depth = 2
def create(self, validated_data):
return Company.objects.create(**validated_data)
def update(self, instance, validated_data):
instance.__dict__.update(**validated_data)
instance.save()
return instance
the viewset are as follows
class BrandViewSet(viewsets.ModelViewSet):
queryset = Brand.objects.all()
serializer_class = BrandSerializer
model = Brand
def get_serializer(self, *args, **kwargs):
if 'data' in kwargs:
data = kwargs['data']
if isinstance(data, list):
kwargs['many'] = True
return super(BrandViewSet, self).get_serializer(*args, **kwargs)
class CompanyViewSet(viewsets.ModelViewSet):
queryset = Company.objects.all()
serializer_class = CompanySerializer
and I want to show the company objects with Brand objects ,however,it seems to ignore the brand object and its field
appreciate any help ,thanks
Try,
Brand = BrandSerializer(source='brand_set', read_only=True, many=True)
Since, you have defined the field relation as ManyToMany, more than one Brand objects are related to a single Company instance. By using the reverse relation, you can access them in your serializer, and many=True lets the serializer handle multiple objects in the relation.
I am trying to sort out a specific problem that involve "many2many" relationship using through specification.
I've already tried to use inline_factory but I was not able to sort out the problem.
I have these tables
class Person(models.Model):
id = models.AutoField(primary_key=True)
fullname = models.CharField(max_length=200)
nickname = models.CharField(max_length=45, blank=True)
class Meta:
db_table = 'people'
class Role(models.Model):
role = models.CharField(max_length=200)
class Meta:
verbose_name_plural = 'roles'
db_table = 'roles'
class Study(models.Model):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=255)
description = models.CharField(max_length=1000)
members = models.ManyToManyField(Person, through='Studies2People')
class Meta:
db_table = 'studies'
class Studies2People(models.Model):
person = models.ForeignKey(Person)
role = models.ForeignKey(Role)
study = models.ForeignKey(Study)
class Meta:
verbose_name_plural = 'studies2people'
db_table = 'studies2people'
unique_together = (('person', 'role', 'study'),)
#forms.py
from .models import Study, Person, Role, Studies2People
class RegisterStudyForm(ModelForm):
class Meta:
model = Study
fields = '__all__'
#View.py
class StudyCreateView(CreateView):
template_name = 'managements/register_study.html'
model = Study
form_class = RegisterStudyForm
success_url = 'success/'
def get(self, request, *args, **kwargs):
self.object = None
form_class = self.get_form_class()
form = self.get_form(form_class)
return self.render_to_response(self.get_context_data(form=form))
The code above creates a form like:
Study.Title
Study.description
List of People
I want to create a form to fill in all fields that involve Studies2People Something like this:
Study.Title
Study.description
Combo(people.list)
Combo(Role.list)
Maybe I should start from Studies2People but I don't know how to show the "inline" forms involved.
Thanks in advance
C.
waiting someone that is able to explain with some examples the relationship m2m with through (model & view), I sorted out my problem in a different way.
I've created three forms.
1 Model Form (study)
2 Form (forms with ModelChoiceField(queryset=TableX.objects.all())
Created a classView to manage the get and post action.(validation form too)
In the post procedure I used "transaction" to avoid "fake" data.
I hope that someone will post an example with complex m2m relationships.
Regards
Cinzia
I have the following model:
class Article(models.Model):
title = models.CharField()
description = models.TextField()
author = models.ForeignKey(User)
class Rating(models.Model):
value = models.IntegerField(choices=RATING_CHOICES)
additional_note = models.TextField(null=True, blank=True)
from_user = models.ForeignKey(User, related_name='from_user')
to_user = models.ForeignKey(User, related_name='to_user')
rated_article = models.ForeignKey(Article, null=True, blank=True)
dtobject = models.DateTimeField(auto_now_add=True)
Based upon the above model, i have created a model form, as follows:
Model Forms:
class RatingForm(ModelForm):
class Meta:
model = Rating
exclude = ('from_user', 'dtobject')
Excluding from_user because the request.user is the from_user.
The form renders well, but in to_user in the dropdown field, the author can rate himself as well. So i would want the current_user's name to populate in the dropdown field. How do i do it?
Override __init__ to remove current user from the to_user choices.
Update: More Explanation
ForeignKey uses ModelChoiceField whose choices are queryset. So in __init__ you have to remove the current user from to_user's queryset.
Update 2: Example
class RatingForm(ModelForm):
def __init__(self, current_user, *args, **kwargs):
super(RatingForm, self).__init__(*args, **kwargs)
self.fields['to_user'].queryset = self.fields['to_user'].queryset.exclude(id=current_user.id)
class Meta:
model = Rating
exclude = ('from_user', 'dtobject')
Now in the view where you create RatingForm object pass request.user as keyword argument current_user like this.
form = RatingForm(current_user=request.user)