How can I use multiple queryset in a ModelChoiceField? - django

I'm just beginning to learn Django and I would like to use different queryset in a ModelChoiceField.
I have 3 models like that :
class Politic(models.Model):
name = models.CharField(max_length=100)
class Economic(models.Model):
name = models.CharField(max_length=100)
class Category(models.Model):
politic = models.ForeignKey(Politic, blank = True, null = True)
economic = models.ForeignKey(Economic, blank = True, null = True)
And a form like that :
class MyForm(forms.Form):
choice = forms.ChoiceField(choices = (("0", u"---------"), ("1", u"Politic"),
("2", u"Economic")),
required=False)
category = forms.ModelChoiceField(queryset=Economic.objects.all(),
required=False)
In my template, I use Ajax to populate my category field with a list of all Politic or Economic value according to my choice field.
But if I choose "Politic", I have a problem in the validation of my form because the queryset of my category field is Economic.objects.all(), not Politic.objects.all().
How can I change my dynamicaly queryset? Any ideas?

You can have 2 different selects One for politic and one for economic and show/hide them based on choice field.
Or maybe Abstract Model Inheritance would solve your problem

One possibility would be to use a Generic Relation in your Catagory model.

Thanks for your answers, I try to use your two solutions (Abstract Model and Generic Relation) but it doesn't resolve my problem.
So I create two differents ModelChoiceField (one for Politic and one for Economic) and I use hide/show effects of Jquery in my template (like you say Kugel).
But if you have any others ideas for my problem, I'm interessed.

Related

Error saving django model MultipleChoiceField checkbox field

I have a checkbox choice field like this:
models.py
TYPE_CHOICES = (
('s', 'small'),
('m', 'medium'),
('b', 'big'),
)
class Post(models.Model) :
size = models.CharField(blank=True,max_length="3", choices=TYPE_CHOICES)
So in the admin form:
class MainContent(forms.ModelForm):
size = forms.MultipleChoiceField(choices=TYPE_CHOICES, widget=forms.CheckboxSelectMultiple())
class Meta:
model = Post
fields = '__all__'
But when I saving the form it give me this error:
Select a valid choice. ['s', 'm', 'b'] is not one of the available
choices.
So, what is the problem?
UPDATE
My apology, this question was not given enough info, let me explain more.
The reason I want a checkbox input is because I want it able to store multiple values in the single field (one column). Perhaps the data can be serialized (or comma separated),
Since the TYPE_CHOICES is static and will not changed in the future, I am not planning to use ManytoMany.
Also I want it able to display in the template easily by the language language.
Hope this is clear enough.
Presumably, you want a single column in a table that is storing
multiple values. This will also force you to think about how to will
serialize - for example, you can't simply do comma separated if you
need to store strings that might contain commas.
However, you are best using a solution like one of the following:
https://pypi.python.org/pypi/django-multiselectfield/
https://pypi.python.org/pypi/django-select-multiple-field/
This answer solve your problem, you are try to store a list of strings, but the charfield.
Link to post
or try use ChoiceField
You're using a CharField in your model but in your form you use MultipleChoiceField, for a ModelForm it's an incompatible type because it wouldn't know what to do if the user chooses more than one option, I would recommend using a catalog and a ManyToManyField:
If you want to select more than one size for a Post model:
models.py
class SizesCatalog(models.Model):
description = models.CharField(max_length=255)
def __str__(self):
return self.description
class Post(models.Model) :
size = models.ManyToMany(SizesCatalog, db_table='post_sizes')
admin form
class MainContent(forms.ModelForm):
class Meta:
model = Post
fields = '__all__'
if you want to select just one size for just one:
models.py
class SizesCatalog(models.Model):
description = models.CharField(max_length=255)
def __str__(self):
return self.description
class Post(models.Model) :
size = models.ManyToMany(SizesCatalog)
admin form
class MainContent(forms.ModelForm):
class Meta:
model = Post
fields = '__all__'
That way you let Django deal with your problems and in a future you could even update your sizes in a better way

django modelform use normal field for relation

I am building a little message system with this model:
class Mail(models.Model):
sender = models.ForeignKey(Character, related_name="+")
to = models.ForeignKey(Character, related_name="+")
sent_at = models.DateTimeField(auto_now_add=True)
subject = models.CharField(max_length=127)
body = models.TextField()
now i made a modelform from this:
class ComposeForm(forms.ModelForm):
class Meta:
model = Mail
exclude = ["folder", "sender", "sent_at"]
however this gives my "to" field a drop down list with all possible characters.
Id like to make this in a normal charfield (later with auto completer) instead of this drop down.
Any idea how i can achieve this?
I've been in a similar place and I found 2 solutions, depending on the needs. The first one is suposing you're going to use something like a select2 and get the query via ajax:
class ComposeForm(forms.ModelForm):
to_char = forms.CharField(max_length=255, required=False) # use the name you want
class Meta:
model = Mail
exclude = ["folder", "sender", "sent_at","to"]
So to_char is empty, and then you manage that field as you want, and when you do the POST, you'll get the value of to_char in the view, and assign to the model where you need it.
The other option I suggest is to use a ModelChoiceField instead of Charfield like this:
class ComposeForm(forms.ModelForm):
to_char = forms.ModelMultipleChoiceField(queryset=Character.objects.all())
class Meta:
model = Mail
exclude = ["folder", "sender", "sent_at","to"]
This will make easier to use an external select tool as select2 (without AJAX)
I choose the first one when the model has thousands of possible choices, so the select hasn't to load all the choices and the page will be fast. I use a select2 in the template over this field, in this case to_char, that loads the options in an AJAX view
I use the second one when there are hundred of choices and using the autocomplete of select2 over this field has no problems, I think if you don't have too many choices this will be the best for you, the ModelChoiceField, you can attach an autocomplete without any trouble
I might have found even a neater solution to this problem. By overriding the default form field in this way:
class ComposeForm(forms.ModelForm):
class Meta:
model = Mail
exclude = ["folder", "sender", "sent_at"]
widgets = {'to': forms.TextInput()}
1) If you do not want to display all the values, then all you need to do is to override to field queryset.
Like:
class ComposeForm(forms.ModelForm):
class Meta:
model = Mail
exclude = ["folder", "sender", "sent_at"]
def __init__(self, *args, **kwargs):
super(ComposeForm, self).__init__(*args, **kwargs)
self.fields['to'].queryset = Character.objects.none()
2) If you want to add autocomplete then you will need view that does the filtering and returns filtered options. You also need some kind of js widget. There are many of those available. On django side you only need to update field widget parameters so your js can pick up the field.

Django forms with odd model relationship

I am working with an existing database that I can not modify and having some trouble trying to deal with presenting forms for modifying the database in Django. The structure in question is as follows and all models are unmanaged.
class Persons(models.Model):
personid = models.BigIntegerField(primary_key=True, db_column='PersonID')
....
class Phones(models.Model):
phoneid = models.BigIntegerField(primary_key=True, db_column='PhoneID')
number = models.CharField(max_length=60, db_column='Number', blank=True)
type = models.CharField(max_length=15, db_column='Type', blank=True)
...
class Personsphones(models.Model):
personphoneid = models.BigIntegerField(primary_key=True, db_column='PersonPhoneID')
personid = models.ForeignKey(Persons, db_column='PersonID')
phoneid = models.ForeignKey(Phones, db_column='PhoneID')
...
I want to create a form to display all of the 'Phones' associated with a particular 'Persons' and in addition be able to modify/add/remove 'Phones' belonging to a 'Persons'. Right now the only thing I can think of is to display the 'Phones' in a modelformset and then if one is added or removed manually set the 'Personsphones' relation. Any ideas on how to best deal with this model setup?
For making changes to your models you may want to use django-south http://south.aeracode.org/docs/
As far as displaying your 'Phone' under your forms.py you may want to set up class meta like so. With this any changes made to models will reflect on change
class Meta:
model = Persons
exclude = ('user')
In models you may want to use Foreignkey fore relationships between phones and Persons. Better seen in action here https://docs.djangoproject.com/en/dev/ref/models/fields/#foreignkey

Django Many to Many through intermediary table form like admin's TabularInline form?

I'd like to have a form to add, edit and delete values for a many to many relationship using a specified intermediary table just like what I can get from Django's admin TabularInline form. Is there a way to do this? I have not found it in Django's documentation.
I have created a form to edit the UserProfile and would like to be able to add, edit and delete the many to many with UserProfile_Language (both language and proficiency). How do I make a form for this? How do I handle this in the view?
My Models are as follows:
class Language(models.Model):
LANGUAGE_ENGLISH = 1
LANGUAGE_FRENCH = 2
LANGUAGE_CHOICES = (
(LANGUAGE_ENGLISH, 'English'),
(LANGUAGE_FRENCH, 'French')
)
language = models.SmallIntegerField(choices=LANGUAGE_CHOICES)
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
languages = models.ManyToManyField(Language, null=True, blank=True, through='UserProfile_Language')
class UserProfile_Language(models.Model):
FLUENT = 1
OK = 2
PROFICIENCY_CHOICES = (
(FLUENT, 'Fluent'),
(OK, 'Okay')
)
userprofile = models.ForeignKey(UserProfile)
language = models.ForeignKey(Language)
proficiency = models.SmallIntegerField(choices=PROFICIENCY_CHOICES)
I assuming the you mean on the front end and not in the admin. I believe that you can do this using a form set. (http://docs.djangoproject.com/en/dev/topics/forms/formsets/). You would create a form for the through table to use in the formset.
Also, you may have simplified your models for posting, but if the language model is really just one choice field, why not just combine language and userprofile_language into one? You can replace the ForeignKey with the choice field and get the same behavior. That would make your display easier. (ignore this is language actually has more fields)

django views - accessing a m2m field in a generic view

I've stumbled upon this issue and my noob brain got fried trying to resolve it. I feel like there's some basic concepts here that I'm missing.
So I have this "Films" model with category choice field and a m2m relationship to a "Directors" model, and I'm trying to write 2 different views, one that returns a list of films filtered by category and one that returns a list of films filtered by director.
The first one is easy, but I just don't know how to get the director model's name field to create the second filter.
So I have this models (i've taken the irrelevant stuff out including the category thing i mentioned above)
class Director(models.Model):
name = models.CharField(max_length=50)
web = models.URLField(blank=True, help_text= "opcional")
class Film(models.Model):
name = models.CharField(max_length=50)
slug = models.SlugField(max_length= 15)
director = models.ManyToManyField(Director, blank=True, help_text= "opcional")
this url
(r'^peliculas/director/(?P<director>\w+)/$', 'filtered_by_director'),
and this view
def filtered_by_director(request,director):
return list_detail.object_list(
request,
queryset = Film.objects.filter(director.name=director),
template_name ='sections/film_list.html',
template_object_name = 'film',
paginate_by = 3
)
The same template is supposed to be used by both views to render the relevant list of objects
The view doesn't like the filter i'm using at the queryset for the m2m field, but I have no clue how to do it really, I've tried whatever I could think of and it gives me a "keyword can't be an expression" error
Any help to this lowly noob will be appreciated.
Line queryset = Film.objects.filter(director.name=director),
needs to read: queryset = Film.objects.filter(director__name=director),
Field lookups are done by __ double underscore syntax:
http://docs.djangoproject.com/en/dev/topics/db/queries/#field-lookups
In your filter, try specifying the director name like (documentation):
filter(director__name=director)