How to exclude some values in MultipleChoiceField Django - python

This is my model:
class MyModel(models.Model):
my_field = models.ManyToManyField(AnotherModel)
This is my view:
class MyModelView(UpdateView):
model = MyModel
Is it possible to exclude some values from multiple choice list in my view?
For example:
There are 10 positions in table AnotherModel but when updating MyModel I want only 5 values possible to choose.

You can use limit_choices_to argument to ManyToManyField.
It works exactly similar to limit_choices_to argument in ForeignKey. You can check out examples given in in ForeignKey documentation.

Related

How to check if ManyToMany field is not empty?

How do I check if there are any ManyToMany field objects related to my model object?
For example, I have a model:
class Category(models.Model):
related_categories = models.ManyToManyField('self', blank=True)
I want to do something only if there are related objects existing:
if example_category.related_categories:
do_something()
I tried to do example_category.related_categories, example_category.related_categories.all(), example_category.related_categories.all().exists(), example_category.related_categories.count(), but none of these works for me.
I have no any additional conditions to filter by.
Is there any easy way to check emptiness of this field?
you should use the .exists method:
related_categories = example_category.related_categories
if related_categories.exists():
# do something

How to set related_name in ManyToMany field in an abstract model?

I have this abstract model:
class HasSystemMessage(models.Model):
class Meta:
abstract = True
messages = models.ManyToManyField(SystemMessage, related_name=?)
I am going to use this abstract model in at least three other models, lets say, A, B, and C. How can I set the related_name dynamically for these classes? for example, for class B, I want the related_name to be Bs. Is it possible to do so?
To further clarify the question, The classes will look like this:
class B(HasSystemMessage):
# Some model fields
class A(HasSystemMessage):
# Some model fields
HasSystemMessage.objects.filter(a__contains=[some elements])
You can use %(class)s or %(app_label)s
class HasSystemMessage(models.Model):
class Meta:
abstract = True
messages = models.ManyToManyField(SystemMessage, related_name=%(app_label)s_%(class)s_related)
From Django docs
Be careful with related_name and related_query_nameĀ¶ If you are using
related_name or related_query_name on a ForeignKey or ManyToManyField,
you must always specify a unique reverse name and query name for the
field. This would normally cause a problem in abstract base classes,
since the fields on this class are included into each of the child
classes, with exactly the same values for the attributes (including
related_name and related_query_name) each time.
To work around this problem, when you are using related_name or
related_query_name in an abstract base class (only), part of the value
should contain '%(app_label)s' and '%(class)s'.
'%(class)s' is replaced by the lower-cased name of the child class
that the field is used in. '%(app_label)s' is replaced by the
lower-cased name of the app the child class is contained within. Each
installed application name must be unique and the model class names
within each app must also be unique, therefore the resulting name will
end up being different.
Ref: https://docs.djangoproject.com/en/2.0/topics/db/models/#be-careful-with-related-name-and-related-query-name
You Just need to put a string in this attribute which specifies the name of the reverse relation from the SystemMessage.Also read in Django Docs
Try this:
class HasSystemMessage(models.Model):
class Meta:
abstract = True
messages = models.ManyToManyField(SystemMessage, related_name='system_message')

Django form exclude options in select field

I have one model that has a ManyToMany Field (let's call it "Options") with another Model
When I create the ModelForm it displays all options.
Is there any way to exclude some option values or to show only some of them?
Here is an example:
models.py
class Options (model.Models):
name = ...
...
class Anything (model.Models):
...
options = ManyToManyField(Options)
values of "Options" in my DB:
["OK",
"OK_2",
"NOT_OK",
"OK_3,
"NOT_OK_2"]
Let's say that I need to show ONLY the "OK" values and hide or not to show the "NOT_OK" values.
Is there any way to do this with ModelForms?
You certainly can filter the queryset for a foreign key field or m2m on the related model by using a Form or more commonly a ModelForm.
The reason doing this at form level is useful is because that filtering could well be based on business logic which is not applicable in all cases and so allows more flexibility than defining it against the model for example.
While you can do this while defining the form fields it is best to do it once the form has been constructed and so it takes place at runtime and not compile time (I have just experienced a few interesting occasions where this has caused me some issues, however that was an earlier version of Django!)
The following ModelForm would do the job:
class AnythingForm(ModelForm):
options = forms.MultipleChoiceField()
def __init__(self, **kwargs):
super(AnythingForm, self).__init__(self, **kwargs)
self.fields['options'].queryset = Option.objects.filter({pass in your filters here...})
class Meta:
model = Anything
You can pass the limit_choices_to parameter to your ManyToMany field:
from django.db.models import Q
class Anything (models.Model):
options = models.ManyToManyField(Options,
limit_choices_to=Q(name__startswith='OK'))
In django 1.7 you can even pass a callable in case if list of choices should be changed dynamically.

Django: add model fields to list_display and display related values per entry

I have the following model definitions, see below.
models.py:
class Userstatus(models.Model):
label = models.CharField(...)
description = models.CharField(...)
class Foo(models.Model):
title = models.CharField(...)
visibility = models.ManyToManyField(Userstatus)
admin.py:
class FooAdmin(ModelAdmin):
list_display = ('id', 'title', )
admin.site.register(Foo, FooAdmin)
In the admin list view of "Foo" via FooAdmin the list_display list should include the "label"s from Userstatus so a column for each label will appear. I could create and call a method that creates the list for list_display.
But then no properties or callables actually exist that would allow me to return let's say a boolean for each label column, based on the visibility-many-to-many field.
What are my options? Should I try to intercept a callable or attribute request to Foo and create a boolean result on the fly? (Hitting the DB too often or making the columns sortable is another problem, but first things first).
Django documentation says ...
ManyToManyField fields aren't supported, because that would entail
executing a separate SQL statement for each row in the table. If you
want to do this nonetheless, give your model a custom method, and add
that method's name to list_display. (See below for more on custom
methods in list_display.)
Are you sure you want Userstatus to be a database table and not just a list of a few statuses that could be accessed through a "choices" tuple?

Django models.Model class member not appearing in model_instance._meta.fields

I have a django.contrib.contenttypes.generic.genericForeignKeyField as a member of my model,
however, it is not appearing when I instantiate the model and then try to get the fields out of the _meta of the object.
e.g:
class A(models.Model):
field2 = models.IntegerField(...)
field1 = generic.genericForeignKeyField()
a = A()
a._meta.fields ---> this does not show field1, but shows field2.
Can someone please tell me why ?
Thanks !
Your are not setting up the generic relation correctly. Read the documentation:
There are three parts to setting up a GenericForeignKey:
Give your model a ForeignKey to ContentType.
Give your model a field that can store a primary-key value from the models you'll be relating to. (For most models, this means an IntegerField or PositiveIntegerField.)
This field must be of the same type as the primary key of the models that will be involved in the generic relation. For example, if you use IntegerField, you won't be able to form a generic relation with a model that uses a CharField as a primary key.
Give your model a GenericForeignKey, and pass it the names of the two fields described above. If these fields are named "content_type" and "object_id", you can omit this -- those are the default field names GenericForeignKey will look for.
In the end, it must be something like:
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
Why would you expect it to? It's not a real field. It's a virtual field that's calculated using the (real) content_type and object_id fields on the model.
You can however see it in a._meta.virtual_fields.

Categories

Resources