Ordering Choices in ModelForm ManytoManyField DJANGO - django

I have in my models.py
class Business(models.Model):
industry = models.models.ManyToManyField(Industry)
in forms.py
class BusinessForm(forms.ModelForm):
class Meta:
model = Business
When I render the form, the industry names appear in a multiple select box. What do I do to make the industry names in alphabetical order?

There are several ways:
You can override the queryset ordering on a per-form basis, set the ordering meta class option, or override the model manager queryset with an ordering method.
Override global model manager queryset
class IndustryManager(models.Manager):
def get_query_set(self):
return (
super(IndustryManager, self)
.get_query_set()
.order_by('name')
)
class Industry(models.Model):
name = models.CharField(max_length=128)
objects = IndustryManager()
Specify global meta option ordering
class Industry(models.Model):
name = models.CharField(max_length=128)
class Meta:
ordering = ['name']
Per form ordering
class MyForm(forms.ModelForm):
class Meta:
model = Business
def __init__(self, *args, **kwargs):
super(MyForm, self).__init__(*args, **kwargs)
self.fields['industry'].queryset = Industry.objects.order_by('name')
There's also a shortcut called formfield_for_manytomany if you are dealing with the django admin.

I like this method:
class BusinessForm(forms.ModelForm):
class Meta:
model = Business
industry = forms.ModelMultipleChoiceField(
queryset=Industry.objects.order_by('name'))
I like it, since it does not alter the database model, and since it is declarative (less programming).

Related

Create Dynamic Through Model

I have many models with ManyToMany fields.
class Author(Model):
name = CharField()
class Publication(Model):
name = CharField()
authors = ManyToManyField(Author)
class Meta:
abstract = True
class Book(Publication):
pass
class Article(Publication):
pass
class Journal(Publication):
pass
class D(Model):
authors = ManyToManyField(Author)
class E(Model):
authors = ManyToManyField(Author)
I want to add ordering field to all ManyToMany fields.
What is the best way to automatically do this?
Attempt.
# Substitution for ManyToMany
class AuthorField(ManyToManyField):
def __init__(self, **kwargs):
class Relationship(Model):
entity = models.ForeignKey(???????????)
author = models.ForeignKey(Author)
ordering = models.PositiveSmallIntegerField(default=1)
class Meta:
ordering = ('ordering',)
kwargs['to'] = Author
kwargs['through'] = Relationship
super(AuthorField, self).__init__(**kwargs)
I have found a way.
class OrderedManyToManyField(models.ManyToManyField):
def contribute_to_class(self, cls, name, **kwargs):
super(OrderedManyToManyField, self).contribute_to_class(cls, name, **kwargs)
if self.remote_field.through:
self.remote_field.through.add_to_class('ordering', models.PositiveSmallIntegerField(default=1))
self.remote_field.through._meta.ordering = ('ordering', )

How to sort a ChoiceField in a ModelForm?

I have a model that contains a user field.
usr = models.ForeignKey(User, related_name='+', limit_choices_to={'is_active': True})
I have a ModelForm (shown below) that allows the usr to be set: this all works fine. However, the list of users is presented in a random order.
class MyModelForm(forms.ModelForm):
class Meta:
model = MyModel
fields = ['usr', ]
How can I sort the list of active users in the drop down?
One option is to set the ordering for your model. In your form, the model choice field should use the same ordering.
class MyModel(models.Model):
...
class Meta:
ordering = ['username']
If you want a different ordering in your model form, then you can use a ModelChoiceField and order the queryset.
class MyModelForm(forms.ModelForm):
usr = forms.ModelChoiceField(Usr.objects.order_by('username'))
class Meta:
model = MyModel
fields = ['usr', ]
The disadvantage of this is you lose information from the model field (e.g. help_text) unless you duplicate it in the form.
To prevent duplication, you can replace the queryset in the __init__ method.
class MyModelForm(forms.ModelForm):
class Meta:
model = MyModel
fields = ['usr', ]
def __init__(self, *args, **kwargs):
super(MyModelForm, self).__init__(*args, **kwargs)
self.fields['usr'].queryset = self.fields['usr'].queryset.order_by('username')

Create base Django model class for DB-view related models setting all ForeignKey-fields to on_delete=DO_NOTHING

In my Django (1.6+) application, I have many Django models that point to (read only) DB views.
These models also contain foreign key relations.
Now if the Django application tries to delete the related fk-models, this will lead to DB errors ("Cannot delete from view") if I don't set cascade=DO_NOTHING on all foreign key fields.
Example:
class PersonView(models.Model):
person = models.ForeignKey(Person, db_column='fk_person', on_delete=DO_NOTHING)
class Meta:
db_table = 'view_persons'
managed = False
Since all my db-view-model-ForeignKey-fields should have cascade=DO_NOTHING by default, I'd like to create a DB-View model base class which will automatically set all foreign-key-fields to on_delete=DO_NOTHING, so I only need to care for inheriting from this model - otherwise it's easy to forget (and redundant) setting this attribute for all fields.
In the end I want to end up with a code like this:
class ViewModel(models.Model):
class Meta:
abstract = True
def __init__(self, *args, **kwargs):
super(ViewModel, self).__init__(*args, **kwargs)
# How to set all foreign-key fields' on_delete attribute to "DO_NOTHING"?
class PersonView(ViewModel):
# no need to set on_delete anymore
person = models.ForeignKey(Person, db_column='fk_person')
class Meta:
db_table = 'view_persons'
managed = False
How can I alter Django model attributes in my base class to set all foreign key fields to on_delete=DO_NOTHING?
Well, you can monkey-patch models.ForeignKey but the more preferred method is to simply subclass ForeignKey:
class MyForeignKey(models.ForeignKey):
def __init__(self, *args, **kwargs):
super(MyForeignKey, self).__init__(*args, **kwargs)
self.on_delete = models.DO_NOTHING
Then you can use MyForeignKey instead of ForeignKey in your models.

Django - Feeding only part of Foreignkey in models

i'm new to django and as a exercise I want to make "home expenses".
I've already did simple model and form :
(from models)
#models.py
#these are the type (groceries/clothes/etc. )
class TypWydatku(models.Model):
typ_wydatku = models.CharField(max_length=25)
data_wpisu=models.DateField(auto_now_add=True)
#these are the actual input with dates/prices/etc
class Wpisy(models.Model):
data_zakupu=models.DateField(default=timezone.now())
data_wpisu=models.DateField(auto_now=True)
typ_wydatku=models.ForeignKey(TypWydatku)
kwota=models.FloatField('kwota')
uwagi=models.CharField(max_length=255, blank=True)
But now I would like to add another model, which will describe expenses connected to my car more specific. So I add another TypWydatku - Moto with id=3
Next step is to create new model with extra fields (mileage/ fuel tanked):
#models.py
(...)
class WpisyMoto(models.Model):
wpis=models.ForeignKey(Wpisy)
przebieg=models.IntegerField()
uwagi=models.CharField(max_length=200)
litry=models.FloatField()
#and more
I have the sipmlest forms as one can have rigth now :
# forms.py
class TypWydatkuForm(ModelForm):
class Meta:
model = TypWydatku
fields = '__all__'
class WpisyForm(ModelForm):
class Meta:
model = Wpisy
fields = '__all__'
class WpisyMotoForm(ModelForm):
class Meta:
model = WpisyMoto
fields = '__all__'
I would like to have choice field 'wpis' in the template, where i want to see onlythose which have 'typ_wydatku'=3. How should I do it ?
From the docs for the ModelChoiceField field (which is the form field type Django will use to represent the ForeignKey field), this can be achieved by setting the form field's queryset attribute:
class WpisyMotoForm(ModelForm):
class Meta:
model = WpisyMoto
fields = '__all__'
def __init__(self, *args, **kwargs):
super(WpisyMotoForm, self).__init__(*args, **kwargs)
self.fields["wpis"].queryset = Wpisy.objects.filter(typ_wydatku__pk=3)

How to order the results of a ForeignKey relationship in a Django form?

I have this models in Django
class Country(models.Model):
name = models.CharField(max_length=80)
class Person(models.Model):
first_name = models.CharField(max_length=100, db_index=True)
last_name = models.CharField(max_length=100, db_index=True)
country = models.ForeignKey(Country)
and this ModelForm
class PersonForm(forms.ModelForm):
class Meta:
model = Person
when I use this form in a template, everything works fine, but the country list in the <select> appears disordered. How can I order it?
You can use the ordering property:
class Country(models.Model):
name = models.CharField(max_length=80)
class Meta:
ordering = ["name"]
If you set the ordering to the Country class, it shall display them as you want.
If you can't or don't want to use the ordering attribute in class Meta of model, you also can do this:
You need make a Form object, something like:
from django import forms
class PersonForm(forms.ModelForm):
country = forms.ModelChoiceField(queryset=Country.objects.all().order_by('name'))
class Meta:
model = Person
field types for formsmodels
There's 2 good answers here, but I wanted to retain help_text, blank, and other settings from the model without having to repeat them and also not change the default ordering on the model. Here's what I did:
class PersonForm(forms.ModelForm):
class Meta:
model = Person
def __init__(self, *args, **kwargs):
super(PersonForm, self).__init__(*args, **kwargs)
self.fields['country'].queryset = self.fields['country'].queryset.order_by('name')
Essentially I just updated the queryset on the automatically added field to order the way I wanted.
try adding this into class Meta, inside class Person:
ordering = ['country']
http://docs.djangoproject.com/en/dev/ref/models/options/#ordering
In view.py
First: you create the form
form = YourForm(request.POST)
Later your set the query:
form.fields['country '].queryset = YourDBTable.objects.all().order_by('Your_Attr')