2010-06-16 4 views
1

У меня есть следующие модели:Проверка на ManyToManyField перед сохранением в models.py

class Application(models.Model): 
users = models.ManyToManyField(User, through='Permission') 
folder = models.ForeignKey(Folder) 

class Folder(models.Model): 
company = models.ManyToManyField(Compnay) 

class UserProfile(models.Model): 
user = models.OneToOneField(User, related_name='profile') 
company = models.ManyToManyField(Company) 

То, что я хотел бы сделать, это проверить, имеет ли один из пользователей Заявке той же компании, как заявка (через папку). Если это так, экземпляр приложения не должен быть сохранен.

Проблема в том, что ManyToManyFields не обновляются до тех пор, пока не будет получен сигнал «после сохранения».
Единственным вариантом является новый сигнал m2m_changed. Но я не уверен, как я откат назад, что уже произошло.
Другим вариантом было бы переписать функцию сохранения (в models.py, потому что я говорю об этом здесь), но я не уверен, как получить доступ к содержимому manytomanyfield.
Наконец-то я прочитал что-то о переписывании функции сохранения в администраторе модели в admin.py, однако я все равно не знаю, как вы получите доступ к содержимому manytomanyfield.

Я искал это везде, но ничего, с которым я сталкиваюсь, похоже, работает на меня.
Если что-то неясно, сообщите мне.

Благодарим за помощь!
Heleen

+0

Почему у вас есть ManyToManyField для UserProfile.company и Folder.company? Может ли пользователь/папка быть в нескольких компаниях? В этом случае я предлагаю переименовать поля в «компании». –

+0

Компании действительно были бы лучшим именем. Мне нужно, чтобы пользователи были сотрудниками нескольких компаний.Папка может принадлежать нескольким компаниям. Оба случая, вероятно, будут исключениями, но они по-прежнему должны быть возможны. – Heyl1

+0

Я не уверен, как вы можете это сделать с помощью проверки модели, но с проверкой формы он должен работать, как в моем отредактированном примере. Вы можете зарегистрировать свою собственную форму, которая будет использоваться администратором. –

ответ

1

Поскольку я не получил ответа от Botondus, я решил задать новый вопрос в Django Users Google Group и, наконец, получил ответ от jaymz.

Я понял, что метод Ботондса был правильным способом сделать это, он просто не работал. Причина, по которой он не работает в этом случае, заключается в том, что я использую модель Through для поля, на котором я хотел бы выполнить проверку. Из-за некоторой обратной связи я получил ранее заданный вопрос, который я собрал, что сначала экземпляр приложения сохранен, а затем экземпляры ManyToMany сохранены (я считаю, что это правильно, но исправьте меня, если я ошибаюсь). Поэтому я подумал, что если бы я выполнил проверку в поле ManyToMany в модели Through, это не помешало бы сохранить экземпляр приложения. Но на самом деле это предотвращает это.

Так что если у вас есть встроенный ManyToMany поле в администраторе вашей модели, и вы хотели бы сделать проверку на этом поле необходимо указать чистую функцию в сквозной модели, как это:

admin.py 
class PermissionInline(admin.TabularInline): 
    form = PermissionForm 
    model = Permission 
    extra = 3 

forms.py 
class PermissionForm(forms.ModelForm): 
    class Meta: 
     model = Permission 

    def clean(self): 
     cleaned_data = self.cleaned_data 
     user = cleaned_data['user'] 
     role = cleaned_data['role'] 
     if role.id != 1: 
      folder = cleaned_data['application'].folder 
      if len(filter(lambda x:x in user.profile.company.all(),folder.company.all())) > 0: # this is an intersection 
       raise forms.ValidationError("One of the users of this Application works for one of the Repository's organisations!") 
     return cleaned_data 

Если проверка приводит к ошибке NOTHING (ни экземпляр приложения, ни многие экземпляры пользователей) не сохраняется, и вы получаете возможность исправить ошибку.

+0

Благодарим вас за то, что вы вернулись и рассказали нам, как вы это сделали. У меня много головной боли. – Tiago

0

forms.py

class ApplicationForm(ModelForm): 
    class Meta: 
     model = Application 

    def clean(self): 
     cleaned_data = self.cleaned_data 
     users = cleaned_data['users'] 
     folder = cleaned_data['folder'] 
     if users.filter(profile__company__in=folder.company.all()).count() > 0: 
      raise forms.ValidationError('One of the users of this Application works in one of the Folder companies!') 
     return cleaned_data 

admin.py

class ApplicationAdmin(ModelAdmin): 
    form = ApplicationForm 

Редактировать: Заменено начальная (неправильно) модельный пример проверки с проверкой формы.

+0

Когда я сделал profile__company__in в кавычках, я получил синтаксическую ошибку. Когда я его недооцениваю, я получаю: экземпляр «Приложение» должен иметь значение первичного ключа, прежде чем использовать отношения «многие-ко-многим». Спасибо за вашу помощь до сих пор! – Heyl1

+0

Кроме того, я ожидал бы, что «profile__company__in» = self.folder.company.all() приведет к тому, что компании пользователя будут подмножеством компаний этой папки. Или я ошибаюсь, и это приводит к пересечению, как и предполагалось? – Heyl1

+0

Я уверен, что это будет пересечение. Но вы можете проверить это, чтобы быть уверенным. –