Selecting values to populate the combobox using Modelform - django

I want to get all the country names in a list so that i can set it it as source of a dropdown.
My modelform class looks like below
class UserExtForm(ModelForm):
countries = Countries.objects.values('countryname').filter(countryname__isnull = False)
class Meta:
model = UserExtras
fields=['phone','aboutme','countries']
I am trying to fill countries object with all the country names, but when the html form is displayed the dropdown is filled with text 'Countries object'. Please help me by pointing out what is here.
Thank you very much

in your models.py
from django.db import models
class Article(models.Model):
countries = models.CharField(max_length=200) //whatever
def __str__(self): # __unicode__ on Python 2
return self.countries
taken from the docs :
"It’s important to add str() methods to your models, not only for your own convenience when dealing with the interactive prompt, but also because objects’ representations are used throughout Django’s automatically-generated admin."

Related

ModelForm Instance vs Initial

I'm super new to Django, so bare with me. I'm trying to write a simple CRUD, using modelforms. In the update view, the form object initialization takes the arguments initial and instance, which confuses me. From django doc:
"As with regular forms, it’s possible to specify initial data for forms by specifying an initial parameter when instantiating the form. Initial values provided this way will override both initial values from the form field and values from an attached model instance."
Which confuses even more. I know my question isn't specific, but if someone could explain this and honestly, the background connection between the model and modelforms I would really appreciate it. Thanks y'all
Here is the example from Django docs;
from django.db import models
from django.forms import ModelForm
TITLE_CHOICES = [
('MR', 'Mr.'),
('MRS', 'Mrs.'),
('MS', 'Ms.'),
]
class Author(models.Model):
name = models.CharField(max_length=100)
title = models.CharField(max_length=3, choices=TITLE_CHOICES)
birth_date = models.DateField(blank=True, null=True)
def __str__(self):
return self.name
class AuthorForm(ModelForm):
class Meta:
model = Author
fields = ['name', 'title', 'birth_date']
Your form -AuthorForm has information that name is string and it can't be greater than 100 characters. Because it's in your model -Author. Same for title and birth_date. title can't be greater than 3 characters and it must be one of the MR, MRS or MS.
You don't have to specify types, rules for form fields if you use model forms. Model forms can create forms quickly from your model and makes validations based on your model.
Let's assume you have an author instance which has name is Joe.
If you print author.name, it returns Joe.
form = AuthorForm(initial={'name': 'Patrick'}, instance=author)
If you print form['name'].value(), it returns Patrick, not Joe. It ignores author's name value. You overrided it in your form. It could be Joe if you didn't pass initial parameter.

Django - build form fields from database dynamically

I hope the title of this question is as it should be based on this explanation below.
I have a model as below:
class Setting(models.Model):
TYPE_CHOICES = (
('CONFIG', 'Config'),
('PREFS', 'Prefs'),
)
attribute = models.CharField(max_length=100, unique=True)
value = models.CharField(max_length=200)
description = models.CharField(max_length=300)
type = models.CharField(max_length=30, choices=TYPE_CHOICES)
is_active = models.BooleanField(_('Active'), default=True)
I use this to save settings. I have don't know all settings in advance and they can change in future. So I decided to save attributes and their values in this model instead of creating columns for each setting(attribute in the model).
Now the problem I am facing is how do I present form with all attributes as fields so that a user can fill in appropriate values.
Right now, as you can see, form shows columns 'Attribute' and "Value" as labels. I would like it to show value of column 'Attribute' as label and column 'Value' as field input.
For example, in Setting model I have this:
Attribute ------------ Value
'Accept Cash' ---------- 'No'
I would like to appear this on form as
<Label>: <Input>
'Accept Cash': 'No'
I think I will have to build form fields from the database(Setting model). I am new to this and have no idea how to begin with it any example or link to tutorial that would help me get started will be much appreciated.
Thank you
you can define a model form based on your Settings model. Check the django documentation on Django Model Forms. The basic definition of the model form should be something like this
Define a forms.py file in your current django app and put the following code in it.
from django import forms
from .models import Settings
class SettingsForm(forms.ModelForm):
class Meta:
model = Settings
fields = ['the fields you want to add'] # or use '__all__' without the parentheses for all fields
Then in your views.py file navigate to the function which renders the page containing the form and add this to it
from .forms import SettingsForm
def your_function(request):
....
context = {
....
'form':SettingsForm()
}
return render(request, 'template_name.html', context)
Now in your template add the form using
........
{{ form }}
.......

Django model design: editable help text for individual model fields. Is there a foreign field that references a specific field of a model?

I have several models with several fields in my app. I want to set up a way for the user to be able to modify a help text system for each field in the model. Can you give me some guidance on how to design the models, and what field types to use? I don't feel right about storing the model and field name in CharFields, but if that is the only way, I may be stuck with it.
Is there a more elegant solution using Django?
For a quick and silly example, with an app named jobs, one named fun, and make a new app named helptext:
jobs.models.py:
class Person(models.Model):
first_name = models.CharField(max_length=32)
.
.
interests = models.TextField()
def __unicode__(self):
return self.name
class Job(models.Model):
name = models.CharField(max_length=128)
person = models.ForeignKey(Person)
address = models.TextField()
duties = models.TextField()
def __unicode__(self):
return self.name
fun.models.py:
class RollerCoaster(models.Model):
name = models.CharField(max_length=128)
scare_factor = models.PositiveInteger()
def __unicode__(self):
return self.name
class BigDipper(RollerCoaster):
max_elevation = models.PositiveInteger()
best_comment_ever_made = models.CharField(max_length=255)
def __unicode__(self):
return super.name
Now, let's say I want to have editable help text on Person.interests, and Job.duties, RollerCoaster.scare_factor, and BigDipper.best_comment_ever_made. I'd have something like:
helptext.models.py:
from django.contrib.contenttypes.models import ContentType
class HelpText(models.Model):
the_model = models.ForeignKey(ContentType)
the_field = models.CharField(max_length=255)
helptext = models.CharField(max_length=128)
def __unicode__(self):
return self.helptext
So, what is the better way to do this, other than making HelpText.the_model and HelpText.the_field CharFields that have to be compared when I am rendering the template to see if helptext is associated with each field on the screen?
Thanks in advance!
Edit:
I know about the help_text parameter of the fields, but I want this to be easily edited through the GUI, and it may contain a LOT of help with styling, etc. It would be HTML with probably upwards of 50-60 lines of text for probably 100 different model fields. I don't want to store it in the field definition for those reasons.
I changed the HelpText model to have a reference to ContentType and the field a CharField. Does this seem like a good solution? I am not sure this is the most elegant way. Please advise.
Edit 2013-04-19 16:53 PST:
Currently, I tried this and it works, but not sure this is great:
from django.db import models
from django.contrib.contenttypes.models import ContentType
# Field choices for the drop down.
FIELDS = ()
# For each ContentType verify the model_class() is not None and if not, add a tuple
# to FIELDS with the model name and field name displayed, but storing only the field
# name.
for ct in ContentType.objects.all():
m = ct.model_class()
if m is not None:
for f in ct.model_class()._meta.get_all_field_names():
FIELDS += ((f, str(ct.model) + '.' + str(f)),)
# HelpText model, associated with multiple models and fields.
class HelpText(models.Model):
the_model = models.ForeignKey(ContentType)
the_field = models.CharField(max_length=255, choices=FIELDS)
helptext = models.TextField(null=True, blank=True)
def __unicode__(self):
return self.helptext
Doesn't feel like the best, but please advise if this is a solution that will bite me in the behind later on and make me filled with regrets... :*(
The solution works, and I have it implemented, but you have to be aware that sometimes the ContentTypes get out of sync with your models. You can manually update the content types with this:
python manage.py shell
>>> from django.contrib.contenttypes.management import update_all_contenttypes
>>> update_all_contenttypes(interactive=True)
This allows you to add the new ones and remove the old ones, if they exist.
The nice thing about the Field not being a foreign key is that I can put anything in it for help text. So, say I have a field "First Name." I can put a helptext connected to the Person model and the "first_name" field. I can also make something up, like "Something really confusing." The helptext is now associated with the Person model and the "Something really confusing" field. So, I can put it at the top of the form, instead of associating to a field with hard foreign keying. It can be anything arbitrary and will follow with that "field" anywhere. The hangup would be that you may change the name of the helptext field association inadvertently sending your original helptext into never land.
To make this easy, I created a TemplateTag, which I pass the name of the model and the name of the "field" I want to associate. Then anytime the template is rendered, that helptext is there, editable for anybody to get assistance with their user interface forms.
Not sure this is the best solution, but I couldn't really see any other way to do it, and got no responses.
Cheerio!

Model "Behaviors" in Django

I'm new to Django, moved from PHP with Propel ORM engine.
So here is what I am currently doing in Django. My website has several models like
Book,
Publisher,
Comment,
Article and so on (it's not the point)
Each of them can can be
liked or disliked by a user (only once) changing the model's rating by +1 or -1.
In terms of PHP i would create a behavior, for ex. "Rateable" which would add some fields and methods to the original model and query class (like get_rating(), order_by_rating(), etc) and create a separate table for each model, for ex. book_rating_history which would hold all of the ratings for each object, to determine if the user can or can't change the rating (or show all object's ratings, if necessary). So all I would need to do is to specify the "Rateable" behavior in the model declaration, and that's all. Everything else is done automatically.
The question is - how to solve this in Django? How to model correctly? Which techniques do you use in similar cases?
You'll want to store ratings and books separately, something like this (untested).
from django.contrib.auth.models import User
from django.db import models
from django.db.models import Sum
class BookRating(models.Model):
user = models.ForeignKey(User)
book = models.ForeignKey('Book')
# you'll want to enforce that this is only ever +1 or -1
rating = models.IntegerField()
class Meta:
unique_together = (('user', 'book'),)
class Book(models.Model):
title = models.CharField(max_length = 50)
def rating(self):
return BookRating.objects.filter(book = self).aggregate(Sum('rating'))
unique_together enforces that each user can only rate a given book once.
You can then use this something like:
book = Book.objects.get(pk = 1)
rating = book.rating()
Add a comment if you have problems with this - I've not tested it, but hopefully this is enough to get you started.
You can probably avoid each object (books, publishers, comments, articles) having a separate rating object using content types, if you want.
Alternatively, you might consider looking at existing reusable apps that handle liking, like django-likes or phileo.
You can define special methods (for example vote, get_rating, etc.) only onсe in abstract model and then create your "Rateable" models using this one.
class Rateable(models.Model):
class Meta:
abstract = True
def vote(self, *args, **kwargs):
...
def rating(self, *args, **kwargs):
...
class Book(Rateable):
...
Also it is better to use single model for storing rating data witch content types as noticed Dominic Rodger

Validating an Autocomplete field in Django

I have models similar to the following:
class Band(models.Model):
name = models.CharField(unique=True)
class Event(models.Model):
name = models.CharField(max_length=50, unique=True)
bands = models.ManyToManyField(Band)
and essentially I want to use the validation capability offered by a ModelForm that already exists for Event, but I do not want to show the default Multi-Select list (for 'bands') on the page, because the potential length of the related models is extremely long.
I have the following form defined:
class AddEventForm(ModelForm):
class Meta:
model = Event
fields = ('name', )
Which does what is expected for the Model, but of course, validation could care less about the 'bands' field. I've got it working enough to add bands correctly, but there's no correct validation, and it will simply drop bad band IDs.
What should I do so that I can ensure that at least one (correct) band ID has been sent along with my form?
For how I'm sending the band-IDs with auto-complete, see this related question: Django ModelForm Validate custom Autocomplete for M2M, instead of ugly Multi-Select
You can override the default fields in a ModelForm.
class AddEventForm(forms.ModelForm):
band = forms.CharField(max_length=50)
def clean_band(self):
bands = Band.objects.filter(name=band,
self.data.get('band', ''))
if not bands:
raise forms.ValidationError('Please specify a valid band name')
self.cleaned_data['band_id'] = bands[0].id
Then you can use your autocomplete widget, or some other widget. You can also use a custom widget, just pass it into the band field definition: band = forms.CharField(widget=...)