Django - ManyToManyField is not shown in Form - python

I've defined language_tuples = models.ManyToManyField(LanguageTuple) in my UserProfile. This field should be filled when regular user want to became a translator. So he should be able to choose as many as needed tuples of languages - language by language.
EDIT: Thanks to Shang Wang, now I can choose multiple LanguageTuples but I'm not able to create new LanguageTuple objects inside the form.
class Language(models.Model):
shortcut = models.CharField(max_length=40)
name = models.CharField(max_length=40)
def __str__(self):
return self.name
class LanguageTuple(models.Model):
language_from = models.ForeignKey(Language, related_name='language_from', null=True)
language_to = models.ForeignKey(Language, related_name='language_to', null=True)
def __str__(self):
return '{} to {}'.format(self.language_from, self.language_to)
So let's assume that there are multiple Language objects in database already but no instances of LanguageTuple. I want user to be able to built his own tuples (as many as he wants). So if there were languages CZ,EN,GE,SK - he can built for example these tuples: CZ-EN, EN-CZ, GE-CZ, SK-GE etc. - after choosing tuples, those tuples are created inside the database as regular LanguageTuple instances if does not exists.
The problem is that there is no form field inside the form when it is rendered. Don't know what to do with that... as you can see, I've added field - language_tuples into the form.
class TranslatorRegistrationForm(forms.Form):
IBAN = forms.CharField(max_length=40,required=True)
first_name = forms.CharField(max_length=40,required=True)
last_name = forms.CharField(max_length=40,required=True)
class Meta:
model = UserProfile
fields = (
'first_name','last_name','IBAN','language_tuples'
)

One problem I've already mentioned in comment that you need forms.ModelForm for TranslatorRegistrationForm, otherwise django won't recognize all fields you want to display.
If you want user to choose from language_tuples as well as creating new pairs, it's going to be 2 forms. One for your existing form, the other is a form for model LanguageTuple. You need to display both forms in the template, so people could choose either from the list language_tuples or fill out the form for LanguageTuple.
Now be aware that you need some logic in place to detect whether user has chosen an existing language_tuple or trying to use a newly created LanguageTuple. It's some extra steps before you save everything to database but it should be straight forward.

Related

Formset for MainClass<-ForeignKey<-OneToOneField?

I need to process applications to an amateur sports event. An event has several distances/subclasses, each of them has some restrictions (age, etc).
My models are
class Event(models.Model):
title = models.CharField(max_length=255)
# more fields
class Klass(models.Model):
title = models.CharField(max_length=255)
capacity = models.IntegerField()
event = models.ForeignKey('Event', related_name="klasses")
# more fields
class TeamRestrictions(models.Model):
age_min = models.IntegerField()
age_max = models.IntegerField()
klass = models.OneToOneField(TeamRestrictions, related_name='restrict')
# more fields
I want to have a single page where a user creates a new event: names it, adds several subclasses into it and restrictions for every subclass. Well, without this one-to-one relationship, for just Event with several Klasses, I could use FormSet.
Of course, I could move all TeamRestrictions fields to Klass, but that looks ugly for me.
What should I use for this more complex structure?
You should create for each model a form and do it separately or you can create really sofisticated form which will do it for you.
This form then would have fields as title (Event), title (Klass), capacity, event, age_min ... so for the relation fields as ForeignKey you will have to use the ChoiceField which will be populated with choices in the __init__ function and so on. Then it should have good cleaning function so that it would have olny valid data and at the end the save. You will have to look if user has selected a field or is creating a new one (such as Event for Klass) and then process them and link and create everything. But that's not the best solution (even it could be in one step) but it is a choice. It could look great even if you added some javascript.

Django Form with a one-to-many relationship

I have a form in Django called PersonForm this forms model has a one-to-many relationship with Car. When displaying the PersonForm just like in the Django Admin I would like to allow my users to select/deselect from a list of Cars etc. Is this possible? I'm looking for information on where to start.
This is what I have so far for the PersonForm:
class PersonForm(forms.ModelForm):
class Meta:
model = Person
fields = ('description',)
The Models:
class Person(models.Model):
description = models.CharField(max_length="150")
class Car(models.Model):
make = models.CharField(max_length="25")
owner = models.ForeignKey('Person', related_name="Car")
So in the person form I need to show a list of cars that person is the owner of an allow selecting/deselecting of them. I'm assuming I can do this in the form i.e. using something like the related name.
Sounds like you want an inline model form. This give you the ability to add/remove Car objects from a Person within the Person form.
That previous link was for inlinemodeladmin. This next link is for an inline form:
https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#modelforms-factory
I didn't have any chance with inline formset, so i would suggest to override your save method of the model, i feel it's more DRY:
class PersonForm(forms.ModelForm):
# add a field to select a car
car = forms.ModelChoiceField(car.objects.all())
class Meta:
model = Person
fields = ('description', 'car')
def save(self, commit=True):
instance = super().save(commit)
# set Car reverse foreign key from the Person model
instance.car_set.add(self.cleaned_data['car']))
return instance
I know this is an old thread, but since I found myself almost exclusively pointed here by google when searching, I thought I would include the following for anyone else looking for an answer.
The answer, I think, is to use
https://docs.djangoproject.com/en/3.1/ref/forms/fields/#modelchoicefield
or
https://docs.djangoproject.com/en/3.1/ref/forms/fields/#modelmultiplechoicefield
There is a good article on how to use the modelmultiplechoicefield at :
https://medium.com/swlh/django-forms-for-many-to-many-fields-d977dec4b024
But it works for one to many fields as well. These allow us to generate a form with multiple choices as checkboxes or similar widgets based upon a related field in a model.

Django: saving a ModelForm with custom many-to-many models

I have Publications and Authors. Since the ordering of Authors matters (the professor doesn't want to be listed after the intern that contributed some trivial data), I defined a custom many-to-many model:
class Authorship(models.Model):
author = models.ForeignKey("Author")
publication = models.ForeignKey("Publication")
ordering = models.IntegerField(default=0)
class Author(models.Model):
name = models.CharField(max_length=100)
class Publication(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToManyField(Author, through=Authorship)
I've got aModelForm for publications and use it in a view. Problem is, when I call form.save(), the authors are obviously added with the default ordering of 0. I've written a OrderedModelMultipleChoiceField with a clean method that returns the objects to be saved in the correct order, but I didn't find the hook where the m2m data is actually saved, so that I could add/edit/remove the Authorship instances myself.
Any ideas?
If you are using a custom M2M table using the through parameter, I believe you must do the saves manually in order to save the additional fields. So in your view you would add:
...
publication = form.save()
#assuming that these records are in order! They may not be
order_idx = 0
for author in request.POST.getlist('authors'):
authorship = Authorship(author=author, publication=publication, ordering=order_idx)
authorship.save()
order_idx += 1
You may also be able to place this in your ModelForm's save function.
I'm not sure if there's a hook for this, but you could save it manually with something like:
form = PublicationForm(...)
pub = form.save(commit=False)
pub.save()
form.save_m2m()
So you can handle any custom actions in between as required. See the examples in the docs for the save method.

Django form does not display when only one field is being used

I have a django model and model form that look like this:
-models.py
class Menu_Category(models.Model):
merchant = models.ForeignKey(Merchant, related_name='menu_categories')
name = models.CharField(max_length=64)
test_field = models.CharField(max_length=20)
def __unicode__(self):
return self.name
-forms.py
class MenuCategoryForm(ModelForm):
class Meta:
model = Menu_Category
fields = ('name')
The problem i'm experiencing is that when I only select one field from the form to display (fields = ('name')) the form does not display anything nor do i get any errors. It is completely blank. However, when I add a second field fields = ('name','test_field') the form displays both fields just fine. Is there a minimum number of fields a form can display?
Thanks in advance.
You have been bitten by a common Python gotcha.
In this line:
fields = ('name')
the variable you have created is not a single-element tuple containing the single string "name". Instead, it is a single string, which is iterable, so when Django tries to iterate through it to get the names of the fields, it will think you have set 'n','a','m','e'.
To make a single-element tuple, you always need a trailing comma.
fields = ('name',)
(In fact, as the Python docs show, it is not the parentheses that make the tuple at all, but the comma.)

How to create user defined fields in Django

Ok, I am working on a Django application with several different models, namely Accounts, Contacts, etc, each with a different set of fields. I need to be able to allow each of my users to define their own fields in addition to the existing fields. I have seen several different ways to implement this, from having a large number of CustomFields and just mapping a custom name to each field used by each user. I have also seem recommendations for implementing complex mapping or XML/JSON style storage/retrieval of user defined fields.
So my question is this, has anyone implemented user defined fields in a Django application? If so, how did you do it and what was your experience with the overall implementation (stability, performance, etc)?
Update: My goal is to allow each of my users to create n number of each record type (accounts, contacts, etc) and associate user defined data with each record. So for example, one of my users might want to associate an SSN with each of his contacts, so I would need to store that additional field for each Contact record he creates.
Thanks!
Mark
What if you were to use a ForeignKey?
This code (untested and for demo) is assuming there is a system-wide set of custom fields. To make it user-specific, you'd add a "user = models.ForiegnKey(User)" onto the class CustomField.
class Account(models.Model):
name = models.CharField(max_length=75)
# ...
def get_custom_fields(self):
return CustomField.objects.filter(content_type=ContentType.objects.get_for_model(Account))
custom_fields = property(get_fields)
class CustomField(models.Model):
"""
A field abstract -- it describe what the field is. There are one of these
for each custom field the user configures.
"""
name = models.CharField(max_length=75)
content_type = models.ForeignKey(ContentType)
class CustomFieldValueManager(models.Manager):
get_value_for_model_instance(self, model):
content_type = ContentType.objects.get_for_model(model)
return self.filter(model__content_type=content_type, model__object_id=model.pk)
class CustomFieldValue(models.Model):
"""
A field instance -- contains the actual data. There are many of these, for
each value that corresponds to a CustomField for a given model.
"""
field = models.ForeignKey(CustomField, related_name='instance')
value = models.CharField(max_length=255)
model = models.GenericForeignKey()
objects = CustomFieldValueManager()
# If you wanted to enumerate the custom fields and their values, it would look
# look like so:
account = Account.objects.get(pk=1)
for field in account.custom_fields:
print field.name, field.instance.objects.get_value_for_model_instance(account)

Categories

Resources