django updating m2m field - django

I have a model service and a ModelForm named Service which I use to add and update the service model. The model looks like this:
class Service(models.Model):
categories = models.ManyToManyField(Category)
The categories field is displayed as a tag with that allows multiple selection. It works well when I'm adding a new record but when I'm updating it, only one service is showing up on the request.POST['categories'] even if I selected multiple categories.
I tried dumping the request object and I can see that the categories is showing something like:
u'categories': [u'3', u'4', u'2']
I tried calling the request._get_post() and it did return only 1 category, hence the request.POST['categories'] returns only 1. Anybody who knows what's happening and how to fix it?

You probably want to use
request.POST.getlist('categories')
which will return all the selected values for that form field.

Related

How to create foreign key linked fields in forms just like in Django Admin?

In django admin, you can add, edit, and even delete objects from another model if there is a relationship between the two.
For instance, if my code looks like this:
class Category(models.Model):
...
class Product(models.Model):
...
category = models.ForeignKey(Category)
When I am editing/adding a product using the django admin site, in the category field, I have 3 buttons to add/edit/delete categories. Adding one takes to a new window, and once I submit the form, the category is added, the window is closed, and I am returned to my product form with the extra category present. Like this:
How can I do this in my normal application (outside the admin) using forms?
If I understand your question correctly, you could do what django admin does, which is to link the add button to this:
/admin/<your_app>/<your_model>/add/?_to_field=id&_popup=1
and then it uses a bit of javascript to get back the new object you just created. If you look into the contrib/admin/static/admin/js/admin/RelatedObjectLookups.js file (in django's code), you'll see a few functions that pass the id of the calling field to the popup (in showRelatedObjectPopup), and then bring back the selected id (in dismissRelatedLookupPopup).
This is for adding a new object, but you can look into the logic for changing/deleting.
You can replicate that logic with your own forms.

Updating Django's ManytoMany after filter

I was trying to update certain Article's created_by and edited_by which have ManytoMany relation with a user and add another user to it.
I came across
MyModel.objects.filter(pk=some_value).update(field1='some value')
As a way to update with a single query is there a way to update ManytoMany with a single query too?
Article.objects.filter(Q(created_by__in=[deleted_user_id])| Q(edited_by__in=[deleted_user_id])).update(?)
What should I replace "?" with?
Assume that I need to add "replacement_user_id" to all those article which the filter returns.
I guess we can do by querying the "through" model maybe.
This is not possible using update method:
You can only set non-relation fields and ForeignKey fields using this
method.To update a non-relation field, provide the new value as a
constant. To update ForeignKey fields, set the new value to be the new
model instance you want to point to.
Learn more here
Update:
You can add multilple objects like:
articles = Article.objects.filter(Q(created_by__in=[deleted_user_id])| Q(edited_by__in=[deleted_user_id]))
created_by_objs = User.objects.filter(...)
edited_by_objs = User.objects.filter(...)
for article in articles:
#article.created_by.clear() uncomment if needed
article.created_by.add(*created_by_objs)
#article.edited_by.clear() uncomment if needed
article.edited_by.add(*edited_by_objs)
Learn more here

Django disable widget caching?

So I have a form where I defined a select widget like this:
class AdHocVoucherTemplateForm(ModelForm):
class Meta:
model = AdHocVoucherTemplate
widgets = {
'retailer_id': Select(choices=[(r.pk, r.name) for r in Retailer.objects.all()]),
}
This way I achieve a select input field with all retailers. User can select a retailer from a drop down list and submit the form.
The problem I noticed is that when I add a new retailer (Retailer.objects.create etc), it doesn't appear in the form in the drop down list. It appears to be cached. When I restart the uwsgi service running Django, it is there.
How can I make the widget always refresh the newest values from the database?
I don't see this caching behavior when I do something similar with a ModelChoiceField.
It's default widget is a Select.
Something like:
retailer = forms.ModelChoiceField(queryset=Retailer.objects.all())
When your code is evaluated, that choices parameter is constructed once and then your select just has a static list of retailer (id,name) tuples. When the ModelChoiceField is constructed, it is referencing a QuerySet which is not evaluated until the list of choices is actually requested/displayed.

limit choices for foreign field based on other field

Is it possible to do really dynamic form in AdminModel? I have following models:
class MyModel(models.Model):
firstfield=models.ForeignKey(First)
secondField= models.ForeignKey(Second, blank=True,null=True)
#some other fields
class Second(models.Model):
firstfield=models.ForeignKey(First)
#other fields
As you can see Second is optional. But I want it to limit according to current selection in First? It would require some page refreshing or some ajax work but I simply don't know how to even pass First value. Maybe I should add it to request and then use something similar to:
https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.formfield_for_foreignkey ?
You can do it through ajax request. If you don't know how it works see the below links.
How to implement two dropdowns dependent on each other using Django and jQuery
Dynamic select fields with JQuery and django

Django model ManytoMany getters

I wanted to get a list of objects associated to model A by ManyToMany with model B, e.g. diners (A) confirmed to attend a meal(B). But I'm not sure what getter I should use. I actually wanted to do this to show the associated objects in the admin panel. The method included beneath was one failed attempt I made.
class Meal(models.Model):
diners = models.ManyToManyField(User, through='Attendance', related_name="eating", blank=True)
def diners(self):
return self.eating
Can you help?
Thanks
As ilvar suggested, remove diners method and use self.diners.all() to get objects inside Meal methods. related_name='eating' is for fetching attended meals of a user, reversely.
I arrived at this page with the same problem as OP. I ended up simply removing the reference to the ManyToMany field in list_display in my admin model. The result: on the admin page for that app, under the ManyToMany field name, appeared a nicely formatted multi-selection list widget with the possible values for my ManyToMany relationship shown.
So the solution was to remove the reference in list_display and let Django handle it. This is with Django 1.4.3.