3

Currently, I have a Django project containing a model called Event which has several properties, one of them being full_name.

from django.db import models


class Event(models.Model):
    description = models.CharField(blank=False, max_length=200)
    full_name = models.CharField(blank=False, null=True, max_length=200, unique=True)

What I want to acchieve is to prevent users from making two events in which one would be called MyEvent and the other would be called myevent, so I want the name to not be case sensitive. Furthermore, I come from a country with some funny letters, like š. Users are so used to computer systems not supporting these letters that I want to also prevent the existance of two events, one called šoo and the other soo.

Basically, I have a function myfunction and want to have a model constraint such that for each instance of the model, the value myfunction(instance.full_name) is unique.

My first idea, which sort of works, is to have a model form with a clean full name function:

def clean_full_name(self):
    return myfunction(self.cleaned_data.get('full_name'))

This works. However, I now have a view in which I want to display the full names of all events, and here, I want to display the original names. Using my approach, this is impossible (the funcion is one-way only). Is there an elegant solution to this?

5xum
  • 5,250
  • 8
  • 36
  • 56

3 Answers3

3

You can have another field which is basically the slug of the name. Infact, I believe it is not a good idea to have the name as a unique field (but i should clarify that i do not know your requirement).

Basically, the validation on the slug field ensures uniqueness. Also, you can just keep the slug field hidden from all forms, etc..

Example:

>>> from django.utils.text import slugify
>>> slugify(u"śtack Overflow")
u'stack-overflow'
>>> slugify(u"stack Overflow")
u'stack-overflow'
>>> slugify(u"stack  Overflow")
u'stack-overflow'
>>> slugify(u"stack \t Overflow")
u'stack-overflow'
>>> slugify(u"stack \n Overflow")
u'stack-overflow'

A few of these combinations map to the same slug - which ensures uniqueness for the broad usecases.

karthikr
  • 97,368
  • 26
  • 197
  • 188
  • As far as I understand, this `slugify` is simply a replacement for `myfunction`, so I don't see how this answers my question... – 5xum Jul 30 '15 at 13:12
  • Would this not address the issue of the accented characters ? But sure, you can have that validation in your `myfunction` rather than another field. I dont understand your confusion – karthikr Jul 30 '15 at 13:16
  • The accented characters are not the issue. I already know which strings I want to equate. The question is how can I do this without destroying the original full name... – 5xum Jul 30 '15 at 13:17
  • Well, thats the reason i recommend a separate slug field which would allow you to retain your original full name. Basically the slug is a helper field to ensure bad data does not creep in. I don't think it is a replacement for the myfunction. I will let you think a little more on this. – karthikr Jul 30 '15 at 13:23
  • Ah, there has been a misunderstanding. As I stated before: the `slugify` is the replacement for `myfunction`. Not the slugfield itself – 5xum Jul 30 '15 at 13:25
  • Oh.. I was just demonstrating the functionality of slugification just to make the point (Sorry for not being clear). I was talking about the [`SlugField`](https://docs.djangoproject.com/en/1.8/ref/models/fields/#slugfield) at the model level though. – karthikr Jul 30 '15 at 13:34
  • I still don't think this answer adresses something: how could it be possible to validate both fields and then only show errors (in the forms) for one of them? – 5xum Jul 30 '15 at 15:03
  • See http://stackoverflow.com/questions/31727564/validating-two-fields-at-the-same-time for a discussion on that. – 5xum Jul 30 '15 at 15:13
3

An idea would be to implement a case insensitive unique constraint on the field.

Possible answers in:

Community
  • 1
  • 1
n__o
  • 1,620
  • 15
  • 18
  • Both these answers rely heavily on the PostGres behind the app, so I am looking for a more database-independent solution... – 5xum Jul 30 '15 at 13:15
  • 2
    Then maybe you could go with updating clean_full_name, but, instead of returning the cleaned string, perform a validation and leave the string unchanged? `if MyModel.objects.filter(full_name__iexact=thestring).exists():raise ValidationError; return the_string`? – n__o Jul 30 '15 at 16:08
0

Just save both full_name and clean_full_name in the database, and make clean_full_name unique.

You can validate the full_name field by putting the validation code in a property setter. Have a look at this blog for details.

Rob
  • 3,418
  • 1
  • 19
  • 27
  • But where do I run the validation? I mean, the does the EventForm then have a clean_full_name_unique field? But I want that to be filled automatically. And If the form will not respond correctly if a non-unique name is given... – 5xum Jul 30 '15 at 12:59
  • @5xum You can set clean_full_name in model to be non editable, unique and overwrite model's save method to automatically fill it. Then edit validation of the model to catch validation error from clean_full_name and pass it to full_name. Edit: I would not overwrite property setter if you use clean_fulll_name only for validation/identification purposes. – Piotr Jaszkowski Jul 30 '15 at 13:08
  • @PiotrJaszkowski What do you mean by "catch validation error from clean_full_name and pass it to full_name"? How is this even possible? – 5xum Jul 30 '15 at 14:24