When I want to create new object from product I got this error:
slugify() got an unexpected keyword argument 'allow_unicode'
This is my models:
class BaseModel(models.Model):
created_date = models.DateTimeField(auto_now_add=True)
modified_date = models.DateTimeField(auto_now=True,)
slug = models.SlugField(null=True, blank=True, unique=True, allow_unicode=True, max_length=255)
class Meta:
abstract = True
class Product(BaseModel):
author = models.ForeignKey(User)
title = models.CharField()
# overwrite your model save method
def save(self, *args, **kwargs):
title = self.title
# allow_unicode=True for support utf-8 languages
self.slug = slugify(title, allow_unicode=True)
super(Product, self).save(*args, **kwargs)
I also ran the same pattern for other app(blog) ,and there I didn't run into this problem.
What's wrong with this app?
Since the slugify function is working in the other apps, it means that you use a different function that, at least in that file is referenced through the slugify identifier. This can have several reasons:
you imported the wrong slugify function (for example the slugify template filter function [Django-doc];
you did import the correct one, but later in the file you imported another function with the name slugify (perhaps through an alias or through a wildcard import); or
you defined a class or function named slugify in your file (perhaps after importing slugify).
Regardless the reason, it is thus pointing to the "wrong" function, and therefore it can not handle the named argument allow_unicode.
You can resolve that by reorganizing your imports, or giving the function/class name a different name.
Upgrade Django, that argument allow_unicode introduced in the version 1.9, or call the function without that argument.
Related
I am writing an API in Django Rest Framework- when using the POST method to create a new object, if the 'done' field is True and the 'done_date' is Null, I would like the 'done_date' to automatically be set to current time. Here's what I tried to do, overriding the save method in my models:
In models.py
from django.db import models
from django.utils import timezone
class Task(models.Model):
title = models.CharField(max_length=100)
done = models.BooleanField(default=False)
author_ip = models.GenericIPAddressField()
created_date = models.DateTimeField(default=timezone.now)
done_date = models.DateTimeField(null=True, blank=True)
class Meta:
ordering = ('id',)
def __str__(self):
return '{} - {}'.format(self.pk, self.title)
def save(self, *args, **kwargs):
if self.done and not self.done_date:
self.done_date = timezone.now
super(Task, self).save(*args, **kwargs)
However, this throws a "TypeError when calling Task.objects.create(). This may be because you have a writable field on the serializer class that is not a valid argument to Task.objects.create(). You may need to make the field read-only, or override the TaskSerializer.create() method to handle this correctly."
Now, I am fairly certain that it's related to timezone.now in the save method, could someone advise me on how to proceed? I apologise if it is a basic question, thanks!
All you have to do is to call the timezone.now() function (with the parenthesis)
alternatively, you could use: auto_now=True and set editable=True
I have created a (kind of) singleton to put all the app parameters in my database:
class SingletonModel(models.Model):
def save(self, *args, **kwargs):
self.pk = 1
super(SingletonModel, self).save(*args, **kwargs)
#classmethod
def load(cls):
return cls.objects.all().get()
class Meta:
abstract = True
class AppParameters(SingletonModel, models.Model):
DEFAULT_BALANCE_ALERT_THRESHOLD = models.PositiveIntegerField(default=5)
# other parameters...
It worked pretty well, until I tried to use one of these parameters in a default attribute of a model field:
class Convive(models.Model):
balance_alert_threshold = models.IntegerField(
default=AppParameters.load().DEFAULT_BALANCE_ALERT_THRESHOLD,
blank=True,
null=True)
This seemed to work too, but when I use a script to reinitialise local data, the first manage.py migrate produce a DoesNotExist since my Singleton does not exist yet.
It happens because of a file importing Convive model.
How would you solve this?
Is there a way to "delay" the evaluation of the default field?
Thanks.
EDIT
After posting this, I think that if my code processes db queries at import time, something may be wrong with it...
Create a method that returns the default value,
def get_default_balance_alert_threshold():
return AppParameters.load().DEFAULT_BALANCE_ALERT_THRESHOLD
then use that method as your default.
class Convive(models.Model):
balance_alert_threshold = models.IntegerField(
default=get_default_balance_alert_threshold,
blank=True,
null=True,
)
I have a Django model defined as below:
class Category(models.Model):
name = models.CharField(max_length=100, unique=True)
slug = models.SlugField(unique=True)
Although both defined as uniqe, django admin allows me to add categories like "python", "Python", "PYTHON". I know this is the default behavior.
To prevent this i have created a clean() method in Category models as follows:
def clean(self, *args, **kwargs):
from django.core.exceptions import ValidationError
slug = slugify(self.name.lower())
r = Category.objects.filter(slug=slug)
print("size")
print(r.count())
if r:
raise ValidationError("Category with this name already exists. Try again with a new name.")
self.slug = slug
super(Category, self).clean(*args, **kwargs)
It works for most of the cases. But lets say database already has Python category and if i try to add Python again, it will show me two errors one from clean() method and one from validate_unique() method. Here is how it looks.
I want to display only one message is there a way to prevent it. Is there any way to override this behavior or something. Thanks in advance.
From docs:
To assign exceptions to a specific field, instantiate the ValidationError with a dictionary, where the keys are the field names.
if r:
raise ValidationError({'name': ["Category with this name already exists.",]})
I am using PyCharm 4.5.2, Django 1.8.2.
If I define a class as:
class User(models.Model):
first_name = models.CharField(max_length=256)
last_name = models.CharField(max_length=256)
slug = models.SlugField(max_length=256, unique=True, default=make_slug)
def make_slug(self):
return self.first_name + self.last_name[0]
The IDE highlights default=make_slug with make_slug being undefined. The interpretter agrees and when the development server tries to refresh it exits with status 1 and the error NameError: name 'make_slug' is not defined.
Because it's just the name of a callable, I can't pass arguments. So if I define the function outside the class (to move into a higher scope and be defined) I can't use the class properties. I have read some suggestions that use lambdas but from the Django documentation that is wrong:
Note that lambdas cannot be used for field options like default
because they cannot be serialized by migrations. See that
documentation for other caveats.
What is the proper way to define a callable for default values in a model.
You shouldn't use this method to set your default value, rather than override the save method of the model and use it there. For example:
class User(models.Model):
first_name = models.CharField(max_length=256)
last_name = models.CharField(max_length=256)
slug = models.SlugField(max_length=256, unique=True, default=uuid.uuid1)
def make_slug(self):
return self.first_name + self.last_name[0]
def save(self, *args, **kwargs):
self.slug = self.make_slug()
super().save(*args, **kwargs)
You get this error
NameError: name 'make_slug' is not defined.
because you refer to make_slug before you defined it. If you moved the make_slug function above the slug field, then you wouldn't get that error.
However, it isn't possible to pass any arguments to the callable that you use as the default, so that won't work either. You can't get around that restriction by using a model method as you are trying.
If you need access to the model instance to calculate the default, then setting the value in the save() method as ruddra suggests is a good idea. Note that you might want to check whether or not the model has a primary key, so that you only create the slug when you first create the instance.
I'm trying to build a web service, but I'm stuck with my models. I have made a Model "User" and it has a ListField() as photos, "Photo" is an embedded document. But while saving this user object I get an error as :
Traceback (most recent call last):
File "E:\Challenge\trial\services\workspace\Service\src\appservices\trial.py",
line 7, in <module>
likedBy=["Name1", "Name2", "Name3", "Name4"]))
File "E:\Challenge\trial\Python27\lib\site-packages\djangotoolbox\fields.py",
line 253, in __init__
super(EmbeddedModelField, self).__init__(*args, **kwargs)
TypeError: __init__() got an unexpected keyword argument 'likedBy'
Below is my models file:
from django.db import models
from djangotoolbox.fields import ListField, EmbeddedModelField
class User(models.Model):
username = models.CharField(max_length=100, blank=False, unique = True)
fname = models.CharField(max_length=100, blank=False)
lname = models.CharField(max_length=100, blank=True)
photos = ListField() #embedded list of photos uploaded by users
created = models.DateTimeField(auto_now_add=True)
def __unicode__(self):
return self.name
class Photo(EmbeddedModelField):
description = models.TextField()
link = models.TextField()
like = models.IntegerField
likedBy = ListField()
def __unicode__(self):
return self.name
And the way I'm trying to save the User object is:
user = User(username="username", fname="Harshal", lname="Tripathi")
user.photos.append(Photo(description="This is a great photo uploaded for trial", link="http://image.com/images/user_photo.jpg", like="365", likedBy=["Name1", "Name2", "Name3", "Name4"]))
user.save()
This looks to me like nothing more than a normal Python issue. You've subclassed from EmbeddedModelField, but you've not overridden the init method in your subclass. As a result, when you instantiate that class providing arguments specific to your subclass, those are being fed directly to the base class's init, which is then bombing out.
At a glance at Django docs, you'll want to override init and process your class-specific args/kwargs and pass any generic/common arguments up to the base class (snippet from the docs below the following example).
I'm not a Django dev, and do not have time to get it installed and setup, but based on your provided code above, I would expect the following to work unless there's something inherent to Django that I'm not privy to and don't see at a glance in the docs.
from django.db import models
from djangotoolbox.fields import ListField, EmbeddedModelField
class User(models.Model):
username = models.CharField(max_length=100, blank=False, unique = True)
fname = models.CharField(max_length=100, blank=False)
lname = models.CharField(max_length=100, blank=True)
photos = ListField() #embedded list of photos uploaded by users
created = models.DateTimeField(auto_now_add=True)
def __unicode__(self):
return self.name
class Photo(EmbeddedModelField):
description = models.TextField()
link = models.TextField()
like = models.IntegerField
likedBy = ListField()
def __init__(self, link=None, like=None, likedBy=None, *args, **kwargs):
super(Photo, self).__init__(*args, **kwargs)
self.link = link or self.link
self.like = like or self.like
self.likedBy = likedBy or self.likedBy
def __unicode__(self):
return self.name
Writing a field subclass¶
When planning your Field subclass, first give some thought to which
existing Field class your new field is most similar to. Can you
subclass an existing Django field and save yourself some work? If not,
you should subclass the Field class, from which everything is
descended.
Initializing your new field is a matter of separating out any
arguments that are specific to your case from the common arguments and
passing the latter to the __init__() method of Field (or your parent
class).
In our example, we’ll call our field HandField. (It’s a good idea to
call your Field subclass Field, so it’s easily identifiable
as a Field subclass.) It doesn’t behave like any existing field, so
we’ll subclass directly from Field:
from django.db import models
class HandField(models.Field):
description = "A hand of cards (bridge style)"
def __init__(self, *args, **kwargs):
kwargs['max_length'] = 104
super(HandField, self).__init__(*args, **kwargs)