How to add unique_together with generic foreign key in Django - python

I am not sure if I am doing it wrong or there is some issue when handling unique constraint when working with GenericForeign Relations in Django.
When I try to save an object (in Admin for example) I get unique constraint error (raises 500) form database but not ValidationError on Admin (UI).
Below is my code snippet,
I have one generic relation model as below,
class Targeting(models.Model):
TARGETING_CHOICES = (
('geo', "Geo targeting"),
('other', "Other targeting"),
)
targeting_type = models.CharField(max_length=64, choices=TARGETING_CHOICES, null=False)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
class Meta:
unique_together = ('content_type', 'object_id', 'targeting_type')
And my other model using it is,
class MyModel(models.Model):
name = models.CharField(max_length=60, db_index=True)
targeting = GenericRelation('Targeting')
Exception Raised:
duplicate key value violates unique constraint "mymodel_targeting_targeting_type_0dff10ee_uniq"
DETAIL: Key (targeting_type, content_type_id, object_id)=(geo, 18, 188) already exists.
Is there something wrong with way I implemented it ? or something is not meant to used like this ?
Any sort of help is really appreciated. Thanks

You won't receive ValidationError here, because it can't be validated without additional query and django won't create that query by itself. If you need to have that validation, you need to write it by yourself.

Related

django.db.utils.OperationalError: (1071, 'Specified key was too long; max key length is 767 bytes') with unique_togther field

I am having the same issue as the user from this post, however, all of the proposed solutions did not work for me. I am using MySQL 8.0.24 with Django 3.1.
Similar to them, I had a model without a unique_together field as shown below
class Show(models.Model):
english_name = models.CharField(max_length=400)
kanji_name = models.CharField(max_length=200, blank=True)
romanji_name = models.CharField(max_length=400, blank=True)
show_type = models.CharField(max_length=100, blank=True)
# a bunch of other fields...
class Meta:
verbose_name_plural = 'Series'
ordering = ('-created',)
unique_together = ['english_name', 'kanji_name', 'romanji_name', 'show_type']
def __str__(self):
return self.english_name
It was only until I changed class Meta to this
class Meta:
verbose_name_plural = 'Series'
ordering = ('-created',)
unique_together = ['english_name', 'kanji_name', 'romanji_name', 'show_type']
That I started receiving this error whenever I migrated my database.
django.db.utils.OperationalError: (1071, 'Specified key was too long; max key length is 3072 bytes')
I followed the steps in the post I linked above to ensure the utf8 was used, I was able to confirm that the dataset was using that character set, but it didn't resolve my issue. Is there anything else I can do to ensure that the unique_together field can be used?
I just decided to get rid of that field and instead check the database using exists() whenever uploading a spreadsheet of data to ensure that duplicate entries aren't made.

Django DRF (De-)Serializer not working for me?

I'm stumled upon a case I don't understand.
I have two related models:
class Course(models.Model):
code = models.CharField(max_length=10, default='')
semester = models.CharField(max_length=10, default='')
class Meta:
unique_together = [['code', 'semester']]
and:
class StudentWork(models.Model):
code = models.CharField(max_length=10, default='')
course = models.ForeignKey(Course,on_delete=models.CASCADE, related_name='student_works')
deadline = models.DateTimeField(blank=True)
In the StudentWorkSerializer I'd like to expand a course field into [code, semester]:
class CourseNaturalSerializer(serializers.ModelSerializer):
class Meta:
model = Course
fields = ['code', 'semester']
class StudentWorkWithCourseSerializer(serializers.ModelSerializer):
course = CourseNaturalSerializer(read_only=True)
class Meta:
model = StudentWork
fields = ['code', 'course', 'deadline']
This works nicely for GET, e.g. I receive this:
{'code': 'HW1', 'course': {'code': 'T101', 'semester': 'S20'}, 'deadline': '2020-09-04T23:59:00+03:00'}
but this does not work for POST:
POST /studentworks json=dict(code='HW2', course={"code": "T101", "semester": "S20"}, deadline="2020-09-04T23:59")
says in the stacktrace:
django.db.utils.IntegrityError: NOT NULL constraint failed: botdb_studentwork.course_id
So this looks to me that {"code": "T101", "semester": "S20"} does not de-serialize into Course object and it's id is not passed to StudentWork's create?
What should I do?
Thanks in advance!
UPDATE:
I was asked if read_only=True on the related field serializer is intentional?
If I don't set it, I get:
'{"course":{"non_field_errors":["The fields code, semester must make a unique set."]}}'
which makes me thinking that it wants to create a new Course for me (Since code and semester are declared unique_together) at the time I want to create a StudentWork. Which I don't want.
If I than change, say, semester to S21 in the POST data, I get:
AssertionError: The `.create()` method does not support writable nested fields by default.
Write an explicit `.create()` method for serializer `botdb.serializers.StudentWorkWithCourseSerializer`, or set `read_only=True` on nested serializer fields.
So hence my confusion - I can't figure out how to prevent it from attempting to create a new Course, and just use an existing in a related field.
You can consider passing just course_id in POST.

How to insert data into a relational one to one table in django?

I have a UserProfile table which is in relation with the default Django User table. Here's how it looks.
class UserProfile(models.Model):
user = user.OneToOneField(User, on_delete=models.CASCADE)
section = models.CharField(max_length=255, blank=True)
year = models.IntegerField(null=True, blank=True)
course = models.CharField(max_length=255, blank=True)
qrcode = models.CharField(max_length=255, blank=True)
present = models.BooleanField(default=False)
I am trying to insert the data into the UserProfile table using the Django Shell.
from users.models import UserProfile
a = UserProfile(qrcode="hello")
a.save()
This is how I have always known to insert data into tables, it has always worked. BUT when i try to do this in UserProfile model. I get this exception. NOT NULL constraint failed: users_userprofile.user_id. Which in turn is caused by the following exception Error in formatting: RelatedObjectDoesNotExist: UserProfile has no user.
I somewhat understand that I somehow need to supply a user instance. But I am clueless as to how. Can someone please help me.
Firstly you need to create User.
u1 = User(username='user1')
u1.save()
Create a UserProfile. Pass the ID of the “parent” object as this object’s ID:
v1 = UserProfile(user=u1, ....)
v1.save()
refer this
You need to create your User first
user = User.objects.create(username='user')
and then you can do:
user_profile = UserProfile.objects.create(user=user, ...)

Django reference a Model by foreign key or a different field

I am using Django REST Framework. I have two models, Sites and Statuses.
class Sites(models.Model):
site_id = models.AutoField(primary_key=True)
status = models.ForeignKey(Statuses, models.DO_NOTHING, blank=True, null=True)
class Statuses(models.Model):
status_id = models.AutoField(primary_key=True)
description = models.CharField(max_length=255, blank=True, null=True, unique=True)
class Meta:
managed = True
db_table = 'Statuses'
I would like to be able to perform a GET on sites, and have the Statuses.description field returned (instead of Statuses.status_id). Also, I would like it so that either status_id or description may be used interchangeably in a POST to create a new site. Where does this type of functionality belong (serializer, models, etc...)?
I know I can accomplish the first part of my question by adding a property to the Sites model and then referencing this field in the Sites serializer.
#property
def status(self):
return self.row_status.description
However I thought the convention of a Model is that it should be a 1:1 representation of the database table. Is there a better way to do this?
This fits well in the serializer, like this:
class SitesSerializer(serializers.ModelSerializer):
description = serializers.CharField(source='status.description')
class Meta:
model = Sites
fields = ('site_id', 'description')
(But the status field should probably not have null=True set.)

Django 1.7 foreign key queryset

I encountered a problem with Django 1.7. When I want make my migration I raise this exception :
Models aren't loaded yet.
I tried solution said here but it doesn't work.
I saw this solution but I can't how do it with my models.
Error is due to person_type field on UserProfile Class. When I removed it migrations works.
class Typo_model(BaseModel):
key = models.CharField(max_length=32, db_index=True)
text = models.CharField(max_length=255)
class UserProfile(AbstractUser, BaseModel):
person_type = models.ForeignKey(Typo_model, queryset =
Typo_model.objects.filter(cle="person_type"), verbose_name="Person type")
I don't think you can set queryset on a ForeignKey. Purhaps limit_choices_to is what you are looking for. https://docs.djangoproject.com/en/1.7/ref/models/fields/#django.db.models.ForeignKey.limit_choices_to
Like this:
person_type = models.ForeignKey(
Typo_model,
limit_choices_to={'cle': 'person_type'}
)

Categories