How to work with unsaved many-to-many relations in django?

前端 未结 3 1167
孤街浪徒
孤街浪徒 2021-01-12 23:51

I have a couple of models in django which are connected many-to-many. I want to create instances of these models in memory, present them to the user (via custom met

相关标签:
3条回答
  • 2021-01-13 00:04

    I think that using django forms may be the answer, as outlined in this documentation (search for m2m...).

    Edited to add some explanation for other people who might have the same problem:

    say you have a model like this:

    from django.db import models
    from django.forms import ModelForm
    
    class Foo(models.Model):
        name = models.CharField(max_length = 30)
    
    class Bar(models.Model):
          foos = models.ManyToManyField(Foo)
    
      def __unicode__(self):
          return " ".join([x.name for x in foos])
    

    then you cannot call unicode() on an unsaved Bar object. If you do want to print things out before they will be saved, you have to do this:

    class BarForm(ModelForm):
        class Meta:
            model = Bar
    
    def example():      
        f1 = Foo(name = 'sue')
        f1.save()
        f2 = foo(name = 'wendy')
        f2.save()
        bf = BarForm({'foos' : [f1.id, f2.id]})
        b = bf.save(commit = false)
        # unfortunately, unicode(b) doesn't work before it is saved properly,
        # so we need to do it this way: 
        if(not bf.is_valid()):
            print bf.errors
        else:
            for (key, value) in bf.cleaned_data.items():
                print key + " => " + str(value)
    

    So, in this case, you have to have saved Foo objects (which you might validate before saving those, using their own form), and before saving the models with many to many keys, you can validate those as well. All without the need to save data too early and mess up the database or dealing with transactions...

    0 讨论(0)
  • 2021-01-13 00:10

    I would add a field which indicates whether the objects are "draft" or "live". That way they are persisted across requests, sessions, etc. and django stops complaining.

    You can then filter your objects to only show "live" objects in public views and only show "draft" objects to the user that created them. This can also be extended to allow "archived" objects (or any other state that makes sense).

    0 讨论(0)
  • 2021-01-13 00:19

    Very late answer, but wagtail's team has made a separate Django extension called django-modelcluster. It's what powers their CMS's draft previews.

    It allows you to do something like this (from their README):

    from modelcluster.models import ClusterableModel
    from modelcluster.fields import ParentalKey
    
    class Band(ClusterableModel):
        name = models.CharField(max_length=255)
    
    class BandMember(models.Model):
        band = ParentalKey('Band', related_name='members')
        name = models.CharField(max_length=255)
    

    Then the models can be used like so:

    beatles = Band(name='The Beatles')
    beatles.members = [
        BandMember(name='John Lennon'),
        BandMember(name='Paul McCartney'),
    ]
    

    Here, ParentalKey is the replacement for Django's ForeignKey. Similarly, they have ParentalManyToManyField to replace Django's ManyToManyField.

    0 讨论(0)
提交回复
热议问题