Django - build form fields from database dynamically - django

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 }}
.......

Related

How to avoid fields that has null values automatically when rendering html

I want to not to display the null value fields in template.So How can i achieve this in django?Is there any functions available to do this.
In you used Django ModeForm then do this
class ProductForm(forms.ModelForm):
class Meta:
model = ProductModel
exclude = ('selling_price','discounted_price') # this is exclude fields not render in html template
NOTE:- pass null=True, blank=True in Model
If what you are saying is that you do not want a field that has been set to null = True in your models.py to be rendered in your html template, you can use django inbulit form class to render the form and exclude whatever field is null
Here is an example of what i am saying.
class Userdetail(forms.ModelForm):
class Meta:
model = User_detail
exclude = ("name_of_null_field",) #This field won't be rendered in your html template because it is excluded.
You can read more on Django forms here Working with forms

How to set value of DateTime field automatically in Django REST Framework HTML form?

I have a very basic Django Model and use it in Django REST Framework.
When using the browsable API tool and requesting an instance of a ressource, I can set the values of the different attributes using the HTML form at the bottom of the page. All attributes have their current value pre-set except for the DateTime fields. Is there a special setting required such that the form fields for DateTime entries field are prefilled with their current value?
Model class:
class C(models.Model):
OrderDate = models.DateTimeField(auto_now=False)
p1 = models.ForeignKey(PA, related_name="cs", on_delete=models.CASCADE, null=True)
p2 = models.ForeignKey(PB, related_name="cs", on_delete=models.DO_NOTHING, null=True)
class Meta:
ordering = ['OrderDate']
View:
class CViewSet(viewsets.ModelViewSet):
queryset = C.objects.all().order_by('-OrderDate')
serializer_class = CSerializer
def get_queryset(self):
cs = C.objects.all()
# Some filters...
return cs
Serializer:
class CSerializer(serializers.HyperlinkedModelSerializer):
p1 = PASerializer(many=False, read_only=True)
p2 = PBSerializer(many=False, read_only=True)
class Meta:
model = C
fields = (
'id',
'OrderDate',
'p1',
'p2',
)
I tried to generalize the code hope the general idea is clear.
I would like that the OrderDate field is prefilled with the current value when the HTML form in the browsable API is shown.
in DateTimeField you have 2 options, add a default value or use auto_now_add.
in your situation you have set auto_now, and according to this question
auto_now - updates the value of field to current time and date every time the Model.save() is called.
auto_now_add - updates the value with the time and date of creation of record.
so you have this two possibilities:
OrderDate = models.DateTimeField(default=datetime.now)
or
OrderDate = models.DateTimeField(auto_now_add=True)
This is work if you want to automatically add the current time when a user submit the form without displaying it in your HTML, if you want to display the current date and time in html field (your Form), then you have to set it in the frontend side using JavaScript and HTML
Use: <input type="datetime-local">
I'm new to django drf and had the same problem, and this solved it. (DATETIME_FORMAT in settings.py)
my guess is because when rendering the html it uses a different format than the one DRF uses
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS':
'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 10,
'DATETIME_FORMAT' : '%Y-%m-%dT%H:%M',
}

How to add Placeholder text in fields with django crispy-forms

I'm new to django and using crispy-forms to render the form.How do i add placeholder text to a field e.g "please enter your address"
In my views.py
class PostCreateView(LoginRequiredMixin, CreateView):
model = Post
fields = ['name', 'address']
In models.py
class Post(models.Model):
name = models.CharField(max_length=100, blank="true")
address = models.CharField(max_length=100, blank="true")
Every input field is Given an id by django; get the ids from inspect -- In the Html file and add a script tag some where and
Then use this JS code
document.getElementbyId('id of the field').setAtribute('placeholder','Your PH')
Btw use google for spelling errors and soory for them

Combining unrelated Models in Formset and saving results

These are the models related to my problem:
Models.py
class SequenceDiagram(models.Model):
name = models.TextField(blank=True)
attributeMappingName = models.TextField(blank=True)
class AttributeFilter(models.Model):
seqDiagram = models.ForeignKey(SequenceDiagram)
attributeName = models.TextField(blank=True)
protocol = models.TextField()
isDisplayed = models.BooleanField(default=False)
class AttributeMapping(models.Model):
mappingName = models.TextField()
protocol = models.TextField(blank=True)
nativeName = models.TextField(blank=True)
customName = models.TextField(blank=True
Filters are specific to each SequenceDiagram but mappings are generic and applicable to different Diagrams.
I want a Formset with all AttributeFilters and AttributeMappings linked with the SequenceDiagram.
These are to be displayed in a table where isDisplayed and customName can be edited and then saved to the database.
How can I combine them to a Formset and then save the users changes?
Can a many-to-many relationship help solve my problem? If so, in which end should it be defined?
Please tell me if anything needs to be clarified.
edit
The resulting table should look like this:
Protocol|Native|Custom|Display
prot1 | Nat1 | Cus1 | Chkbx1
prot2 | Nat2 | Cus2 | Chkbx2
.......
So that matching customNames and isDisplayed are aligned.
I have tried using objects.extra() but I can't seem to save the changes to the 'other' model, I also don't know how to get the queryset to a Formfield and back.
AttributeFilter.objects.extra(
select={"protocol":"protocol", "sd":"sdAttributeName"},
where=["customName=nativeName"],
tables=["project_attributemapping"])
You can display both forms in the template and the process the forms separately in the view.
Here, we will be using ModelForms. We will create ModelForm for each model and then save all the models in a single view.
forms.py
from django import forms
from my_app.models import SequenceDiagram, AttributeFilter, AttributeMapping
class SequenceDiagramForm(forms.ModelForm):
class Meta:
model = SequenceDiagram
class AttributeFilterForm(forms.ModelForm):
class Meta:
model = AttributeFilter
exclude = (seqDiagram,)
class AttributeMappingForm(forms.ModelForm):
class Meta:
model = AttributeMapping
views.py
from django.views.generic import View
class MyView(View):
def post(self, request, *args, **kwargs):
sequence_diagram_form = SequenceDiagramForm(request.POST) # create form instance and populate with data
attribute_filter_form = AttributeFilterForm(request.POST) # create form instance and populate with data
attribute_mapping_form = AttributeMappingForm(request.POST) # create form instance and populate with data
sequence_diagram_form_valid = sequence_diagram_form.is_valid() # check if 'SequenceDiagramForm' is valid
attribute_filter_form_valid = attribute_filter_form.is_valid() # check if 'AttributeFilterForm' is valid
attribute_mapping_form_valid = attribute_mapping_form.is_valid() # check if 'AttributeMappingForm' is valid
# Check if all the forms are valid
if sequence_diagram_form_valid and attribute_filter_form_valid and attribute_mapping_form_valid:
sequence_diagram_obj = sequence_diagram_form.save() # save the SequenceDiagram object
attribute_filter_obj = attribute_filter_form.save(commit=False) # not save but get the instance
attribute_mapping_obj = attribute_mapping_form.save() # save the AttributeMapping object
attribute_filter_obj.seqDiagram = sequence_diagram_obj # set the `seqDiagram` to `sequence_diagram_obj`
attribute_filter_obj.save() # Now save the AttributeFilter object
...
# redirect to success page on all all forms being valid
...
# render the page again with errors if any of the form is invalid
In our view, we check if all the forms are valid and then only save all the 3 objects into db. If any of the form is invalid, then we don't save any of them.
For the case when any of the form is invalid, you can add the code to render the page again with the form errors.

Django Form with no required fields

I want to make a form used to filter searches without any field being required. For example given this code:
models.py:
class Message(models.Model):
happened = models.DateTimeField()
filename = models.CharField(max_length=512, blank=True, null=True)
message = models.TextField(blank=True, null=True)
dest = models.CharField(max_length=512, blank=True, null=True)
fromhost = models.ForeignKey(Hosts, related_name='to hosts', blank=True, null=True)
TYPE_CHOICES = ( (u'Info', u'Info'), (u'Error', u'Error'), (u'File', u'File'), (u'BPS', u'BPS'),)
type = models.CharField(max_length=7, choices=TYPE_CHOICES)
job = models.ForeignKey(Jobs)
views.py:
WHEN_CHOICES = ( (u'', ''), (1, u'Today'), (2, u'Two days'), (3, u'Three Days'), (7, u'Week'),(31, u'Month'),)
class MessageSearch(ModelForm): #Class that makes a form from a model that can be customized by placing info above the class Meta
message = forms.CharField(max_length=25, required=False)
job = forms.CharField(max_length=25, required=False)
happened = forms.CharField(max_length=14, widget=forms.Select(choices=WHEN_CHOICES), required=False)
class Meta:
model = Message
That's the code I have now. As you can see it makes a form based on a model. I redefined message in the form because I'm using an icontains filter so I didn't need a giant text box. I redefined the date mostly because I didn't want to have to mess around with dates (I hate working with dates! Who doesnt?) And I changed the jobs field because otherwise I was getting a drop down list of existing jobs and I really wanted to be able to search by common words. So I was able to mark all of those as not required
The problem is it's marking all my other fields as required because in the model they're not allowed to be blank.
Now in the model they can't be blank. If they're blank then the data is bad and I don't want it in the DB. However the form is only a filter form on a page to display the data. I'm never going to save from that form so I don't care if fields are blank or not. So is there an easy way to make all fields as required=false while still using the class Meta: model = Message format in the form? It's really handy that I can make a form directly from a model.
Also this is my first serious attempt at a django app so if something is absurdly wrong please be kind :)
You can create a custom ModelForm that suit your needs. This custom ModelForm will override the save method and set all fields to be non-required:
from django.forms import ModelForm
class SearchForm(ModelForm):
def __init__(self, *args, **kwargs):
super(SearchForm, self).__init__(*args, **kwargs)
for key, field in self.fields.iteritems():
self.fields[key].required = False
So you could declare your forms by simply calling instead of the ModelForm, e.g.:
class MessageForm(SearchForm):
class Meta:
model = Message
You could also pass empty_permitted=True when you instantiate the form, e.g.,
form = MessageSearch(empty_permitted=True)
that way you can still have normal validation rules for when someone does enter data into the form.
I would give a try to the django-filter module :
http://django-filter.readthedocs.io/en/develop/
fields are not required. these are filters actually. It would look like this :
import django_filters
class MessageSearch(django_filters.FilterSet):
class Meta:
model = Message
fields = ['happened', 'filename', 'message', '...', ]
# django-filter has its own default widgets corresponding to the field
# type of the model, but you can tweak and subclass in a django way :
happened = django_filters.DateFromToRangeFilter()
mandatory, hidden filters can be defined if you want to narrow a list of model depending on something like user rights etc.
also : setup a filter on a 'reverse' relationship (the foreignkey is not in the filtered model : the model is referenced elsewhere in another table), is easy, just name the table where the foreign key of the filtered model field is :
# the 'tags' model has a fk like message = models.ForeignKey(Message...)
tags= django_filters.<some filter>(name='tags')
quick extendable and clean to setup.
please note I didn't wrote this module, I'm just very happy with it :)