user4079217
user4079217

Reputation:

how to save Many to Many relationship in django

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()

Upvotes: 4

Views: 16756

Answers (5)

Brian
Brian

Reputation: 416

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

Upvotes: 2

doniyor
doniyor

Reputation: 37934

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)

Upvotes: 6

Raja Simon
Raja Simon

Reputation: 10315

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'])

Upvotes: 0

cdvv7788
cdvv7788

Reputation: 2099

Maybe:

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

Let me know how it goes

Upvotes: 0

jibreel
jibreel

Reputation: 359

new.stores.all()

returns all stores linked to the object.

Upvotes: 0

Related Questions