I want to add unlimited fields in the Django model.
Actually, I want my model to look like this, Is it Possible ?
It is possible, but in a somewhat different way: Namely, by creating another model (called Choice, for instance) and letting several Choice objects point to the same Question by using a ForeignKey relationship. This way there can then be arbitrarily many Choices. Django's seven-part tutorial explains precisely how to create such an app. I highly recommend to work through it start to finish: https://docs.djangoproject.com/en/4.1/intro/tutorial01/
It will exactly as picture
in admin panel
admin.py
class AnswersInline(admin.TabularInline):
model = Answers
class QuestionAdmin(admin.ModelAdmin):
inlines = [
AnswersInline
]
admin.site.register(Question,QuestionAdmin)
modelpy
class Question(models.Model):
Username = models.CharField(max_length=50, verbose_name='User Name')
Question = models.CharField(max_length=50, verbose_name='Question')
CorrectAnswer = models.CharField(max_length=50, verbose_name='Hidden Answer')
def __str__(self):
return f"{self.Question}"
class Answers(models.Model):
QuestionId = models.ForeignKey('Question', models.DO_NOTHING)
Answer = models.CharField(max_length=50, verbose_name='User Name')
def __str__(self):
return f"{self.Answer}"
Related
I have two models that have many to many relationship. One model consists of all possible choices and the other model can have some or all of those choices.
These are the two models:
class LanguageDomains(models.Model):
DOMAIN_CHOICES=(
('Choice1', _(u'Choice1')),
('Choice2', _(u'Choice2')),
('Choice3', _(u'Choice3')),
('Choice4', _(u'Choice4')),
)
# There is many more choices in the actual code
domains = models.CharField(max_length=255, choices=DOMAIN_CHOICES, default=None)
def __unicode__(self):
return self.domains
class Revitalization(models.Model):
code = models.ForeignKey(Codes, related_name ='revitalization')
program_name = models.CharField(max_length=255, null=True, blank=True)
year_founded = models.CharField(max_length=4, null=True, blank=True)
some_domains = models.ManyToManyField(LanguageDomains, related_name='revitalization')
def __unicode__(self):
return self.code.primary_name
My admin.py:
class RevitalizationAdmin(admin.ModelAdmin):
list_display = ('code','id')
filter_horizontal = ('language_domains',)
This is what the admin console looks like:
The question is, is there a way to populate the "Available language domains" list with all the DOMAIN_CHOICES from LanguageDomains model?
You could write a data migration that will populate the LanguageDomains model table with all the available choices.
Depending on your use-case, if the sole purpose of LanguageDomains is to present multiple choices and it's not going to be edited in runtime look into using django-multiselectfield.
I am just starting with Django and want to create a model for an application.
I find Djangos feature to
- automatically define validations and html widget types for forms according to the field type defined in the model and
- define a choice set for the field right in the model
very usefull and I want to make best use of it. Also, I want to make best use of the admin interface.
However, what if I want to allow the user of the application to add fields to the model? For example, consider a simple adress book. I want the user to be able to define additional atributes for all of his contacts in the admin settings, i.e. add a fax number field, so that a fax number can be added to all contacts.
from a relational DB perspective, I would have a table with atributes (PK: atr_ID, atr_name, atr_type) and an N:N relation between atributes and contacts with foreign keys from atributes and contacts - i.e. it would result in 3 tables in the DB. right?
but that way I cannot define the field types directly in the Django model. Now what is best practice here? How can I make use of Djangos functionality AND allow the user to add aditional/custom fields via the admin interface?
Thank you! :)
Best
Teconomix
i would suggest storing json as a string in the database, that way it can be as extendable as you want and the field list can go very long.
Edit:
If you are using other damn backends you can use Django-jsonfield. If you are using Postgres then it has a native jsonfield support for enhanced querying, etc.
Edit 2:
Using django mongodb connector can also help.
I've used this approach, first seen in django-payslip, to allow for extendable fields. This provides a structure for adding fields to models, from which you can allow users to add/edit through standard view procedures (no admin hacking necessary). This should be enough to get you started, and taking a look at django-payslip's source code (see the views) also provides view Mixins and forms as an example of how to render to users.
class YourModel(models.Model):
extra_fields = models.ManyToManyField(
'your_app.ExtraField',
verbose_name=_('Extra fields'),
blank=True, null=True,
)
class ExtraFieldType(models.Model):
"""
Model to create custom information holders.
:name: Name of the attribute.
:description: Description of the attribute.
:model: Can be set in order to allow the use of only one model.
:fixed_values: Can transform related exta fields into choices.
"""
name = models.CharField(
max_length=100,
verbose_name=_('Name'),
)
description = models.CharField(
max_length=100,
blank=True, null=True,
verbose_name=_('Description'),
)
model = models.CharField(
max_length=10,
choices=(
('YourModel', 'YourModel'),
('AnotherModel', 'AnotherModel'), # which models do you want to add extra fields to?
),
verbose_name=_('Model'),
blank=True, null=True,
)
fixed_values = models.BooleanField(
default=False,
verbose_name=_('Fixed values'),
)
class Meta:
ordering = ['name', ]
def __unicode__(self):
return '{0}'.format(self.name)
class ExtraField(models.Model):
"""
Model to create custom fields.
:field_type: Connection to the field type.
:value: Current value of this extra field.
"""
field_type = models.ForeignKey(
'your_app.ExtraFieldType',
verbose_name=_('Field type'),
related_name='extra_fields',
help_text=_('Only field types with fixed values can be chosen to add'
' global values.'),
)
value = models.CharField(
max_length=200,
verbose_name=_('Value'),
)
class Meta:
ordering = ['field_type__name', ]
def __unicode__(self):
return '{0} ({1}) - {2}'.format(
self.field_type, self.field_type.get_model_display() or 'general',
self.value)
You can use InlineModelAdmin objects. It should be something like:
#models.py
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=100)
class ContactType(models.Model):
name = models.CharField(max_length=100)
class Contact(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
contact_type = models.ForeignKey(ContactType, on_delete=models.CASCADE)
value = models.CharField(max_length=100)
#admin.py
from django.contrib import admin
class ContactInline(admin.TabularInline):
model = Contact
class PersonAdmin(admin.ModelAdmin):
inlines = [
ContactInline,
]
By the way... stackoverflow questions should contain some code. You should try to do something before asking a question.
I am trying to build an app, where user can customize forms. The Following example contains classes for creating Fields (QuestionField, AnswerField) which is used by the admin and the BoolAnswer which is filled by the user: This Way an admin can create a Form with questions and possible answers.
According to django documentation, blank=True is related to evaluation. The problem is that it is set on the class level rather than on object level.
How can I set blank=True depending on the related model so that I do not have to reimplement an own validator? (see pseudo code in BoolAnswer)
My models.py:
class QuestionField(models.Model):
question = models.TextField(max_length=200)
models.ForeignKey(Sheet)
class BoolAnswerField(AnswerField):
question = models.ForeignKey(models.Model)
if_true_field = models.TextField(max_length=100, null=True)
class BoolAnswer(models.Model):
bool_answer_field = models.ForeignKey(BoolAnswerField)
result = models.BooleanField()
if_true = models.TextField(max_length=100, null=True,
blank=True if self.bool_answer_field.if_true_field)
** Short explanation **:
If the Answer to a BoolAnswerField question is True, if_true field should explain, why
Don't hate me, but validation is the way to go, see here
class BoolAnswer(models.Model):
bool_answer_field = models.ForeignKey(BoolAnswerField)
result = models.BooleanField()
if_true = models.TextField(max_length=100, null=True, blank=True)
def clean(self)
if self.bool_answer_field.if_true_field and not self.if_true:
raise ValidationError('BAF is True without a reason')
In case you want your error message to be displayed next to the field, not at the beginning of the form, you've got to pass a dict to ValidationError, like:
from django.utils.translation import gettext_lazy as _
...
raise ValidationError({
'field_name': _('This field is required.')})
I have an application that makes use of Django's UserProfile to extend the built-in Django User model. Looks a bit like:
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
# Local Stuff
image_url_s = models.CharField(max_length=128, blank=True)
image_url_m = models.CharField(max_length=128, blank=True)
# Admin
class Admin: pass
I have added a new class to my model:
class Team(models.Model):
name = models.CharField(max_length=128)
manager = models.ForeignKey(User, related_name='manager')
members = models.ManyToManyField(User, blank=True)
And it is registered into the Admin:
class TeamAdmin(admin.ModelAdmin):
list_display = ('name', 'manager')
admin.site.register(Team, TeamAdmin)
Alas, in the admin inteface, when I go to select a manager from the drop-down box, or set team members via the multi-select field, they are ordered by the User numeric ID. For the life of me, I can not figure out how to get these sorted.
I have a similar class with:
class Meta:
ordering = ['name']
That works great! But I don't "own" the User class, and when I try this trick in UserAdmin:
class Meta:
ordering = ['username']
I get:
django.core.management.base.CommandError: One or more models did not validate:
events.userprofile: "ordering" refers to "username", a field that doesn't exist.
user.username doesn't work either. I could specify, like image_url_s if I wanted to . . . how can I tell the admin to sort my lists of users by username? Thanks!
This
class Meta:
ordering = ['username']
should be
ordering = ['user__username']
if it's in your UserProfile admin class. That'll stop the exception, but I don't think it helps you.
Ordering the User model as you describe is quite tricky, but see http://code.djangoproject.com/ticket/6089#comment:8 for a solution.
One way would be to define a custom form to use for your Team model in the admin, and override the manager field to use a queryset with the correct ordering:
from django import forms
class TeamForm(forms.ModelForm):
manager = forms.ModelChoiceField(queryset=User.objects.order_by('username'))
class Meta:
model = Team
class TeamAdmin(admin.ModelAdmin):
list_display = ('name', 'manager')
form = TeamForm
This might be dangerous for some reason, but this can be done in one line in your project's models.py file:
User._meta.ordering=["username"]
For me, the only working solution was to use Proxy Model. As stated in the documentation, you can create own proxy models for even built-in models and customize anything like in regular models:
class OrderedUser(User):
class Meta:
proxy = True
ordering = ["username"]
def __str__(self):
return '%s %s' % (self.first_name, self.last_name)
After that, in your model just change Foreign Key to:
user = models.OneToOneField(OrderedUser, unique=True)
or even more suitable
user = models.OneToOneField(OrderedUser, unique = True, parent_link = True)
I have a manytomany relationship between publication and pathology. Each publication can have many pathologies. When a publication appears in the admin template, I need to be able to see the many pathologies associated with that publication. Here is the model statement:
class Pathology(models.Model):
pathology = models.CharField(max_length=100)
def __unicode__(self):
return self.pathology
class Meta:
ordering = ["pathology"]
class Publication(models.Model):
pubtitle = models.TextField()
pathology = models.ManyToManyField(Pathology)
def __unicode__(self):
return self.pubtitle
class Meta:
ordering = ["pubtitle"]
Here is the admin.py. I have tried variations of the following, but always
get an error saying either publication or pathology doesn't have a foreign key
associated.
from myprograms.cpssite.models import Pathology
class PathologyAdmin(admin.ModelAdmin):
# ...
list_display = ('pathology', 'id')
admin.site.register(Pathology, PathologyAdmin)
class PathologyInline(admin.TabularInline):
#...
model = Pathology
extra = 3
class PublicationAdmin(admin.ModelAdmin):
# ...
ordering = ('pubtitle', 'year')
inlines = [PathologyInline]
admin.site.register(Publication,PublicationAdmin)
Thanks for any help.
Unless you are using a intermediate table as documented here http://docs.djangoproject.com/en/dev/ref/contrib/admin/#working-with-many-to-many-intermediary-models, I don't think you need to create an Inline class. Try removing the line includes=[PathologyInline] and see what happens.
I realize now that Django is great for the administration (data entry) of a website, simple searching and template inheritance, but Django and Python are not very good for complex web applications, where data is moved back and forth between a database and an html template. I have decided to combine Django and PHP, hopefully, applying the strengths of both. Thanks for you help!
That looks more like a one-to-many relationship to me, tho I'm somewhat unclear on what exactly Pathologies are. Also, so far as I understand, Inlines don't work on manytomany. That should work if you flip the order of the models, remove the manytomany and add a ForeignKey field to Publication in Pathology.
class Publication(models.Model):
pubtitle = models.TextField()
def __unicode__(self):
return self.pubtitle
class Meta:
ordering = ["pubtitle"]
class Pathology(models.Model):
pathology = models.CharField(max_length=100)
publication = models.ForeignKey(Publication)
def __unicode__(self):
return self.pathology
class Meta:
ordering = ["pathology"]