When I read a project, there I saw the params for create the field:
class Task(models.Model):
title = models.CharField('标题', max_length=100)
description = models.TextField('描述')
completed = models.BooleanField('是否完成', default=False)
create_date = models.DateTimeField('创建时间', auto_now_add=True)
Such as: title = models.CharField('标题', max_length=100)
I don't understand the 标题 here has what function.
The first parameter of a Field in django is the verbose name
A human-readable name for the field. If the verbose name isn’t given, Django will automatically create it using the field’s attribute name, converting underscores to spaces
You will have couple of fields , one default value for that model column , one max length of that model column , alias name for that model column , and if that column is primary that will also be there
it's the field name displayed in the admin panel forms or if you use ModelForm for you website forms
Related
I'm using Django 3.1.3 and working with an existing postgresql database. Most of the models and fields names of this DB are badly chosen and/or way too long. Most of the time its easy to change them with some handy Django options like so :
class NewModelName(models.Models):
new_field_name = models.CharField(max_length=50, db_column='old_field_name')
class Meta:
managed=False
db_table='database_old_table_name'
But let say I want to change a M2M field name and the corresponding model name. I'd like to have something like :
class Foo(models.Models):
new_m2m_field_name = models.ManyToManyField('RelatedModel', blank=True, db_column='old_m2m_field_name')
class Meta:
managed=False
db_table='foo_old_table_name'
class RelatedModel(models.Models):
name = models.CharField(max_length=50)
class Meta:
managed=False
db_table='related_model_old_table_name'
But if I do that, Django will throw an error stating
django.db.utils.ProgrammingError: relation "foo_new_m2m_field_name" does not exist. It is like it is ignoring the db_column option. Any idea how I could get to a similar result ?
Thanks!
From Django documentation regarding ManyToManyField
ManyToManyField.db_table The name of the table to create for storing
the many-to-many data. If this is not provided, Django will assume a
default name based upon the names of: the table for the model defining
the relationship and the name of the field itself.
Also depending on column names (non standard names) in original database you might have to define through model ( pivot table) as through table
You will probably need to manually define the Through model (that Django would otherwise implicitly create behind the scenes) in order to make it unmanaged.
class Foo(models.Models):
new_m2m_field_name = models.ManyToManyField(
"RelatedModel",
blank=True,
db_column="old_m2m_field_name",
through="FooRelatedJoin", # <- new
)
class Meta:
managed = False
db_table = "foo_old_table_name"
class RelatedModel(models.Models):
name = models.CharField(max_length=50)
class Meta:
managed = False
db_table = "related_model_old_table_name"
class FooRelatedJoin(models.Models): # <- all new
foo = models.ForeignKey(Foo)
related_model = models.ForeignKey(RelatedModel)
class Meta:
managed = False
db_table = "foo_join_table"
You could add a property db_table (link)
linking to the previous table, named foo_old_table_name in your case.
According to the doc,
By default, this table name is generated using the name of the
many-to-many field and the name of the table for the model that
contains it
So for the field new_m2m_field_name, the previous table making the link was named : old_field_name_database_old_table_name.
Hence :
new_field_name = models.CharField(max_length=50, db_column='old_field_name', db_table='old_field_name_database_old_table_name')
The option through could be changed too, but I do not think it is necessary if the modifications on names are coherent.
I've got a 'set' model, which has a many to many relationship to the 'Item' model. The issue is that 'set' is a subclass of Item (everything is an Item on the project).
It works fine, until I try to create a 'through' relationship to an intermediary model called 'order', which I'm defining so I can order the 'Items' inside the 'Set'.
When I try to define the relationship, I get this error:
ERRORS:
curate.Set.items_: (fields.E001) Field names must not end with an underscore.
curate.order.set: (fields.E304) Reverse accessor for 'order.set' clashes with reverse accessor for 'order.item'.
HINT: Add or change a related_name argument to the definition for 'order.set' or 'order.item'.
I've tried adding a related_name to Order.set, and also Order.item, but it doesn't seem to work. I can get migrations to be happy, but then when I try to migrate I get an error saying:
ValueError: Cannot alter field curate.Set.items into curate.Set.items - they are not compatible types (you cannot alter to or from M2M fields, or add or remove through= on M2M fields)
models.py
class Item(models.Model, AdminVideoMixin):
title = models.TextField(max_length=5000)
slug = models.SlugField(max_length=5000, default='')
...
class Video(Item):
video_embed = EmbedVideoField(max_length=500)
...
class Article(Item):
authors = models.CharField(max_length=10000)
...
class Podcast(Item):
categories = models.CharField(max_length=5000, null=True, blank=True,)
...
class Episode(Item):
author = models.CharField(max_length=10000, null=True,blank=True,)
...
class Set(Item):
items = models.ManyToManyField(Item, related_name='setItems', max_length=5000, through='Order')
front_page = models.BooleanField(max_length=300, blank=False, default=False, null=False)
class order(models.Model):
item = models.ForeignKey(Item, on_delete=models.CASCADE,)
set = models.ForeignKey(Set, on_delete=models.CASCADE,)
order = models.CharField(max_length=64, default=0)
You can't change a ManyToMany field to use a through relationship once it has been created. This is because the through table will now contain extra fields that cannot be populated by the standard ManyToMany relationship (this is the same reason why you can't use add, clear, remove, delete when using a through table). You will need to create a new ManyToMany field on Set that uses the through relationship and then populate it with the data from Set.items before removing Set.items.
Docs on through tables
If you need to have the new field called items you can do the following:
Change items to items_old in the Set model, you will need to change the related_name as well if you would like that to be the same (make and run the migration)
Add the new items field with the through relationship (make and run the migration)
Populate the new items field with the data from items_old
set_items = Set.objects.filter(items__isnull=False)
Order.objects.bulk_create([
Order(item=item, set=s)
for s in set_items
for item in s.items.all()
])
Remove items_old from Set
NB - Like katoozi mentioned in his comment, you probably shouldn't have fields named set
I'm trying to create 'unique_together' meta for a model, but instead of two fields from the current model, one of them is a field of other model (which is a foreign key in the current model):
I want the 'Item' model to have unique_together that contains both its 'identifier' field and the Spec's container_id. a Spec is foreign key in 'Item'.
Tried something like this, but I get "Unresolved reference spec..."
class Spec(BaseModel):
title = models.CharField(max_length=200)
identifier = models.IntegerField(unique=True)
container = models.ForeignKey(Container, related_name='specs')
class Item(SubmittalsBaseModel, BaseModel, DirtyFieldsMixin):
title = models.CharField(max_length=200)
identifier = models.CharField(max_length=200, unique=True)
spec = models.ForeignKey(Spec, related_name='items')
class Meta:
container_id = spec.container
unique_together = ('identifier', 'container_id')
You can't do that.. (at least I think)..
The unique_together clause is directly translated to the SQL unique index. And you can only set those on columns of a single table, not a combination of several tables.
You can add validation for it yourself though, simply overwrite the validate_unique method and add this validation to it.
Docs: http://docs.djangoproject.com/en/dev/ref/models/instances/#django.db.models.Model.validate_unique
I am trying to make my ID in class Animal unique, so that it automatically increments without a user having to add data into the filed (so the filed is hidden), but I can't figure out how to do it.
Right now I have this in my models.py:
class Animal(models.Model):
id = models.CharField(max_length=100, blank=True, unique=True, default=uuid.uuid4, primary_key=True)
name = models.CharField(max_length=200)
Which in my mind will have to make id unique, but currently it doesn't do anything.
Here is my serialisers.py for reference:
class AnimalSerialiser(serializers.HyperlinkedModelSerializer):
doctor = DoctorSerealiser(read_only=True)
class Meta:
model = Animal
fields = ('id' , 'name' , 'gender' , 'breed' , 'adoption' , 'vaccines', 'doctor')
As other people have mentioned in the comments, you're defining your model wrong. Django adds an auto-incrementing field by default. Take a look at the docs for more information - https://docs.djangoproject.com/en/1.9/topics/db/models/#automatic-primary-key-fields.
You really just need:
class Animal(models.Model):
name = models.CharField(max_length=200)
and then you can still access that field like animal.id.
And UUID's are totally different than an auto-incrementing ID. See the wiki - they're basically just strings that are nearly impossible to generate duplicates of.
The Django docs describe how to query reverse m2m fields:
https://docs.djangoproject.com/en/1.8/topics/db/queries/#many-to-many-relationships
According to this answer we should use related_name as the first argument in the query.
But I'm having trouble making this work. (I'm using Django 1.8.5). Here are my example models:
class Nlpneutralfeature(models.Model):
neutral_feature = models.CharField(u'found word', max_length=255, default='')
class Userproject(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name="project", verbose_name=("owner"))
monitoring_words = models.ManyToManyField(Nlpneutralfeature, null=True, blank=True, related_name="monitoringwords")
name = models.CharField(u'Название проекта', unique=True, max_length=255)
So, to get all Nlpneutralfeature rows that belong to Userproject where Userproject.name == '48', I need to do:
Nlpneutralfeature.objects.filter(userproject__monitoringwords__name='48')
But this does not work. The error I get is: Cannot resolve keyword *'userproject'* into field.
So, Django cannot understand that 'userproject' is lowercased model name Userproject.
Now, this is working:
Nlpneutralfeature.objects.filter(monitoringwords__name='48')
How does Django know that monitoringwords is related_name? No error is strange to me, sicne there is no monitoringwords field in the Nlpneutralfeature model!
Note the phrasing in the Django docs:
The name to user for the relation from the related object back to this one. It's also the default value for related_query_name (the name to use for the reverse filter name from the target model).
In your example, the "target model" is Nlpneutralfeature. When you set related_name = 'monitoringwords' on the ManyToManyField Userproject.monitoringwords, it tells Django to use that related_name to refer from Nlpneutralfeature model objects back to the corresponding Userproject model objects.
Correspondingly, if you had declared Userproject.monitoringwords with related_name = 'foo', the way to query for all Nlpneautralfeatures belonging to project 48 would be: Nlpneautralfeature.objects.filter(foo__name='48').
the related_name here is so you can get your Userproject models related to an Nlpneutralfeature model.
eg:
nf = Nlpneutralfeature.objects.get(neutral_feature="XXX")
# From here you can get all Userprojects related to this nf like this:
userProjects = nf.monitoringwords.all()
if you didn't declared a related_name then you had to do it like this:
nf = Nlpneutralfeature.objects.get(neutral_feature="XXX")
# From here you can get all Userprojects related to this nf like this:
userProjects = nf.Userproject_set.all()
i think you understaned this property by inverse.. in my opinion i thing you should declare it here like this: related_name="user_projects"
in summary, related_name is to use when you want to get the current models(where you declare your M2M relationship) from the related model.