Django CheckboxSelectMultiple widget : render only selected data by default - html

Greeting, I have a manytomany field call user in my model_A model, in my form, how can I display only the list of selected data associated to the model_A by default instead of listing entire entries from the User model in my html page? my intention is to create a setting page where I can remove the user associated to a project
below is my code :
model.py :
class model_A(models.Model):
user = models.ManyToManyField(User, blank=True)
form.py :
class EditForm(forms.ModelForm):
prefix = 'edit_form'
class Meta:
model = model_A
fields = '__all__'
widgets = {'user':forms.CheckboxSelectMultiple}
html :
<div class="field">
{{form.user}}
</div>
Any help is much appreciated thanks

Change user queryset inside __init__ method of EditForm class.
class EditForm(forms.ModelForm):
prefix = 'edit_form'
class Meta:
model = model_A
fields = '__all__'
widgets = {'user':forms.CheckboxSelectMultiple}
def __init__(self, **kwargs):
self.event = kwargs.pop('event')
super().__init__(**kwargs)
# replace dots with your conditions in filter
self.fields['user'].queryset = self.user.filter(...)
UPDATE
List users that are associated with Model_A
self.fields['user'].queryset = self.user.all()

Related

FilterSet for ManyToMany relationship existence

Basic models:
class ModelA(Model):
name = CharField(...)
class ModelB(Model):
model_a = ManyToManyField(ModelA, blank=True)
class ModelBFilter(filters.FilterSet):
unassigned = BooleanFilter(field_name='model_a', lookup_expr='isnull')
class Meta:
model = ModelB
fields = ['unassigned']
How do I filter (with django-filter) to find the ModelB's that do not have a corresponding related model?
It looks to me that what you have should work. Perhaps the fields = ['unassigned'] is unnecessary? According to the documentation you can also negate the filter thusly:
class ModelBFilter(filters.FilterSet):
assigned = BooleanFilter(field_name='model_a', lookup_expr='isnull', exclude=True)
class Meta:
model = ModelB

How do I populate my form fields with data from the database Django

Hello I have a form page and I only need users to fill in certain fields, with the rest of the fields being pre-filled for them based on the module they pick.
While I can fetch the objects from my database -- i.e. the dropdown list shows Module Object (1), Module Object (2) -- I need only certain fields in these objects, which is why this similar sounding post couldn't answer my question:
Populate a django form with data from database in view
Here's my forms.py
class inputClassInformation(forms.Form):
module = forms.ModelChoiceField(queryset=Module.objects.all())
duration = forms.CharField(disabled=True, required=False)
description = forms.CharField()
assigned_professors = forms.ModelChoiceField(queryset=Class.objects.filter(id='assigned_professors'))
models.py -- not the full models are shown to reduce the post's length
class Module(models.Model):
subject = models.CharField(max_length=200, default="")
class Class(models.Model):
module = models.ForeignKey(Module, on_delete=models.CASCADE, default="")
duration = models.CharField(max_length=200, default="")
description = models.CharField(max_length=200, default="")
assigned_professors = models.CharField(max_length=200, default="")
So an expected result would be:
1) The Module field shows the subjects, instead of Module objects in its dropdown list and
2) The duration field is automatically filled in for the user, based on the module they picked. The reason is so that the user only has to manually fill in certain fields, while the rest are automatically generated.
This has had me stuck for a long while, help is appreciated. Thanks!
So an expected result would be:
1) The Module field shows the subjects, instead of Module objects in its dropdown list and
2) The duration field is automatically filled in for the user.
These are essentially two different questions.
To answer the first: you can override the:
__str__ method for your Model class for python 3 and django 1.8) and the
__unicode__ method for your Model class for django <1.8 and not python3.
For example, to make subjects appear instead of "XXXX Object" for your class do:
class Module(models.Model):
subject = models.CharField(max_length=200, default="")
def __unicode__(self):
return self.subject
Similarly, change __unicode__ for __str__ as appropriate for your django version.
Now, to answer your second question:
2) The duration field is automatically filled in for the user.
You need to do two things:
Do not display the duration field in your form (unless you want to give the users the chance to sometimes fill it in manually)
Override the save method
An example:
class Class(models.Model):
module = models.ForeignKey(Module, on_delete=models.CASCADE, default="")
duration = models.CharField(max_length=200, default="")
description = models.CharField(max_length=200, default="")
assigned_professors = models.CharField(max_length=200, default="")
def save(self, *args, **kwargs):
self.duration = #The value you'd want to automatically set here#
super(Model, self).save(*args, **kwargs)

How to do an update method for a nested django rest framework APi Boolean ? [OnetoOneField]

So i have been researching about how to update the nested serializer with onetoonefield. However it has not been able to solve my problem. As i am still new to django rest framework, i am still inexperience about what is the problem as i never done an API before.
models.py
class Membership(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
membership = models.BooleanField(default=False)
serializers.py
class MembershipSerializer(serializers.ModelSerializer):
class Meta:
model = Membership
fields = ('membership',)
class UserSerializer(serializers.ModelSerializer):
membership = MembershipSerializer(many=False)
class Meta:
model = User
fields = ('id', 'username', 'email', 'password', 'first_name', 'last_name', 'is_staff', 'membership',)
read_only_fields = ('id',)
def create(self, validated_data):
membership_data = validated_data.pop('membership')
user = User.objects.create(**validated_data)
Membership.objects.create(user=user, **membership_data)
return user
def update(self, instance, validated_data):
instance.username = validated_data.get('username', instance.username)
instance.email = validated_data.get('email', instance.email)
instance.password = validated_data.get('password', instance.password)
instance.first_name = validated_data.get('first_name', instance.first_name)
instance.last_name = validated_data.get('last_name', instance.last_name)
instance.is_staff = validated_data.get('is_staff', instance.is_staff)
instance.save()
membership_data = validated_data.get('membership')
membership_id = membership_data.get('id', None)
if membership_id:
membership_item = Membership.objects.get(id=membership_id, membership=instance)
membership_item.membership = membership_data.get('membership', membership_item.name)
membership_item.user = membership_data.get('user', membership_item.user)
membership_item.save()
return instance
views.py
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all().order_by('-date_joined')
serializer_class = UserSerializer
permission_classes = [IsAuthenticated]
def get_permissions(self):
# allow non-authenticated user to create
return (AllowAny() if self.request.method == 'POST'
else permissions.IsStaffOrTargetUser()),
screenshot of api
https://i.imgur.com/dDqthRu.png
As you can see above, my membership is null, i have no idea why so i tested with is_staff to check and it is using false like a normal Booleanfield. This has make me wonder what is wrong with my models for the membership boolean field.
Main problem
As i am using a boolean field, i was trying to get the user membership to be updated. So i try to use PUT method and the result is nothing has change after i check the membership box and click on PUT.
And if i just want to update the username, i have to check on the membership box else it will give me this:
https://i.imgur.com/KpzHIsE.png
I have been checking online for several solution and none of them has work for me with the update method. I am also puzzle by the null value in the api for the booleanfield membership.

depth = 1 doesn't work properly and it's saves Null in ManyToManyField and ForeignKey fields in Django Rest Framework

after adding depth = 1 doesn't work properly
=> models.py file
class State(models.Model):
state_name = models.CharField(max_length = 30, unique=True)
def __unicode__(self):
return str(self.state_name)
class City(models.Model):
state = models.ForeignKey(State, related_name='state_city')
city_name = models.CharField(max_length = 30)
def __unicode__(self):
return str(self.city_name)
class Meta:
ordering = ('city_name',)
unique_together = ('state', 'city_name',)
class Snippet(models.Model):
created = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=100, blank=True, default='')
code = models.TextField()
linenos = models.BooleanField(default=False)
owner = models.ForeignKey('auth.User', related_name='snippets')
state = models.ForeignKey(State,blank=True,null=True)
city = models.ManyToManyField(City)
=> serializers.py file
class StateSerializer(serializers.ModelSerializer):
class Meta:
model = State
class CitySerializer(serializers.ModelSerializer):
state_name = serializers.CharField(source='state.state_name', read_only=True)
class Meta:
model = City
class SnippetSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username', read_only=True)
class Meta:
model = Snippet
fields = ('id', 'title', 'code', 'linenos', 'owner', 'state', 'city')
depth = 1
I have added ForeignKey and ManyToManyField fields in state and city respectively. It doesn't save values in SnippetSerializer while added depth = 1 in Meta Class (it saves Null value in state and city fields). When I add depth = 1 JSON showing related fields as it should be but it doesn't work properly while add new Snippet. Without depth = 1 it works fine.
I have complex database where tables has many ManyToMany and ForeignKey related fields. Please give me suggestion so I can get related data in JSON.
I have djangorestframework-3.1.2 version. I have used latest version too but same problem. please give me solution and thanks in advance.
I faced the same problem and managed to solve it. Since the problem is with the depth, I just change the depth value in the init method.
class SnippetSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username', read_only=True)
class Meta:
model = Snippet
fields = ('id', 'title', 'code', 'linenos', 'owner', 'state', 'city')
depth = 1
def __init__(self, *args, **kwargs):
super(SnippetSerializer, self).__init__(*args, **kwargs)
request = self.context.get('request')
if request and request.method=='POST':
self.Meta.depth = 0
else:
self.Meta.depth = 1
In the code above, I changed the depth dynamically according to what type of request that I made.
But, this is the workaround that I found myself, I'm not sure if this is the best practice but it solve the problem with just little modification.
depth is only for representation (http://www.django-rest-framework.org/api-guide/serializers/#specifying-nested-serialization). If you want to create/update the related fields too you have to overwrite the create/update methods in the serializer (http://www.django-rest-framework.org/api-guide/relations/#writable-nested-serializers).
Greetings.

Django form performance

I asked this in Code Review but it was rejected with a cause of "broken code." That is why I'm asking it here. This site is probably more appropriate for this question than the Code Review one.
In my app, a user can modify a course that they created. One field is a "teacher" field and the user can select a different person to be the teacher. This ForeignKey creates 138 duplicated queries and I can't figure out how to make it more efficient.
Model:
class CourseCatalog(models.Model):
course_name = models.CharField(verbose_name="Course name", max_length=50)
course_desc = models.TextField(verbose_name="Course Description")
teacher = models.ForeignKey(Teacher, blank=True, null=True,
verbose_name='Course Owner', on_delete=models.PROTECT)
...
View:
class EditCourseCatalog(UpdateView):
model = CourseCatalog
fields = ['course_name','course_desc', 'teacher']
template_name = 'school/course_catalog/new_edit_form.html'
Template:
...
<h3>Course Form</h3>
{{ user.teacher }}
<form action="" method="post">{% csrf_token %}
{{form|crispy}}
...
Here is the query from debug that is duplicated 138 times. The only difference between the queries is the school_familymember.id = 220.
SELECT `school_familymember`.`id`, `school_familymember`.`password`,
school_familymember.last_login, school_familymember.is_superuser,
school_familymember.username, school_familymember.first_name,
school_familymember.last_name, school_familymember.email.school_familymember.is_staff, school_familymember.is_active, school_familymember.date_joined, school_familymember.family_id, school_familymember.middle_name, school_familymember.family_member_role_id, school_familymember.address1, school_familymember.address2, school_familymember.city, school_familymember.state, school_familymember.zip_code, school_familymember.notes, school_familymember.gender, school_familymember.phone_number, school_familymember.cell_phone_number FROM school_familymember WHERE school_familymember.id = 220
The Teacher model is also a foreign key to the FamilyMember table and this is where I think I'm having the issue. I'm wondering if there is a way to make one single query to collect the family names and ids and then use that for the drop down list in the form. Can I do this with the built in form managers or do I have to scrap that and create the queries in the view and pass them to the form?
class Teacher(models.Model):
family_member = models.OneToOneField(FamilyMember, verbose_name='name')
notes = models.TextField(blank=True)
Create a custom model form, and in the __init__ method change the teachers queryset to use select_related to be more efficient.
class CourseCatalogForm(forms.ModelForm):
class Meta:
fields = ['course_name','course_desc', 'teacher']
def __init__(self, *args, **kwargs):
super(CourseCatalogForm, self).__init__(*args, **kwargs)
self.fields['teacher'].queryset = self.fields['teacher'].queryset.select_related('family_member')
Then use your new model form class in your view instead of specifying fields.
class EditCourseCatalog(UpdateView):
model = CourseCatalog
template_name = 'school/course_catalog/new_edit_form.html'
form_class = CourseCatalogForm