I have a contact information model/form which I want to add a contacttype foreign key to that should be displayed in a drop down menu:
models.py
class ContactType(models.Model):
contact_type = models.CharField(max_length=50)
class Contact(models.Model):
contact_name = models.CharField(max_length=200)
contact_email = models.CharField(max_length=200, validators=[validators.validate_email])
contact_type = models.ForeignKey(ContactType, default='General Enquiry')
forms.py
class ContactForm(forms.ModelForm):
# contact_type = forms.ModelChoiceField(queryset=ContactType.objects.all())
class Meta:
model = Contact
fields = ['contact_name', 'contact_email']
If I leave the contact_type variable where it is, I get the following error:
no such table: contact_contacttype
Here is my last migration:
dependencies = [
('contact', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='ContactType',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('contact_type', models.CharField(max_length=50)),
],
),
migrations.AddField(
model_name='contact',
name='contact_type',
field=models.ForeignKey(default='General Enquiry', on_delete=django.db.models.deletion.CASCADE, to='contact.ContactType'),
),
]
whereas if I move it into meta class (should I?) nothing renders into the template.
So my question is, is a foreign key the appropriate relationship? And if so, how should I add the ModelChoiceField to the ContactForm
Related
models.py
class Country(models.Model):
name = models.CharField(max_length=50, validators=[validate_name, ])
class Meta:
managed = False
db_table = 'countries'
def __str__(self):
return self.name
0001_initial.py
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Country',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=50, validators=[countries.validators.validate_name])),
],
options={
'db_table': 'countries',
'managed': False,
},
),
]
sql
(venv) michael#michael:~/Documents/PyCharmProjects/db/db$ python manage.py sqlmigrate countries 0001_initial
BEGIN;
--
-- Create model Country
--
-- (no-op)
COMMIT;
Could you tell me whether this sql reflects the model or not? If not, how can it happen? And will it produce in the database?
There is no sql to apply to the db because of managed = False.
That is, running migrate does not change the db.
I created a dummy project just to test the new field JSONField of Django but the column doesn't not appear to be created (I am using Postgresql).
class Author(models.Model):
name = models.CharField(max_length=50)
description = models.TextField()
slug = models.SlugField()
details = models.JSONField()
class Meta:
verbose_name = "Author"
def __str__(self):
return self.name
If i go to the database, the column is not created -- screenshot
When i go to the admin view page of the table Author i get the following error -- screenshot
The error in the admin panel is understandable: you cannot view a column that does not exist. Do you guys have the same error? I can't find this error with JSONField anywhere.
Thanks
Note: This is my first post.
EDIT I create all the fields in the same time. Migration file:
# Generated by Django 3.1.3 on 2020-11-20 10:35
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Author',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=50)),
('description', models.TextField()),
('slug', models.SlugField()),
('details', models.JSONField()),
],
options={
'verbose_name': 'Author',
},
),
]
Migrated with sucess:
Migrations for 'blog':
blog/migrations/0001_initial.py
- Create model Author
check that you migration was applied to the right database
I have the following models:
class Contact(models.Model):
email = models.EmailField()
class EventList(models.Model):
event_contacts = models.ManyToManyField(Contact, through=EventMembership)
class EventMembership(models.Model):
event_list = models.ForeignKey(EventList, null=True, on_delete=models.PROTECT)
event_contact = models.ForeignKey(Contact, null=True, blank=False, on_delete=models.PROTECT)
However, when applying migrations for EventMembership on a completely clean database I get the following error:
psycopg2.errors.InvalidForeignKey: there is no unique constraint
matching given keys for referenced table "contacts_contact"
class Migration(migrations.Migration):
initial = True
dependencies = [
('lists', '0001_initial'),
('contacts', '0002_auto_20200308_2253'),
]
operations = [
migrations.CreateModel(
name='EventMembership',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('event_contact', apps.utils.django_multitenant.fields.TenantForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to='contacts.Contact')),
('event_list', apps.utils.django_multitenant.fields.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to='lists.EventList'))
]
]
Table contacts_contact clearly has a unique constraint in id as the primary key.
What could be causing this error? / How do I debug this?
You just need to do it step by step. Now you are trying to create a foreign key relationship with a table that is not in the database yet. So comment everything out except for Contact model, apply migrations, then add EventList etc. If you are relying on the fact that Contact model goes first, well, it doesn't help in this case.
'authorid' is a foreign key to the Django 'User' model. After running 'makemigrations' and 'migrate' I can not see this field in the sqlite shell.
Here are my models,
class TopicModel(models.Model):
topic = models.CharField(max_length = 100)
topicAuthor = models.CharField(max_length = 100)
authorid = models.ForeignKey(User, related_name = 'id_of_author')
views = models.PositiveIntegerField(default = 0)
def __str__(self):
return self.topic
class PostModel(models.Model):
post = HTMLField(blank = True, max_length = 1000)
pub_date = models.DateTimeField('date published')
author = models.CharField(max_length = 30)
topicid = models.ForeignKey(TopicModel, related_name = 'posts')
def __str__(self):
return self.post
As you can see postmodel also has a foreign key to the topicmodel and there is no problem with this foreign key.
After migration the migrate file 0001_initial.py looks like this,
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import tinymce.models
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='PostModel',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('post', tinymce.models.HTMLField(blank=True, max_length=1000)),
('pub_date', models.DateTimeField(verbose_name='date published')),
('author', models.CharField(max_length=30)),
],
),
migrations.CreateModel(
name='TopicModel',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('topic', models.CharField(max_length=100)),
('topicAuthor', models.CharField(max_length=100)),
('views', models.PositiveIntegerField(default=0)),
('authorid', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='id_of_author', to=settings.AUTH_USER_MODEL)),
],
),
migrations.AddField(
model_name='postmodel',
name='topicid',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='posts', to='crudapp.TopicModel'),
),
]
In the sqlite shell the postmodel shows the field with the foreign key, which is topicid_id
sqlite> PRAGMA table_info(crudapp_postmodel);
0|id|integer|1||1
1|pub_date|datetime|1||0
2|author|varchar(30)|1||0
3|topicid_id|integer|1||0
4|post|text|1||0
But when I do the same with the topicmodel, the field with the foreign key doesn't exist, so there is no authorid field.
sqlite> PRAGMA table_info(crudapp_topicmodel);
0|id|integer|1||1
1|topic|varchar(100)|1||0
2|topicAuthor|varchar(100)|1||0
3|views|integer unsigned|1||0
Solution: As suggested by Alasdair I deleted the sqlitedb file and changed the fields from from topicid and authorid to topic and author.
Your current migration should create the foreign keys. My guess is that you updated the migration file after you had already created the crudapp_topicmodel table in the database.
If you don't have any important data yet, the easiest fix is to delete your sqlite file and rerun ./manage.py migrate.
I'm moving the field some_field from Model_A to a new Model_B, with a OneToOne relationship. Before deleting this field in Model_A, I want to copy the value from (the historical) Model_A to the newly created Model_B. The problem is that I cannot retrieve the field at migration time, since Model_A doesn't any longer contain some_field.
This is the error message I get when I try running my custom migration:
AttributeError: 'Model_A' object has no attribute 'some_field'
Models before changes:
class Model_A:
some_field = models.BooleanField(default=False)
some_other_field = models.BooleanField(default=False)
Models after changes:
class Model_A:
some_other_field = models.BooleanField(default=False)
class Model_B:
model_a = models.OneToOneField(Model_A, related_name='extension')
some_field = models.BooleanField(default=False)
Migration:
class Migration(migrations.Migration):
dependencies = [
('my_app', '0001_initial'),
]
def forwards_func(apps, schema_editor):
# This is where I try to get the "historical" Model_A
Model_A = apps2.get_model("my_app", "Model_A")
# And this is where I intend to copy the some_field values
for model_A_instance in Model_A.objects.all():
b = Model_B(model_a=model_A_instance)
# b gets created correctly, but the following step fails
b.some_field = modelA_instance.some_field
b.save()
operations = [
migrations.CreateModel(
name='Model_B',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('some_field', models.BooleanField(default=False)),
('model_a', models.OneToOneField(related_name='extension', to='my_app.Model_A')),
],
options={
},
bases=(models.Model,),
),
migrations.RunPython(forwards_func),
migrations.RemoveField(
model_name='model_a',
name='some_field',
),
]
I'm pretty much aware that I somehow have to get hold of a "historical" representation of Model_A (= the one currently in the database), but I thought that was what the apps2.get_model("my_app", "Model_A") part was for.
Any input on how to accomplish this? Or should I maybe split the migration into two, where the first one creates Model_B + copies the some_field values and the second one deletes the some_field field from Model_A?
Yes, you need to have historical representation of Model_A and it's pretty easy to retrieve it. Thats what apps passed into your function called by RunPython migration is for, so why are you using some apps2 insdead of apps here? Also, you should get your Model_B from same apps instance as Model_A is from. Your migration should look like that:
class Migration(migrations.Migration):
dependencies = [
('my_app', '0001_initial'),
]
def forwards_func(apps, schema_editor):
# This is where I try to get the "historical" Model_A
# here is change - using apps passed into forwards_func by RunPython instead of apps2
Model_A = apps.get_model("my_app", "Model_A")
Model_B = apps.get_model("my_app", "Model_B")
# And this is where I intend to copy the some_field values
for model_A_instance in Model_A.objects.all():
b = Model_B(model_a=model_A_instance)
b.some_field = modelA_instance.some_field
b.save()
operations = [
migrations.CreateModel(
name='Model_B',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('some_field', models.BooleanField(default=False)),
('model_a', models.OneToOneField(related_name='extension', to='my_app.Model_A')),
],
options={
},
bases=(models.Model,),
),
migrations.RunPython(forwards_func),
migrations.RemoveField(
model_name='model_a',
name='some_field',
),
]
Why are you using apps2 anyway? And what it is?