selective display of model choices in django - django

In my django application I have a model field called 'status'. In one of the forms to get data for this field, I only want to display a subset of all choices available in the model. Is there a way to remove a choice from a form? I need the removed choice in the database and the admin interface where I can select it.
status = models.CharField(STATUS_FIELD_NAME, choices=STATUS_CHOICES,
default=STATUS_DEFAULT,
max_length=3)

You could define the subset of choices in your form:
class YourForm(forms.ModelForm):
SUBSET_CHOICES = (
(YourModel.CHOICE_ONE, _('First choice')),
(YourModel.CHOICE_TWO, _('Second choice')),
)
class Meta:
model = YourModel
fields = ['choice', ]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['choice'].choices = self.SUBSET_CHOICES

Related

Filtering Many-to-many field in Rest Framework

Im working with the Django REST Framwork and got some issues with the Browsable api. I cannot filter a ManyToMany field so that it only shows the objects which the user is owner of.
I do manage to filter the the user and filter out m own objects.
In the serializer I have
class BidSerializer(serializers.HyperlinkedModelSerializer):
id = serializers.HyperlinkedRelatedField(view_name='bid-detail', read_only=True)
def __init__(self, *args, **kwargs):
super(BidSerializer, self).__init__(*args, **kwargs)
request_user = self.context['request'].user
self.fields['my_items'].queryset = Item.objects.filter(owner=request_user)
print(self.fields['my_items'].queryset)
self.fields['others_items'].queryset = Item.objects.exclude(owner=request_user)
self.fields['user'].queryset = User.objects.filter(username=request_user)
class Meta:
model = Bid
fields = ('id','comment','user','others_items','my_items','timestamp')
The strange thing is that the fields 'user' and 'others_items' are filtered as supposed. While 'my_items' is not filtered but showing all items. However the line containing the print statement shows a correct output. The difference between the fields is that my_items is a ManyToMany field and others_items is a foreign key.
Should it be possible to filter as I like? If not why and how could I filter my choices in a better way?
I ran into this same issue and after inspecting one of my many-to-many fields in my debugger I discovered the child_relation property on the many-to-many field which had a queryset property. Adding child_relation property in front of the queryset worked for me.
I'm also using version 3.8.2 of the Django Rest Framework.
Example:
class BidSerializer(serializers.HyperlinkedModelSerializer):
id = serializers.HyperlinkedRelatedField(view_name='bid-detail', read_only=True)
def __init__(self, *args, **kwargs):
super(BidSerializer, self).__init__(*args, **kwargs)
request_user = self.context['request'].user
self.fields['my_items'].child_relation.queryset = Item.objects.filter(owner=request_user)
self.fields['others_items'].child_relation.queryset = Item.objects.exclude(owner=request_user)
self.fields['user'].queryset = User.objects.filter(username=request_user)
class Meta:
model = Bid
fields = ('id', 'comment', 'user', 'others_items', 'my_items', 'timestamp')

Django ModelForm not storing foreignkey in modeladmin

I have the following code which is supposed to create a MyConfig object. However, it doesn't as the app_model is always returned as None.
The idea is to choose from a select few contenttypes and then add a key, and the resulting config will trigger a bunch of services. However whenever I save the form, the contenttype stored in the app_model is always None, which is clearly undesirable.
This is in Django1.8
Here is the admin:
class ContentTypeModelChoiceField(ModelChoiceField):
def label_from_instance(self, obj):
return "{}-{}".format(obj.app_label, obj.model)
class MyConfigForm(ModelForm):
class Meta:
model = models.MyConfig
fields = '__all__'
def __init__(self, *args, **kwargs):
super(MyConfigForm, self).__init__(*args, **kwargs)
self.fields['app_model'].label = "App Name"
app_model = ContentTypeModelChoiceField(
ContentType.objects.filter(
app_label__startswith='myApp',
model="myModel",
),
empty_label="Choose a model",
)
class MyConfigAdmin(admin.ModelAdmin):
model = models.MyConfig
form = MyConfigForm
list_display = (<display fields>
)
search_fields = (<search fields>
)
excluded_fields = ('app_model')
And here is the model itself:
class MyConfig(models.Model):
app_model = models.ForeignKey(ContentType, null=True)
ref_key = models.CharField(max_length=32, null=True)
To unfortunately somewhat have my tail between my legs. The missing code was the excluded_fields which contained app_model. I thought this removed it from the displayed fields, but it actually removes it from the data you save into the model upon save.
Thanks to everyone who looked into this. Many apologies.

modelformset_factory: display more fields for specific instances

I'm using a modelformset_factory to edit multiple instances of Product in the same form:
ProductFormSet = modelformset_factory(Product, fields=('code', 'state'))
form_products = ProductFormSet()
It works well.
But now I need to display an additional field of the Product model in the form but only for a specific instance of Product. I'm not sure if it can be done in a simple manner in Django. Is it possible to do so using a modelformset_factory?
You can specify the form in the modelformset_factory, so create a model form (in forms.py if you have one) override the __init__method to add extra fields.
I would move the fields from the formsetfactory arguments to the form
in forms.py (assuming you have one)
class ProductForm(forms.ModelForm):
model = Product
def __init__(self, *args, **kwargs):
super(ProductForm, self).__init__(*args, **kwargs)
if 'instance' in kwargs :
product = kwargs['instance']
# to add an extra field, add something like this
self.fields['extra_field'] = forms.CharField(max_length=30)
class Meta:
fields = ('code', 'state')
Then pass that to your modelformset factory with the form argument
ProductFormSet = modelformset_factory(Product, form=ProductForm )
form_products = ProductFormSet()

CBV Django Form View set data for ChoiceField

I'm using the Django Form View and I want to enter custom choices per user to my Choicefield.
How can I do this?
Can I use maybe the get_initial function?
Can I overwrite the field?
When I want to change certain things about a form such as the label text, adding required fields or filtering a list of choices etc. I follow a pattern where I use a ModelForm and add a few utility methods to it which contain my overriding code (this helps keep __init__ tidy). These methods are then called from __init__ to override the defaults.
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ('country', 'contact_phone', )
def __init__(self, *args, **kwargs):
super(ProfileForm, self).__init__(*args, **kwargs)
self.set_querysets()
self.set_labels()
self.set_required_values()
self.set_initial_values()
def set_querysets(self):
"""Filter ChoiceFields here."""
# only show active countries in the ‘country’ choices list
self.fields["country"].queryset = Country.objects.filter(active=True)
def set_labels(self):
"""Override field labels here."""
pass
def set_required_values(self):
"""Make specific fields mandatory here."""
pass
def set_initial_values(self):
"""Set initial field values here."""
pass
If the ChoiceField is the only thing you're going to be customising, this is all you need:
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ('country', 'contact_phone', )
def __init__(self, *args, **kwargs):
super(ProfileForm, self).__init__(*args, **kwargs)
# only show active countries in the ‘country’ choices list
self.fields["country"].queryset = Country.objects.filter(active=True)
You can then make your FormView use this form with like this:
class ProfileFormView(FormView):
template_name = "profile.html"
form_class = ProfileForm

Add multiple records at once in django admin panel

I have following setup.
from django.db import models
from django.contrib.auth.models import User
class Event(models.Model):
name = models.CharField(max_length=64)
date = models.DateField()
ATTENDANCE_CHOICES = (
('A','Attending'),
('N','Absent'),
('L','Taken ill'),
)
class Attendance(models.Model):
student = models.ForeignKey(User)
event = models.ForeignKey(Event)
status = models.CharField(max_length=1, choices=ATTENDANCE_CHOICES)
In a nutshell: Students(User) attend or doesn't attend classes(Event), this is registered by Attendance.
Problem is adding those attendance records one at a time.
What I am looking for is a way to provide form for each class(each Event object) with list of all students and attendance status radio buttons or drop downs next to them.
Something like this:
http://i.imgur.com/jANIZ.png
I have looked at many discussions about multiple/bulk record insertion via django admin and am beginning to wonder is this even possible with django admin or do I have to create such form from scratch? Either way, what would be the best (most django-ish) approach?
"Is this even possible?" It's possible right out of the box.
Look into the django Admin app, Inlines, ModelForms, and the RadioSelect widget.
class MyForm(forms.ModelForm):
class Meta:
model = Attendance
def __init__(self, *args, **kwargs):
super(MyForm, self).__init__(*args, **kwargs
self.fields['status'].widget = forms.RadioSelect(choices=self.fields['status'].choices)
class AttendanceInline(admin.TabularInline):
model = Attendance
form = MyForm
class EventAdmin(admin.ModelAdmin):
inlines = [AttendanceInline]
def save_model(self, request, obj, form, change):
obj.save()
for user in User.objects.all():
obj.attendance_set.create(user=user, status='')
# you should consider a null field or a possible choice for "Undecided"
admin.site.register(Event, EventAdmin)