Django: cannot add foreight key to User - python

I am using ldap to do authentication, just like Understanding Django-LDAP authentication.
My model is:
class MyFile(models.Model):
file = models.FileField(upload_to="files")
slug = models.SlugField(max_length=50, blank=True)
user = models.ForeignKey(User, unique=True)
But I cannot make migrations:
python src/manage.py makemigrations
You are trying to add a non-nullable field 'user' to myfile without a default;
we can't do that (the database needs something to populate existing rows).
Please select a fix:
1) Provide a one-off default now (will be set on all existing rows)
2) Quit, and let me add a default in models.py
Select an option:
Then I input datetime.date.today() and run python manage.py migrate
The error is:
File "/usr/local/lib/python2.7/dist-packages/django/db/models/fields/__init__.py", line 915, in get_prep_value
return int(value)
TypeError: int() argument must be a string or a number, not 'datetime.date'
Any idea? Thanks
UPDATE
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='MyFile',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('file', models.FileField(upload_to='files')),
('slug', models.SlugField(blank=True)),
('user', models.ForeignKey(User, blank=True, null=True)),
],
),
]
Error:
ValueError: Lookup failed for model referenced by field fileupload.MyFile.user: auth.User

You need to provide a default User ID for all the existing files. It has to be an existing User ID and an integer. It cannot be a datetime.date.
Or, if applicable, you can make the File->User link optional:
user = models.ForeignKey(User, blank=True, null=True)

Related

How to use a user as a ForeignKey in a Django model

I've got this model in my Django application:
class ClubSession(models.Model):
location = models.CharField(max_length=200)
coach = models.ForeignKey('auth.User', on_delete=models.CASCADE)
date = models.DateTimeField(default=now)
details = models.TextField()
def __str__(self):
return self.title
I can run python manage.py makemigrations club_sessions without issue but when I thn run python manage.py migrate club_sessions I get ValueError: Field 'id' expected a number but got 'username'. username is a superuser and already exists.
How do I resolve this?
This is the latest migration:
# Generated by Django 3.0.6 on 2020-05-28 15:07
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('club_sessions', '0004_auto_20200528_1450'),
]
operations = [
migrations.AlterField(
model_name='clubsession',
name='coach',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
),
migrations.AlterField(
model_name='clubsession',
name='location',
field=models.CharField(max_length=200),
),
]
By default Django lets a ForeignKey refer to the primary key of the target model. This also has some advantages to make relations more uniform.
If you really want to save the username in the ForeignKey, you can specify a to_field=… parameter [Django-doc] and let it refer to a column that is unique (the username of the default User model is unique), so we can refer to it with:
from django.conf import settings
class ClubSession(models.Model):
location = models.CharField(max_length=200)
coach = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
to_field='username'
)
date = models.DateTimeField(default=now)
details = models.TextField()
def __str__(self):
return self.title
You will need to remove the already existing migration and make a new one in order to migrate the database properly.
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.

Make Migrations on Django

I have a Django model which looks like this
class RedUsers(BaseModel):
user_email = models.EmailField(null=True, blank=True)
user_name = models.CharField(max_length=30, null=True, blank=True)
red_id = models.CharField(max_length=30, null=True, blank=True)
active = models.BooleanField(default=False)
def __str__(self):
return self.user_email
class Meta:
verbose_name_plural = "Red Users"
I want to add a new field
activation_key = models.CharField(max_length=40, null=True, blank=True)
I already have lots of data in this model and I can't drop the table, so I need to make migration manually.
I have tried adding the model from my 0001_initial.py file without luck
class Migration(migrations.Migration):
initial = True
dependencies = []
operations = [
migrations.CreateModel(
name='RedUsers',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', models.DateTimeField(auto_now_add=True)),
('modified', models.DateTimeField(auto_now=True)),
('user_email', models.EmailField(blank=True, max_length=254, null=True)),
('user_name', models.CharField(blank=True, max_length=30, null=True)),
('red_id', models.CharField(blank=True, max_length=30, null=True)),
('active', models.BooleanField(default=False)),
],
options={
'verbose_name_plural': 'RED Users',
},
),
migrations.AddField(
model_name='redusers',
name='activation_key',
field=models.CharField(blank=True, max_length=40, null=True, verbose_name='activation key'),
),
]
When I run
python manage.py migrate
It says Your models have changes that are not yet reflected in a migration, and so won't be applied.
I don't know what else to do
I want to add a new field
activation_key = models.CharField(max_length=40, null=True, blank=True)
I already have lots of data in this model and I can't drop the table,
so I need to make migration manually.
You don't need to. If you run makemigrations a second time, Django will detect that you added a field, and will make an extra migration file to add that field to the model.
You thus better here remove the AddField migration object from the migration file, and run python3 manage.py makemigrations.
It will make a new file, likely something that starts with 0002_….py, and it will take the first migration as dependency.
You can then run python3 manage.py migrate, and Django will add the field at the database level, and insert the name of the migration in the migration table.

Django FileField not respecting null=False parameter

I have a Django FileField which is set to not nullable. However it is behaving like it is nullable.
class Thing(models.Model):
document = models.FileField(null=False, blank=False)
thing_id = models.CharField()
# This does not raise but I would like it to
Thing.objects.create(thing_id='123')
edit: the migrations
class Migration(migrations.Migration):
dependencies = [
('data_source', '0002_auto_20190212_1913'),
]
operations = [
migrations.CreateModel(
name='Thing',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('document', models.FileField(upload_to='')),
('thing_id', models.CharField(default=None, max_length=200)),
],
options={
'abstract': False,
},
),
]
The problem is not with your field definition. It's got to do with validation when manually creating a model instance. You need to perform that full validation yourself, since you're not using a ModelForm.
Use this example:
from django.core.exceptions import ValidationError
thing = Thing(thing_id='123')
try:
thing.full_clean()
thing.save()
except ValidationError:
# Handle validation issues.
Read this section in the documentation: https://docs.djangoproject.com/en/2.1/ref/models/instances/#validating-objects
Quoting from there:
Note that full_clean() will not be called automatically when you call
your model’s save() method. You’ll need to call it manually when you
want to run one-step model validation for your own manually created
models
You can add the validation directly in your model overriding save() method:
class Thing(models.Model):
document = models.FileField(null=False, blank=False, default=None)
thing_id = models.CharField(max_length=200)
def save(self, *args, **kwargs):
self.full_clean()
super().save(*args, **kwargs)
By default null and blank are False. Link for every model field. Don't need to add those.
from django.db import models
class Thing(models.Model):
document = models.FileField()
thing_id = models.CharField()

Some issues with UUID while migrating from SQLite to Postgresql in Django 2.0

I am trying to migrate my Django 2.0.4 project from SQLite to PostgreSQL 10 following the steps described here, but I am having differents problems.
During the project I changed some Integer fields to UUID4 fields.
I managed to run python manage.py migrate --run-syncdb manually editing auto_increment migration file making changes of this type (see id field):
From
class Migration(migrations.Migration):
dependencies = [
('dumps', '0011_auto_20180608_1714'),
]
operations = [
migrations.CreateModel(
name='Report',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('data', models.DateTimeField(auto_now_add=True, verbose_name='Date')),
],
),
...
...
...
To
class Migration(migrations.Migration):
dependencies = [
('dumps', '0011_auto_20180608_1714'),
]
operations = [
migrations.CreateModel(
name='Report',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False, verbose_name='ID')),
('data', models.DateTimeField(auto_now_add=True, verbose_name='Date')),
],
),
...
...
...
Next, I commented all auto_increment files in which there was an AlterTable on uuid fields, but when I run python manage.py loaddata datadump.json I obtain the following error:
django.db.utils.ProgrammingError: Problem installing fixture 'C:\Users\djangoproject\datadump.json': Could not load myApp.Reservation(pk=10d00b08-bf35-469f-b53f-ec28f8b6ecb3): ERROR: column "reservation_id" is integer type but the expression is uuid type
LINE 1: UPDATE "myApp_reservation" SET "reservation_id" = '066cff3c-4b...
I think the issue here is that you have old migrations which refer to the int PK field column as an AutoField() before you made the change to use a UUIDField().
You may need to leave the id field as it was (perhaps reverse back your migrations to the point at which the swithc was made), and include a new field (and thus column of type uuid) named uuid in your Report model:
class Report(models.Model)
id = models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')
uuid = models.UUIDField(default=uuid.uuid4, editable=False, serialize=False, verbose_name='UUID')
data = models.DateTimeField(auto_now_add=True, verbose_name='Date')
...
Then re-run database migrations ... you'll likely hit some more migration errors but give me a shout and I can advise on where to go from there in the chat.
I understood where the error was.
The problem was in postgre table scheme: 'id' field had 'integer' type instead of 'uuid'. I converted it to 'uuid' and the import was successful.

Django Table already exist

Here is my Django Migration file.
When I run
python manage.py makemigrations/migrate
I get this error.
Error:-
django.db.utils.OperationalError: (1050, "Table 'tickets_duration' already exists")
I have dropped the database and running it but still get the same error.
class Migration(migrations.Migration):
dependencies = [
]
operations = [
migrations.CreateModel(
name='Duration',
fields=[
('Id', models.UUIDField(primary_key=True, db_column=b'duration_id', default=uuid.uuid4, serialize=False, editable=False)),
('duration', models.CharField(max_length=200, db_column=b'duration')),
],
),
migrations.CreateModel(
name='ErrorCount',
fields=[
('Id', models.UUIDField(primary_key=True, db_column=b'error_id', default=uuid.uuid4, serialize=False, editable=False)),
('error', models.CharField(max_length=200, db_column=b'error')),
],
),
migrations.CreateModel(
name='OutageCaused',
fields=[
('Id', models.UUIDField(primary_key=True, db_column=b'error_id', default=uuid.uuid4, serialize=False, editable=False)),
('outage_caused', models.CharField(max_length=200, db_column=b'outage_caused')),
],
),
migrations.CreateModel(
name='Pg',
fields=[
('Id', models.UUIDField(primary_key=True, db_column=b'pg_id', default=uuid.uuid4, serialize=False, editable=False)),
('pg_cd', models.CharField(max_length=200, db_column=b'pg_cd')),
],
),
migrations.CreateModel(
name='SystemCaused',
fields=[
('Id', models.UUIDField(primary_key=True, db_column=b'error_id', default=uuid.uuid4, serialize=False, editable=False)),
('system_caused', models.CharField(max_length=200, db_column=b'system_caused')),
],
),
migrations.CreateModel(
name='Tickets',
fields=[
('ticket_num', models.CharField(max_length=100, serialize=False, primary_key=True, db_column=b'ticket_id')),
('created_dt', models.DateTimeField(db_column=b'created_dt')),
('ticket_type', models.CharField(max_length=20, db_column=b'ticket_type')),
('addt_notes', models.CharField(max_length=1000, db_column=b'addt_notes')),
('row_create_ts', models.DateTimeField(default=datetime.datetime(2016, 2, 29, 16, 58, 31, 584733))),
('row_end_ts', models.DateTimeField(default=b'9999-12-31 00:00:00.00000-00', db_column=b'row_end_ts')),
('duration', models.ManyToManyField(to='tickets.Duration')),
('error_count', models.ManyToManyField(to='tickets.ErrorCount')),
('outage_caused', models.ManyToManyField(to='tickets.OutageCaused')),
try python manage.py migrate your_app --fake. This post talks about it. Django South - table already exists.
python manage.py migrate --fake-initial should work for django 2.2
This question is already answered here
You should run this:
python manage.py migrate <appname> --fake
temporary solution may be to comment the creation of existing table(tickets_duration).
class Migration(migrations.Migration):
dependencies = [
]
operations = [
#migrations.CreateModel(
# name='Duration',
# fields=[
# ('Id', models.UUIDField(primary_key=True, db_column=b'duration_id', default=uuid.uuid4, serialize=False, editable=False)),
# ('duration', models.CharField(max_length=200, db_column=b'duration')),
# ],
#),
....
....
version:-Django 3.X
If above solution doesn't work :
python manage.py migrate <appname> --fake
If it doesn't work then have a look at the migrations folder you will find that there will be some missing changes which u have done in models.py but somehow Django is unable to capture, so find it there and again do some changes (even a small) to that model fields and then use ,
py manage.py makemigrations app_name
py manage.py migrate app_name
or
py manage.py makemigration <appname> --fake
It is an inconsistent situation of Database.
You may do the followings:
Comment out the code for your last added model.
Run makemigrations and then migrate --fake, to get the record sync at present situation.
Now, uncomment your last added model, and run makemigrations again;
I had the same problem when using sqlite3 because of the way Django creates the third join table. From the docs,
Behind the scenes, Django creates an intermediary join table to represent the many-to-many relationship. 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 basically, the third table is created by concatenating the two table names. This doesn't work with sqlite3 because table names in sqlite3 are case insensitive.
The resolution is to add the db_table option when declaring your ManyToManyField.
models.ManyToManyField(to='tickets.Duration', db_table='_Duration')

Categories