4

How to create an object for a Django model with a many to many field?

From above question i come to know we can save Many to Many field later only.

models.py

class Store(models.Model):
   name = models.CharField(max_length=100)

class Foo(models.Model):
   file = models.FileField(upload_to='')
   store = models.ManyToManyField(Store, null=True, blank=True)

views.py

new_track.file = request.FILES['file']
new_track.save()

And file uploading working fine then later i modify my code to add store then i am here...

Now i am sure db return id's here. Then i tried with my below code but that's given me error only

    x = new_track.id
    new = Foo.objects.filter(id=x)
    new.store.id = request.POST['store']
    new.save()

ok so the error here is 'QuerySet' object has no attribute 'store'

And also i tried with add that's now working either. So the question is how to save()

Community
  • 1
  • 1
  • try to change your code into new.store = request.POST['store'] – Adiyat Mubarak Sep 26 '14 at 15:50
  • 1
    `.filter` returns a queryset. To get an object, you need a `.get()` or `.filter()[0]` – karthikr Sep 26 '14 at 16:10
  • @karthikr I am damn sure getting the id value when save. Is my method correct way for saving many to many relation ? If i do my way i am getting `Foo' object has no attribute 'name'` well i tried yours too. And doniyor told different method return store object then save using add method. What is correct way ? please help –  Sep 27 '14 at 05:12
  • @cdvv7788 i changed my question please take look into it –  Sep 27 '14 at 05:32

5 Answers5

6

the right way of saving objects with manytomany relations would be:

...
new_track.file = request.FILES['file']
new_track.save()

new_store = Store.objects.get(id=int(request.POST['store']))
new_track.store.add(new_store)
doniyor
  • 36,596
  • 57
  • 175
  • 260
  • I tried yours and getting error like `nvalid literal for int() with base 10: 'on'` –  Sep 27 '14 at 05:04
  • @em___life Try this ``new_store = Store.objects.get(id=int(request.POST['store']))`` – doniyor Sep 27 '14 at 07:28
  • ok.. there is no error right now. I guess object is saving. Then i visited mysql workbench, table 'dsp_foo_store` there three field is there (id, foo_id, store_id). If foo_id is 9 then the corresponding store_id 3 but i select multiple means more than three checkbox but it return only one object. How come ? –  Sep 27 '14 at 07:45
  • @em___life (dont forget to upvote and check as answer if it solved your first problem). i dont understand what you mean by ``"i select multiple means more than three checkbox"``. can you describe this case a little more – doniyor Sep 27 '14 at 08:04
  • I have doubt like `objects.get` return only one object but `request.POST['store']` return more than one value bcse each checkbox rendered store `ids`..... –  Sep 27 '14 at 10:20
  • and also i checked in workbench only one id saved in store_id field. This is suppose to be multiple values right ?.. Instead of saving multiple value why only one value save into store_id . –  Sep 27 '14 at 10:22
  • Your solution is right .. But i need this doubts .. I cant' able to upvote bcse i have only 5 reputation .. –  Sep 27 '14 at 10:23
1

As of 2020, here's my approach to saving ManyToMany Field to a given object.

Short Answer

class HostingRequestView(View):
    def post(self, request, *args, **kwargs):
        form = VideoGameForm(request.POST)
        if form.is_valid():
            obj = form.save(commit=False)
            obj.updated_by = request.user
            obj.save()

            selected_categories = form.cleaned_data.get('category') #returns list of all selected categories e.g. ['Sports','Adventure']
            #Now saving the ManyToManyField, can only work after saving the form
            for title in selected_categories:
                category_obj = Category.objects.get(title=title) #get object by title i.e I declared unique for title under Category model
                obj.category.add(category_obj) #now add each category object to the saved form object
            return redirect('confirmation', id=obj.pk)

Full Answer

models.py

class Category(models.Model):
    title = models.CharField(max_length=100, null=True, unique=True)

class VideoGame(models.Model):
    game_id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=50, blank=False, null=False)
    updated_by = models.ForeignKey(settings.AUTH_USER_MODEL, blank=False, on_delete=models.CASCADE)
    category = models.ManyToManyField(Category) #ManyToMany Category field
    date_added = models.DateTimeField(auto_now_add=True, verbose_name="date added")

forms.py ModelForm

class VideoGameForm(forms.ModelForm):
    CATEGORIES = (
        ('Detective', 'Detective'),
        ('Sports', 'Sports'),
        ('Action', 'Action'),
        ('Adventure', 'Adventure'),
    )

    category = forms.MultipleChoiceField(choices=CATEGORIES, widget=forms.SelectMultiple())

    class Meta:
        model = VideoGame
        fields = ['name', 'category', 'date_added']

views.py on POST

class HostingRequestView(View):
    def post(self, request, *args, **kwargs):
        form = VideoGameForm(request.POST)
        if form.is_valid():
            obj = form.save(commit=False)
            obj.updated_by = request.user
            obj.save()

            selected_categories = form.cleaned_data.get('category') #returns list of all selected categories e.g. ['Sports','Adventure']
            #Now saving the ManyToManyField, can only work after saving the form
            for title in selected_categories:
                category_obj = Category.objects.get(title=title) #get object by title i.e I declared unique for title under Category model
                obj.category.add(category_obj) #now add each category object to the saved form object
            return redirect('confirmation', id=obj.pk)

URL path for redirect

urlpatterns = [
    path('confirmation/<int:id>/', Confirmation.as_view(), name='confirmation'),
]

I hope this can be helpful. Regards

Brian
  • 406
  • 1
  • 5
  • 8
0
new.stores.all()

returns all stores linked to the object.

jibreel
  • 359
  • 2
  • 8
0

Maybe:

  1. Change Foo to Tracks
  2. Tracks.objects.filter(id=x) to Tracks.objects.get(id=x)

Let me know how it goes

cdvv7788
  • 2,021
  • 1
  • 18
  • 26
  • i Changed my question please take look into it –  Sep 27 '14 at 05:05
  • @em___life Check my second recommendation. Filter returns a list of results (you can view querysets like that) and you want an object. Change filter by get or try filter()[0] – cdvv7788 Sep 27 '14 at 21:50
0

why this confusion so much.. you are getting the id there then, call the store like

new_track.save()
new_track.store.add(request.POST['store'])
Raja Simon
  • 10,126
  • 5
  • 43
  • 74
  • Thanks now the choice filed is saving but i have multiple choice entry then mysql give me this error `(1062, "Duplicate entry '4-5' for key 'tracks_id'")` –  Sep 27 '14 at 06:56
  • 1
    ``request.POST['store']`` is just a string, you cannot ``.add()`` as manytomany related object – doniyor Sep 27 '14 at 07:29