IntegrityError: column slug is not unique - python

i'm studying django by tangowithdjango tutorials, and there on 7-th chapter I've stacked.
i'm trying to include a slug field in my model and override save method to make it all working. After migrate I have an integrity error.
models.py:
class Category(models.Model):
name = models.CharField(max_length=128, unique=True)
views = models.IntegerField(default=0)
likes = models.IntegerField(default=0)
slug = models.SlugField(unique=True)
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
super(Category, self).save(*args, **kwargs)
class Meta:
verbose_name_plural = "Categories"
def __unicode__(self):
return self.name
Thanks!

Listen to the error. You have the slug attribute specified as unique, but you must have the same slug value for multiple instances of your Category class.
This can easily happen if you add a unique attribute column to a table that already has data, because any constant default you use will automatically break the unique constraint.
To make the migration...
You're going to need to first migrate to just add the slug-field, without specifying it as unqiue, then set a unique slug for each Category in the database, then you can add the unique constraint and migrate again.
Open your most recent migration in the migrations directory of your app and edit the line that looks similar to
migrations.AddField(
model_name='category',
name='slug',
field=models.SlugField(unique=True),
preserve_default=False,
),
so that it is just
migrations.AddField(
model_name='category',
name='slug',
field=models.SlugField(null=True, blank=True),
preserve_default=False,
),
Then run the migration with python manage.py migrate (if you're using django 1.7. Otherwise use South for migrations), then open the django shell with python manage.py shell, import your Category model and run
for cat in Category.objects.all():
cat.slug = cat.name
cat.save()
This will set the slug for each category to be the category's name. Now, assuming all names are unique, you can create your migrations again and successfully migrate so that the DB will force unique slugs.

Related

It is impossible to add a non-nullable field 'id' to video without specifying a default

This is my models.py
from ast import Delete
from email.policy import default
from django.db import models
from django.contrib.auth.models import User
class Video(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
title=models.CharField(max_length=100, null=False)
description=models.TextField(max_length=1000,null=True)
video=models.FileField(upload_to="video/%y",null=False)
def __str__(self):
return self.title
class Euser(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
phone = models.CharField(max_length=10,null=True)
birthdate = models.DateField(null=True,)
profile_pic = models.ImageField(null=True, )
cover_pic = models.ImageField( null=True, upload_to="images/%y")
def __str__(self):
return self.phone
when i try to makemigrations
It is impossible to add a non-nullable field 'id' to video without specifying a default. This is because the database needs something to populate existing rows.
Please select a fix:
Provide a one-off default now (will be set on all existing rows with a null value for this column)
Quit and manually define a default value in models.py.
This error occurs...
Please suggest me what should i do
and also suggest me about any changes in model
For a particular model, in the database, if records already exist and add new fields to the model then it shows such an error. To overcome this problem, you have to set the new field as blank=True and null=True or you can set some default value to the new field using default='some_value'.

Why leads deletion of UUIDField to Django SystemCheckError

I've been building a Django website and included a UUID field "customer_id" in my initial "Customer" model. Finally, I decided to drop it. But when I try to delete it from my models.py, Django throws
SystemCheckError: System check identified some issues:
ERRORS:
<class 'accounts.admin.CustomerAdmin'>: (admin.E035) The value of 'readonly_fields[1]' is not a callable, an attribute of 'CustomerAdmin', or an attribute of 'accounts.Customer'.
Here is the code of models.py
from django.db import models
import uuid
# Create a base model to make sure we keep track of creation and edits
class ModelBaseClass(models.Model):
date_created = models.DateTimeField(auto_now_add=True, null=True)
date_modified = models.DateTimeField(auto_now=True, null=True)
class Meta:
abstract = True
# Create your models here.
class Customer(ModelBaseClass):
customer_id = models.UUIDField(default=uuid.uuid4, #this is the field i try to drop
editable=False,
unique=True)
name = models.CharField(max_length=200, null=True)
email = models.CharField(max_length=200, null=True)
def __str__(self):
return self.name
What I tried so far:
I suspect that this could be related to existing data or some other dependencies. So...
I deleted the sqlite database, deleted all migration files and ran
"python manage.py makemigrations" and "python manage.py migrate".
I ran python manage.py flush.
I also tried to change the editable=False to editable=True and migrate before dropping,
but it didn't change anything.
It's perhaps also worth mentioning that my "Customer" model a relation to another model.
Could someone explain me why Django is preventing me from deleting this field and how to resolve this?
Thanks! :)
Could someone explain me what's going on and how to resolve this?
As the error says, you have a model admin named CustomerAdmin. Indeed:
<class 'accounts.admin.CustomerAdmin'>: (admin.E035) The value of 'readonly_fields[1]' is not a callable, an attribute of 'CustomerAdmin', or an attribute of 'accounts.Customer'.
For the readonly_fields, it lists the customer_id, but since that field is no longer available, it raises the error.

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.

Limit custom migration to one model

I have decided to implement registration option for my website, I used this tutorial (signup with confirmation part). Following this material I have created Profile module to hold some info. Everything (seems to be) working now, but the problem is that old profiles throws relatedObjectDoesNotExist error. According to these two questions (first, second) I need to make a migration to create profiles for old user accounts. I tried to follow this doc as suggested in one of the answers, but then I try to run a migration I get following error: KeyError: ('stv', 'bazinekaina')
stv is the name of my app and bazinekaina is the name of the next model after the one I need to create profiles.
How to limit migration to only the first model?
My relevant models.py code:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
email_confirmed = models.BooleanField(default=False)
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
email = models.EmailField(max_length=254)
#receiver(post_save, sender=User)
def update_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.get(user=instance)
instance.profile.save()
#next model, this one throws an error, despite the fact it should not be touched at all
class BazineKaina(models.Model):
#bazines kainos modelis
bazka = models.DecimalField(max_digits=5, decimal_places=2)
data = models.DateField(auto_now=False, auto_now_add=True)
def __str__(self):
return str(self.bazka)
class Meta:
verbose_name_plural = "Bazinė kaina"
get_latest_by = 'data'
Migration file crated after using python manage.py makemigrations --empty stv command, named 0001_initial.py:
from django.db import migrations, models
def sukurti_profilius(apps, schema_editor):
Profile = apps.get_model("stv", "Profile")
for user in Profile.objects.all():
Profile.objects.get_or_create(user=user)
class Migration(migrations.Migration):
dependencies = [
]
operations = [
]
How and what I should fix to stop migrations from applying to the unrelated models (and throwing error)?
Sorry if it is basic question, but whole django is still very new to me.
If your migration is named 0001_initial then it means that you don't have a migration that actually creates the table for the profile model.
Remove that migration and run:
python manage.py makemigrations stv
python manage.py makemigrations stv --empty --name create_profiles
Then you should have a file 0002_create_profiles.py and put the logic to create profiles there.

Django - Slugs - Key (slug)=() is duplicated

just started fooling around with Django and came across a link here on how to create slugs. I was told to perform the following changes to an existing model:
from django.template.defaultfilters import slugify
class Category(models.Model):
name = models.CharField(max_length=128, unique=True)
views = models.IntegerField(default=0)
likes = models.IntegerField(default=0)
slug = models.SlugField(unique=True)
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
super(Category, self).save(*args, **kwargs)
def __unicode__(self):
return self.name
This worked out pretty well until I tried to migrate the database using:
python manage.py makemigrations
The above asked for a default value so following the guide, I gave it ''. Then:
python manage.py migrate
The above returned "DETAIL: Key (slug)=() is duplicated."
I'm not entirely sure why this happened. Perhaps it's because I'm adding a new field that is unique and I can't populate it with ''? If so, what do I have to do in order to populate the database?
The documentation explains how to migrate in these circumstances. A quick summary:
create the field without unique=True
create a migration with a RunPython function that iterates through all Categories and calls save on them, which will populate the slug
create a final migration which sets unique=True.
Actually i found an easier way to override the admin filter lists, that fixed my error of duplicated fields, So you can filter the fields in the admin panel to get all the duplicated fields and rename them ... and then migrate .. and it will work after removing all the duplication..
first create custom_filter.py file and include this code in it(assuming that you have a field with name slug)
from django.contrib.admin import SimpleListFilter
class DuplicatSlugFilter(SimpleListFilter):
"""
This filter is being used in django admin panel.
"""
title = "Duplicates"
parameter_name = "slug"
def lookups(self, request, model_admin):
return (("duplicates", "Duplicates"),)
def queryset(self, request, queryset):
if not self.value():
return queryset
if self.value().lower() == "duplicates":
return queryset.filter().exclude(
id__in=[slug.id for slug in queryset.distinct("slug").order_by("slug")]
)
Then add those lines to the admin.py file:
from .custom_filter import DuplicatSlugFilter
class CategoryAdmin(admin.ModelAdmin):
list_filter = (DuplicatSlugFilter,)
admin.site.register(Category, CategoryAdmin)
Good Luck

Categories