I would like to know how to set default values into a Django Array Field Model.
I have a TextChoices model named "GameType" :
class GameType(models.TextChoices):
'''
Enumeration of all different game types
'''
EVIL = 'evil', 'evil'
SOLOCOOP = 'solo', 'solo'
MULTI = 'multi', 'multi'
And in my Item model, I can choose in each mode my item is available. Then I have these lines :
game_types = ArrayField(
models.CharField(
default=GameType.SOLOCOOP,
max_length=40,
choices=GameType.choices
), default=default_item_game_types, null=False, blank=False)
Two things :
The first default key "GameType.SOLOCOOP" doesn't work
The default list doesn't work too
Here is my "default_item_game_types" function :
def default_item_game_types():
'''Default callable to avoid errors
'''
return list(GameType)
And in my CMS, I don't have my default values :
Screenshot of my Game types field
I tried many things and searched many solutions but nothing matched in my case.
Is there any response to fix my issues ?
Thanks for your time
Regards,
Steven
1: You need to set it like
self.SOLOCOOP = 'solo'
Can do this in a custom method or init if you know the defaults for it, that would be much easier than calling the custom method.
2:The default values are based on the Charfield as it is an Array of fields in some sense.
EDITED:
Just do the str_value then or better just do the key value for solar as you're already using it as choices in the parameter below.
Related
I am developing an app in Django.
I wanted to insert in my model an auto-incrementing alphanumerical unique ID field, having, by default, a fixed alphabetical part and an auto-incrementing numerical part. But I also want the availability to change, from admin section, this id to another alphanumerical one, with a different alphanumerical and numerical part.
I tryed to implement this, but it turned out that trying to implement such a field and making it the autofield of the model generates problems in my database.
So I am changing my aim: now I want to implement a time-based alphanumerical unique field with predefined aplphabetic part. Please note: I don't want to overwrite the django default id field, I just want to include in my model a field that gets as default value a unique customized alphanumerical value.
Here is what I did, in my models.py:
def return_timestamped_id():
prefix = "ITCH"
import time
this_time = time.time()
this_time = this_time *10000000
this_time = int(this_time)
timestamp = str(this_time)
default_value = prefix + timestamp
return(default_value)
class object_example(models.Model):
name = models.CharField(max_length=256, blank=True, null=True)
Id_generated = models.CharField(max_length=256, blank=False, null=False, unique=True, default=return_timestamped_id())
The problem is that, as I add objects to this model from the admin section, The
Id_generated is always the same.
I expected that the return_timestamped_id() function was called every time I add a new object. It is clear instead that is called just once and then the same return value is passed to the Id_generated of every new object.
How can I change my code in order to get a different timestamp every time a new object is added?
As you probably saw in the Django docs, you can use either a value or a callable as a default. If you use a callable (e.g. a function) then it will be called each time a default is needed.
The problem: you were passing a value because you were calling your function default=return_timestamped_id(). The function was being called once, when your module (models.py) was imported into the application.
The solution: pass the function itself default=return_timestamped_id
You can see in the django.models.Fields class the relevant code (comments mine):
class Field():
def __init__(self, ..., default=NOT_PROVIDED,...):
...
self.default = default # save the default as a member variable
...
def get_default(self):
"""Return the default value for this field."""
return self._get_default()
#cached_property
def _get_default(self):
if self.has_default():
if callable(self.default): # if it is callable, return it
return self.default
return lambda: self.default # else wrap in a callable
I'm trying to make a select box in the admin that shows a list of objects in the database, outside the current app. Here is my model
from typefaces.models import Typeface
class Word(models.Model):
text = models.CharField(max_length=200)
family_select = models.CharField(max_length=100, choices=Typeface.objects.all)
Unfortunately, Django tells me 'choices' must be an iterable (e.g., a list or tuple). But my attemps to make it iterable with iter() have yielded no success.
This is a completely wrong way to do it. Relationships between models should be specified using OneToOneFields, ForeignKeys (one-to-many field) and ManyToManyFields. You should just change the CharField to this:
family = models.ForeginKey(Typeface, related_name='words')
If you have a specific reason for not using the generally acceptable way, please elaborate on that further to get an answer for that.
I have the following model as an inline field in another model:
class route_ordering(models.Model):
route_id = models.ForeignKey(route, on_delete=models.CASCADE)
activity_id = models.ForeignKey(activity, on_delete=models.CASCADE)
day = models.IntegerField()
order = models.IntegerField()
And in the admin.py:
class RouteAdmin(admin.ModelAdmin):
inlines = (RouteOrderingInline,)
I would like to make "order" self-incrementing from one, so it will be auto filled when I go to the Django admin panel (in the first line order=1 , then order-2 etc.)
I know you can use Default to set an autofilled value, but I want it to increment by itself.
How can I do this?
I can't guarantee this will work, and I'm not able to test out right now, but I think you can pass in a generator to your default value arg.
define increment():
return range(1, 1000)
And wherever your passing in a default just call next(increment())
Sorry I can't provide a more detailed example, I'm writing this on my phone XD, but I think that should work.
class Model1(models.Model):
username = models.CharField(max_length=100,null=False,blank=False,unique=True)
password = models.CharField(max_length=100,null=False,blank=False)
class Model2(models.Model):
name = models.ForeignKey(Model1, null=True)
unique_str = models.CharField(max_length=50,null=False,blank=False,unique=True)
city = models.CharField(max_length=100,null=False,blank=False)
class Meta:
unique_together = (('name', 'unique_str'),)
I've already filled 3 sample username-password in Model1 through django-admin page
In my views I'm getting this list as
userlist = Model1.objects.all()
#print userlist[0].username, userlist[0].password
for user in userlist:
#here I want to get or create model2 object by uniqueness defined in meta class.
#I mean unique_str can belong to multiple user so I'm making name and str together as a unique key but I dont know how to use it here with get_or_create method.
#right now (without using unique_together) I'm doing this (but I dont know if this by default include unique_together functionality )
a,b = Model2.objects.get_or_create(unique_str='f3h6y67')
a.name = user
a.city = "acity"
a.save()
What I think you're saying is that your logical key is a combination of name and unique_together, and that you what to use that as the basis for calls to get_or_create().
First, understand the unique_together creates a database constraint. There's no way to use it, and Django doesn't do anything special with this information.
Also, at this time Django cannot use composite natural primary keys, so your models by default will have an auto-incrementing integer primary key. But you can still use name and unique_str as a key.
Looking at your code, it seems you want to do this:
a, _ = Model2.objects.get_or_create(unique_str='f3h6y67',
name=user.username)
a.city = 'acity'
a.save()
On Django 1.7 you can use update_or_create():
a, _ = Model2.objects.update_or_create(unique_str='f3h6y67',
name=user.username,
defaults={'city': 'acity'})
In either case, the key point is that the keyword arguments to _or_create are used for looking up the object, and defaults is used to provide additional data in the case of a create or update. See the documentation.
In sum, to "use" the unique_together constraint you simply use the two fields together whenever you want to uniquely specify an instance.
I'm defining a ChoiceField based on a model's datas.
field = forms.ChoiceField(choices=[[r.id, r.name] for r in Model.objects.all()])
However I'd like to prepend my options with an empty one to select "no" objects.
But I can't find a nice way to prepend that.
All my tests like :
field = forms.ChoiceField(choices=[[0, '----------']].extend([[r.id, r.name] for r in Model.objects.all()]))
Returns me a "NoneType object not iterable" error.
The only way I've found until now is the following :
def append_empty(choices):
ret = [[0, '----------']]
for c in choices:
ret.append(c)
return ret
And when I define my field :
forms.ChoiceField(choices=append_empty([[r.id, r.name] for r in
Restaurant.objects.all()]), required=False)
However I'd like to keep my code clean and not have that kind of horrors.
Would you have an idea for me ? :p
Thanks by advance.
An easy answer is to do:
field = forms.ChoiceField(choices=[[0, '----------']] + [[r.id, r.name] for r in Model.objects.all()])
Unfortunately, your approach is flawed. Even with your 'working' approach, the field choices are defined when the form is defined, not when it is instantiated - so if you add elements to the Model table, they will not appear in the choices list.
You can avoid this by doing the allocation in the __init__ method of your Form.
However, there is a much easier approach. Rather than messing about with field choices dynamically, you should use the field that is specifically designed to provide choices from a model - ModelChoiceField. Not only does this get the list of model elements dynamically at instantiation, it already includes a blank choice by default. See the documentation.
Since this question and its answer almost solved a problem I just had I'd like to add something. For me, the id had to be empty because the model didn't recognise '0' as a valid option, but it accepted empty (null=True, blank=True). In the initializer:
self.fields['option_field'].choices = [
('', '------')] + [[r.id, r.name] for r in Model.objects.all()]