How to create as many ModelForms as the Select option value - django

I want to create x ModelForms - x is the value of the selected option value of a Select.
If Select option value = 5, then I want to create 5 ModelForms
How can I achieve that?

Assuming you pass your x value with an ajax call or something you could just try using:
count = reqest.GET.get('x') # or whatever the name of the passing value
for i in range(count):
form = XForm()
In case you are trying to change existing objects:
object_1 = ObjectName.objects.get(pk=1) # use whatever filtering you need
form = XForm(instance=object_1)

Related

ModelChoiceField: remove empty option and select default value

I'm using the default form field for a models.ForeignKey field, which is a ModelChoiceField using the Select widget.
The related model in question is a Weekday, and the field was made nullable so that it didn't force a default value on hundreds of existing entries. However, in practice, our default should be Sunday, which is Weekday.objects.get(day_of_week=6).
By default the select widget for a nullable field when rendered displays the null option. How can I discard this option and have a default value instead?
If I set a initial value, that one is selected by default on a new form:
self.fields['start_weekday'].initial = Weekday.objects.get(day_of_week=6)
But the empty value is still listed. I tried overriding the widget choices:
self.fields['start_weekday'].widget.choices = [(wd.day_of_week, wd.name) for wd in Weekday.objects.all()]
However now Sunday isn't selected by default. I thought maybe I need to use the option value as the initial one but that didn't work either:
self.fields['start_weekday'].initial = Weekday.objects.get(day_of_week=6).pk
In short: how can I remove the empty option in a nullable model field and select a default instead?
Provide empty_label=None in ModelChoiceField
start_weekday = ModelChoiceField(Weekday.objects.filter(day_of_week=6), empty_label=None)
OR
instead of assigning initial, you can assign empty_label also
self.fields['start_weekday'].empty_label = None
OR
you can provide default value in field in models also
start_weekday = models.CharField(max_length=10,choices=[(wd.day_of_week, wd.name) for wd in Weekday.objects.all()],default=6)

Object.values returns a dictionary, what do you use to simply return a value?

I am relatively new to Django, and I have been experimenting with the object model. I have been having trouble pulling a single value from my database based on the user selecting a scenario name from a dropdown and then hitting a submit button. This is what I am working with.
if request.method =='POST' and 'submitdropdown1' in request.POST:
entry = Scenario.objects.values().get(scenario_name=scenario_name)
r = entry.get('project_cost')
Values() returns a dictionary so:
r = 'Decimal ("200")'
I would like for:
r = 200
What should I use besides Values()?
The values() method returns a QuerySet which retrieves dictionaries instead of model instances. When you use .get on those dictionaries, you are getting back the correct value from that field. In this case, entry['project_cost'] has the actual value Decimal("200").
Decimal is a module that's in the Python Standard Library. If you wish to get the integer value of an object of type Decimal you can quickly cast it to an integer like this:
r = int(entry.get('project_cost'))
and then the r variable will equal the integer 200.
Alternatively, if project_cost is an attribute of the Scenario model and you wish to work at the object level instead of with dicts, you could do something like this instead:
if request.method =='POST' and 'submitdropdown1' in request.POST:
entry = Scenario.objects.get(scenario_name=scenario_name)
r = int(entry.project_cost)

Select a value in a Django Query

I've a Django Query:-
obj = ABC.objects.filter(column1 = value)
a_list = []
for x in obj:
a_list.append(x.column2)
I want to fetch the list of values of column2 in one go., ie dont want to use the for loop. Is there any 1 straight forward query for this?
ABC.objects.filter(column1=value).values_list('column2', flat=True)
https://docs.djangoproject.com/en/1.6/ref/models/querysets/#values-list
If you don’t pass any values to values_list(), it will return all the fields in the model, in the order they were declared.
Note that this method returns a ValuesListQuerySet. This class behaves like a list. Most of the time this is enough, but if you require an actual Python list object, you can simply call list() on it, which will evaluate the queryset.

How to 'bulk update' with Django?

I'd like to update a table with Django - something like this in raw SQL:
update tbl_name set name = 'foo' where name = 'bar'
My first result is something like this - but that's nasty, isn't it?
list = ModelClass.objects.filter(name = 'bar')
for obj in list:
obj.name = 'foo'
obj.save()
Is there a more elegant way?
Update:
Django 2.2 version now has a bulk_update.
Old answer:
Refer to the following django documentation section
Updating multiple objects at once
In short you should be able to use:
ModelClass.objects.filter(name='bar').update(name="foo")
You can also use F objects to do things like incrementing rows:
from django.db.models import F
Entry.objects.all().update(n_pingbacks=F('n_pingbacks') + 1)
See the documentation.
However, note that:
This won't use ModelClass.save method (so if you have some logic inside it won't be triggered).
No django signals will be emitted.
You can't perform an .update() on a sliced QuerySet, it must be on an original QuerySet so you'll need to lean on the .filter() and .exclude() methods.
Consider using django-bulk-update found here on GitHub.
Install: pip install django-bulk-update
Implement: (code taken directly from projects ReadMe file)
from bulk_update.helper import bulk_update
random_names = ['Walter', 'The Dude', 'Donny', 'Jesus']
people = Person.objects.all()
for person in people:
r = random.randrange(4)
person.name = random_names[r]
bulk_update(people) # updates all columns using the default db
Update: As Marc points out in the comments this is not suitable for updating thousands of rows at once. Though it is suitable for smaller batches 10's to 100's. The size of the batch that is right for you depends on your CPU and query complexity. This tool is more like a wheel barrow than a dump truck.
Django 2.2 version now has a bulk_update method (release notes).
https://docs.djangoproject.com/en/stable/ref/models/querysets/#bulk-update
Example:
# get a pk: record dictionary of existing records
updates = YourModel.objects.filter(...).in_bulk()
....
# do something with the updates dict
....
if hasattr(YourModel.objects, 'bulk_update') and updates:
# Use the new method
YourModel.objects.bulk_update(updates.values(), [list the fields to update], batch_size=100)
else:
# The old & slow way
with transaction.atomic():
for obj in updates.values():
obj.save(update_fields=[list the fields to update])
If you want to set the same value on a collection of rows, you can use the update() method combined with any query term to update all rows in one query:
some_list = ModelClass.objects.filter(some condition).values('id')
ModelClass.objects.filter(pk__in=some_list).update(foo=bar)
If you want to update a collection of rows with different values depending on some condition, you can in best case batch the updates according to values. Let's say you have 1000 rows where you want to set a column to one of X values, then you could prepare the batches beforehand and then only run X update-queries (each essentially having the form of the first example above) + the initial SELECT-query.
If every row requires a unique value there is no way to avoid one query per update. Perhaps look into other architectures like CQRS/Event sourcing if you need performance in this latter case.
Here is a useful content which i found in internet regarding the above question
https://www.sankalpjonna.com/learn-django/running-a-bulk-update-with-django
The inefficient way
model_qs= ModelClass.objects.filter(name = 'bar')
for obj in model_qs:
obj.name = 'foo'
obj.save()
The efficient way
ModelClass.objects.filter(name = 'bar').update(name="foo") # for single value 'foo' or add loop
Using bulk_update
update_list = []
model_qs= ModelClass.objects.filter(name = 'bar')
for model_obj in model_qs:
model_obj.name = "foo" # Or what ever the value is for simplicty im providing foo only
update_list.append(model_obj)
ModelClass.objects.bulk_update(update_list,['name'])
Using an atomic transaction
from django.db import transaction
with transaction.atomic():
model_qs = ModelClass.objects.filter(name = 'bar')
for obj in model_qs:
ModelClass.objects.filter(name = 'bar').update(name="foo")
Any Up Votes ? Thanks in advance : Thank you for keep an attention ;)
To update with same value we can simply use this
ModelClass.objects.filter(name = 'bar').update(name='foo')
To update with different values
ob_list = ModelClass.objects.filter(name = 'bar')
obj_to_be_update = []
for obj in obj_list:
obj.name = "Dear "+obj.name
obj_to_be_update.append(obj)
ModelClass.objects.bulk_update(obj_to_be_update, ['name'], batch_size=1000)
It won't trigger save signal every time instead we keep all the objects to be updated on the list and trigger update signal at once.
IT returns number of objects are updated in table.
update_counts = ModelClass.objects.filter(name='bar').update(name="foo")
You can refer this link to get more information on bulk update and create.
Bulk update and Create

Pre-populating forms with a select field with several values in Django

I have tried quite a few things but I still don't know how can I populate a select field in Django. The following example, adds a dictionary with a select field with a name='tags' attribute.
data = {}
for tag in tags:
data['tags'] = tag.name
form = Form(initial=data)
As it is expected, the loop is overwriting the key 'tags', so it only prevails the last value (and indeed, the form shows the last value). I expected that maybe passing a list would work:
data = {}
l = []
for tag in tags:
l.append(tag.name)
data['tags'] = l
form = Form(initial=data)
But in this case, it just doesn't work.
As you can imagine, I'm using a form similar to this:
class NewTopicForm(forms.Form):
... some fields
tags = ChoiceField(
widget=forms.Select(),
choices=SOME_CHOICES
)
What is the correct way to populate a form with a select field when I need to add several values?.
Thanks!
UPDATE:
I tried the following in accordance with this post:
data = {'tags': tags.values_list('name',flat=True) }
Unfortunately, it doesn't work. Am I missing something?.
It seems that you want MultipleChoiceField if you want the initial values to be a list.