2015-07-26 3 views
1

Я пытаюсь создать Model и ModelForm с полями «имя» и «клиент», которые имеют следующие характеристики очистки и проверки. Я могу управлять каждым индивидуальным требованием, но не могу заставить их работать вместе.Django model/form clean, validate и unique

  • Аутентифицированного пользователь может ввести имя для элемента
  • элемента сохраняется с именем и принудительным к клиенту, который связан с учетной записью пользователя.
  • Имя очищается с помощью '' .join
  • Имя проверяется так, что (cleaned_name.lower(), клиент) является уникальным
    • EG (name.strip() Раскол().): Если " FOO BAR»существует связанный клиент пользователя, пользователь получит сообщение об ошибке, если они входят в„Foo бар“

Это довольно простая модель:

class Item(BaseModel): 
    class Meta: 
     unique_together = (("client", "name"),) 

    client = models.ForeignKey(Client,related_name='items',null=True,blank=False) 
    name = models.CharField(max_length=64, null=False, blank=False) 

    def clean_name(self): 
     return ' '.join(self.cleaned_data['name'].strip().split()) 

создает все элемент/обновления сделаны с помощью Django REST Framework:

class ItemSerializer(serializers.HyperlinkedModelSerializer): 
    class Meta: 
     model = Item 
     fields = ('id','name') 

    def create(self,validated_data): 
     item = Item.objects.create(name=validated_data['name'],client=self.context['request'].user.client) 
     item.save() 
     return item 

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

Tx.

+0

было бы приемлемо для вашего 'clean_name', чтобы преобразовать его в нижний регистр? например 'return '' .join (self.cleaned_data ['name']. lower() strip(). split())'. Тогда единственное ограничение объединения будет обрабатывать вашу проверку для вас. – Alasdair

+0

К сожалению, это не сработает, так как мне нужно сохранить заглавную запись, введенную пользователем. – user3802319

ответ

0

В итоге я получил следующее. Единственное предостережение в том, что я должен включить поле name_slug для хранения в целях сортировки.

models.py

class Item(BaseModel): 
    class Meta: 
     db_table = 'item' 
     ordering = ['name_slug'] 

    # relations 
    client = models.ForeignKey(Client,related_name='items',null=True,blank=False) 

    # attributes 
    name = models.CharField(max_length=64, null=False, blank=False) 
    name_slug = models.CharField(max_length=64, null=False, blank=True) 

    def clean(self): 
     self.name = ' '.join(self.name.strip().split()) 
     if Item.objects.filter(client=self.client,name__iexact=self.name).count() > 0: 
      raise ValidationError({'name': 'Name already exists. Please enter a different name'}) 

    def save(self, *args, **kwargs): 
     self.name_slug = '-'.join(self.name.split()).lower() 
     super(Item, self).save(*args, **kwargs) 

serializers.py

class ItemSerializer(serializers.HyperlinkedModelSerializer): 
    class Meta: 
     model = Item 
     fields = ('id','name','name_slug') 
     read_only_fields = ('name_slug',) 

    def validate(self, attrs): 
     attrs['client'] = self.context['request'].user.client 
     instance = Item(**attrs) 
     instance.clean() 
     return { k: getattr(instance,k) for k in attrs.keys()}