Django - 在保存表单的同时创建m2m关系的对象

时间:2022-10-04 14:06:19

My models are as follows:

我的模型如下:

class Photo(models.Model):

  objects = PhotoManager()

  date = models.DateField()
  credit = models.CharField(max_length=60)
  sites = models.ManyToManyField(Site)
  tags = models.ManyToManyField('PhotoTag', related_name='photos')
  caption = models.CharField(max_length=255)
  timestamp = models.DateTimeField(auto_now=True)
  photo_src = models.ImageField()


class PhotoTag(models.Model):

  slug = models.CharField(max_length=255)

Relevant line from my PhotoUploadForm

我的PhotoUploadForm的相关行

tags = forms.CharField(max_length=250)

What I'm trying to do is take the tags field, split by comma it into a list, get_or_create them as PhotoTag objects, then add those to the Photo object in the current form. Probably in the form save method, right? Something like this (this is not working):

我要做的是取标签字段,用逗号分成一个列表,get_or_create它们作为PhotoTag对象,然后将它们添加到当前表单中的Photo对象。可能在表单保存方法中,对吧?像这样的东西(这不起作用):

def save(self, commit=True):

    photo = super(PhotoUploadForm, self).save(commit=False)

    tags = [x.strip() for x in photo.tags.split(',')]

    photo.tags = []

    for tag in tags:
      tag = PhotoTag.objects.get_or_create(slugify(tag))
      photo.tags.append(tag)

    if commit:
      photo.save()

    return photo

I think I have the principle correct, but the execution is not. I would appreciate guidance and learning the correct way to think about this!

我认为我的原则是正确的,但执行不是。我很感激指导和学习正确的思考方式!

Updated with error traceback:

更新了错误回溯:

Traceback:
File "/vagrant/default_env/lib/python3.4/site-packages/django/core/handlers/base.py" in get_response
  111.                     response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/vagrant/default_env/lib/python3.4/site-packages/django/contrib/auth/decorators.py" in _wrapped_view
  22.                 return view_func(request, *args, **kwargs)
File "/vagrant/projects/bluehorse/bluehorse/apps/photos/views.py" in create_form
  46.       photo = form.save(commit=False)
File "/vagrant/projects/bluehorse/bluehorse/apps/photos/forms.py" in save
  31.     tags = [x.strip() for x in photo.tags.split(',')]
File "/vagrant/default_env/lib/python3.4/site-packages/django/db/models/fields/related.py" in __get__
  1175.             through=self.field.rel.through,
File "/vagrant/default_env/lib/python3.4/site-packages/django/db/models/fields/related.py" in __init__
  831.                                  (instance, source_field_name))

Exception Type: ValueError at /admin/photos/create
Exception Value: "<Photo: Photo object>" needs to have a value for field "photo" before this many-to-many relationship can be used.

2 个解决方案

#1


1  

Edit:

编辑:

I misread you question sorry. You have a few problems here. The first is this line

我误解你的问题对不起。你在这里遇到一些问题。首先是这一行

[x.strip() for x in photo.tags.split(',')]

photo.tags is actually a ManyToMany here as

photo.tags实际上是这里的ManyToMany

photo = super(PhotoUploadForm, self).save(commit=False)

returns an unsaved Photo object. You might actually want to use

返回未保存的Photo对象。你可能真的想要使用

tags = [x.strip() for x in self.cleaned_data['tags'].split(',')]

because self.clean_data will contain the data in the form, and the Photo object won't have the data atatched until after you have called save on it.

因为self.clean_data将包含表单中的数据,并且Photo对象在您对其进行调用save之后才会获取数据。

You can't add ManyToMany's until you have actually created the object in the database, because behind the scenes a ManyToMany table looks roughly like this:

在实际在数据库中创建对象之前,不能添加ManyToMany,因为在幕后,ManyToMany表看起来大致如下:

class Photo_PhotoTag_M2M_table(models.Model):
    photo = models.ForeignKey(Photo)
    phototag = models.ForeignKey(PhotoTag)

In your PhotoUploadForm.save function, the Photo object actually gets created in the database when you do this line photo.save(). So you need to add your manytomany's after you have created to form.

在PhotoUploadForm.save函数中,当您执行此行photo.save()时,实际上会在数据库中创建Photo对象。因此,您需要在创建表单后添加manytomany。

(https://docs.djangoproject.com/en/1.7/topics/db/examples/many_to_many/#many-to-many-relationships)

(https://docs.djangoproject.com/en/1.7/topics/db/examples/many_to_many/#many-to-many-relationships)

#2


0  

I don't know how this works with forms but when overriding the save method for models, you can't access m2m fields directly, you must use the m2m_changed signal.

我不知道这对表单有什么用处,但是当覆盖模型的save方法时,你不能直接访问m2m字段,你必须使用m2m_changed信号。

I bet here the same is happening because the traceback is similar.

我打赌这里也是如此,因为追溯是类似的。

#1


1  

Edit:

编辑:

I misread you question sorry. You have a few problems here. The first is this line

我误解你的问题对不起。你在这里遇到一些问题。首先是这一行

[x.strip() for x in photo.tags.split(',')]

photo.tags is actually a ManyToMany here as

photo.tags实际上是这里的ManyToMany

photo = super(PhotoUploadForm, self).save(commit=False)

returns an unsaved Photo object. You might actually want to use

返回未保存的Photo对象。你可能真的想要使用

tags = [x.strip() for x in self.cleaned_data['tags'].split(',')]

because self.clean_data will contain the data in the form, and the Photo object won't have the data atatched until after you have called save on it.

因为self.clean_data将包含表单中的数据,并且Photo对象在您对其进行调用save之后才会获取数据。

You can't add ManyToMany's until you have actually created the object in the database, because behind the scenes a ManyToMany table looks roughly like this:

在实际在数据库中创建对象之前,不能添加ManyToMany,因为在幕后,ManyToMany表看起来大致如下:

class Photo_PhotoTag_M2M_table(models.Model):
    photo = models.ForeignKey(Photo)
    phototag = models.ForeignKey(PhotoTag)

In your PhotoUploadForm.save function, the Photo object actually gets created in the database when you do this line photo.save(). So you need to add your manytomany's after you have created to form.

在PhotoUploadForm.save函数中,当您执行此行photo.save()时,实际上会在数据库中创建Photo对象。因此,您需要在创建表单后添加manytomany。

(https://docs.djangoproject.com/en/1.7/topics/db/examples/many_to_many/#many-to-many-relationships)

(https://docs.djangoproject.com/en/1.7/topics/db/examples/many_to_many/#many-to-many-relationships)

#2


0  

I don't know how this works with forms but when overriding the save method for models, you can't access m2m fields directly, you must use the m2m_changed signal.

我不知道这对表单有什么用处,但是当覆盖模型的save方法时,你不能直接访问m2m字段,你必须使用m2m_changed信号。

I bet here the same is happening because the traceback is similar.

我打赌这里也是如此,因为追溯是类似的。