Django FOREIGN KEY constraint failed - django

My app is a shopping cart. I have a function in views.py that is triggered when someone adds an item to the cart. The function checks if the user has an active order (one that is in the cart but hasn't been paid for).
But the code fails at `user_order, status = Order.objects.get_or_create(owner=user_profile, is_ordered=False)
#login_required()
def add_to_cart(request, **kwargs):
#get the user profile
user_profile = get_object_or_404(UserProfile, user=request.user)
#filter products by id
producto = Producto.objects.filter(id=kwargs.get("pk", "")).first()
#create OrderItem, of the selected product
order_item, status = OrderItem.objects.get_or_create(producto=producto)
if status == False: #adds one to the order_item
order_item.quantity += 1
order_item.save()
print(order_item.quantity)
#create order associated with the user
user_order, status = Order.objects.get_or_create(owner=user_profile, is_ordered=False)
user_order.items.add(order_item)
#print(user_order.items.all()) #queries the items
#print(user_order)
#date is not beign added
# generate a reference code
user_order.ref_code =random.randint(0,100000)
user_order.save()
return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
Relevant models:
class Order(models.Model):
fecha_reparto = models.OneToOneField(DiasDeReparto, on_delete=models.CASCADE, default= 1)
order_nodo = models.OneToOneField(Nodo, on_delete=models.CASCADE, default= 1)
ref_code = models.CharField(max_length=15)
owner = models.ForeignKey(UserProfile, on_delete=models.CASCADE)
is_ordered = models.BooleanField(default=False)
items = models.ManyToManyField(OrderItem)
date_ordered = models.DateTimeField(null=True)
def get_cart_items(self):
return self.items.all()
def get_cart_total(self):
return sum([item.producto.precio * item.quantity for item in self.items.all()])
def __str__(self):
return self.ref_code
class UserProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
class OrderItem(models.Model):
producto = models.OneToOneField(Producto, on_delete=models.SET_NULL, null = True)
quantity = models.IntegerField(default=1)
is_ordered = models.BooleanField(default=False)
date_added = models.DateTimeField(auto_now = True)
date_ordered = models.DateTimeField(null=True)
def __str__(self):
return self.producto.nombre

The problem can be solved with something like this:
try:
Order.objects.get(owner=user_profile)
except:
Order.objects.create(fecha_reparto=dia_reparto[0], order_nodo=nodo[0], ref_code="asdas", owner=user_profile, is_ordered=False, date_ordered=datetime.datetime.now())
But I don't get why get_or_create doesn't work

On your Order model you have a few related model fields and in the get_or_create you are not specifying any defaults. The get or create needs the required values to input if creating and you have a few related fields which are required. That will also explain why the try and except works because you add the fields when creating in the except.
defaults = {fecha_reparto: dia_reparto[0], order_nodo: nodo[0]......}
user_order, status = Order.objects.get_or_create(owner=user_profile, is_ordered=False, defaults=defaults)

Use id instead model instace in this line:
user_order, status = Order.objects.get_or_create(owner=user_profile, is_ordered=False)
So it should look like this:
user_order, status = Order.objects.get_or_create(owner_id=user_profile.pk, is_ordered=False)
It worked for me with similar problem.

Related

how to handle concurrency of bookmark system in django?

I tried to implement bookmark system for product,
when users click bookmark button, it will be recorded in his bookmark table,
and update bookmark count field in Product Model. However I faced DB Lock
when there is too many request at the same time. Also, I realized that when users
add or delete bookmark at the same time, there will be concurency issues like,
users can not read Product Information or Bookmark count or DB Lock..
How to handle concurrency in my situation? I know the exclusive lock but
it will lower the performance.. please help me..
here are my codes
class Bookmark(models.Model):
_id = models.AutoField(primary_key=True, editable=False)
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='bookmark_user')
def __str__(self):
return str(self.user)
class BookmarkItems(models.Model):
_id = models.AutoField(primary_key=True, editable=False)
user = models.CharField(max_length=255, null=True, blank=True)
image = models.CharField(max_length=255, null=True, blank=True)
bookmark = models.ForeignKey(Bookmark, on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
def image_preview(self):
if self.image:
return mark_safe('<img src="{0}" width="75" height="75" />'.format(self.image))
else:
return '(No image)'
def __str__(self):
return str(self.product)
#api_view(['POST'])
#permission_classes([IsAuthenticated])
def addBookmark(request):
user = request.user
user_id = request.data['user']
product_id = request.data['product_id']
image = request.data['image']
product = Product.objects.get(_id=product_id)
with transaction.atomic():
bookmark = Bookmark.objects.get_or_create(user=user)
Product.objects.filter(_id=product_id).update(
bookmark_count = F('bookmark_count') + 1
)
BookmarkItems.objects.create(
user = user_id,
image = image,
bookmark=bookmark[0],
product=product,
)
return Response({'success':'The bookmark has been created.'})
#api_view(['DELETE'])
#permission_classes([IsAuthenticated])
def deleteBookmark(request, pk):
user =request.user.id
with transaction.atomic():
Product.objects.filter(_id=pk).update(
bookmark_count = F('bookmark_count') - 1
)
BookmarkItems.objects.filter(user=user, product=pk).delete()
return Response({'success': 'The bookmark has been deleted.'})

(1062, "Duplicate entry '81CLZECZRW' for key 'orders_orderitem.orders_orderitem_orderItem_ID_7d6cd69b_uniq'") on Django Rest Framework

I am trying to generate a uniq OrderItem_ID during the order create api. But, it generates the above error as django.db.utils.IntegrityError:
The first api is always successful from the postman, but in the second call I tried changing different products for creating the order, but I am getting this unique id order.
I have to remove the order_items from db , to create a new order_item object otherwise I get this unique error.
I am sending data like this.
My model:
import random
import string
# Create your models here.
def id_generator(size=10, chars=string.ascii_uppercase + string.digits):
return ''.join(random.choice(chars) for _ in range(size))
class Order(models.Model):
ORDER_STATUS = (
('To_Ship', 'To Ship',),
('Shipped', 'Shipped',),
('Delivered', 'Delivered',),
('Cancelled', 'Cancelled',),
)
user = models.ForeignKey(User, on_delete=models.CASCADE, blank=True)
order_status = models.CharField(max_length=50,choices=ORDER_STATUS,default='To_Ship')
ordered_date = models.DateTimeField(auto_now_add=True)
ordered = models.BooleanField(default=False)
total_price = models.CharField(max_length=50,blank=True,null=True)
def __str__(self):
return self.user.email
class Meta:
verbose_name_plural = "Orders"
ordering = ('-id',)
class OrderItem(models.Model):
orderItem_ID = models.CharField(max_length=12,unique=True, editable=False, default=id_generator())
order = models.ForeignKey(Order,on_delete=models.CASCADE, blank=True,null=True,related_name='order_items')
item = models.ForeignKey(Product, on_delete=models.CASCADE,blank=True, null=True)
order_variants = models.ForeignKey(Variants,on_delete=models.CASCADE,blank=True,null=True)
quantity = models.IntegerField(default=1)
total_item_price = models.PositiveIntegerField(blank=True,null=True,)
My serializers:
class OrderSerializer(serializers.ModelSerializer):
billing_details = BillingDetailsSerializer()
order_items = OrderItemSerializer(many=True)
user = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault())
class Meta:
model = Order
fields = ['id','user','ordered_date','order_status', 'ordered', 'order_items', 'total_price','billing_details']
# depth = 1
def create(self, validated_data):
user = self.context['request'].user
if not user.is_seller:
order_items = validated_data.pop('order_items')
billing_details = validated_data.pop('billing_details')
order = Order.objects.create(user=user,**validated_data)
BillingDetails.objects.create(user=user,order=order,**billing_details)
for order_items in order_items:
OrderItem.objects.create(order=order,**order_items)
return order
else:
raise serializers.ValidationError("This is not a customer account.Please login as customer.")
In python shell, i tired this and it works fine
the problem is with
orderItem_ID = models.CharField(max_length=12,unique=True, editable=False, default=id_generator())
Here in the default, you're have assigned function call. Thus, it will only be evaluated once at the time of creation, .i.e., at first time you run makemigrations.
We need to have function references in the default values, this way it will be called each time a new instance is created.
Try replacing the line with
orderItem_ID = models.CharField(max_length=12,unique=True, editable=False, default=id_generator)
Note default=id_generator and not default=id_generator().
Hope this answers your question.
PS: you would be required to rerun the makemigrations and migrations commands to set this change into effect.
The validation error comes from here:
orderItem_ID = models.CharField(max_length=12,unique=True, editable=False, default=id_generator())
Add orderItem_ID in OrderItemSerializer and try sending orderItem_ID in "order_items" with a unique value on each post.
As for this: default=id_generator()
Check what this function is generating on each hit, probably its saving the same value each time which is causing the error.

Update Django Model

How to i update a certain value in the database?
class Userdata(models.Model):
user = models.OneToOneField(User, on_delete= models.CASCADE)
faculty = models.ForeignKey(Fakultas,on_delete=models.CASCADE,default= 1)
is_voted = models.BooleanField(default=False)
def __str__(self):return self.user.username
class Voting(models.Model):
name = models.CharField(max_length=50)
faculty = models.ForeignKey(Fakultas, on_delete=models.CASCADE, default=1)
pic = models.CharField(max_length=50)
text = models.TextField()
voters = models.IntegerField()
def __str__(self): return self.name
My Views :
def voted(response):
if response.method == 'POST':
id = response.POST.get['idcalon']
user = Userdata.objects.get() #get the username
calon2 = Voting.objects.get() #get user selection in html
user.is_voted = True
calon2.voters +=1
user.save(['is_voted'])
calon2.save(['voters'])
I'm trying to grab the user's name and then when update the user's is_voted value to True when triggered.
Then, I wanted to grab my Voting model by id, for example, I wanted to edit id = 1
So how do I do it? I've been trying to understand the documentation, but still have 0 idea how to do it.
Thank you
def voted(request):
if request.method == 'POST':
id = request.POST.get['idcalon']
user = Userdata.objects.get(id=request.user.id) #get the username
calon2 = Voting.objects.get(id=id) #get user selection in html
user.is_voted = True
calon2.voters +=1
user.save()
calon2.save()
this will work if user is authenticated

django 3.0 inline admin form foreignkey -> foreignkey

I have any models and one Manager
app/models.py
class castratedListStudent(models.Manager):
use_in_migrations = False
def get_query_set(self):
return super().get_query_set().filter(isOn=1)
class student(models.Model):
id = models.AutoField(primary_key=True)
firstName = models.CharField(max_length=20)
lastName = models.CharField(max_length=20)
isOn = models.BooleanField()
default_manager = castratedListStudent()
objects = castratedListStudent()
class discipline(models.Model):
id = models.AutoField(primary_key=True)
nameDiscipline = models.CharField(max_length=100, null=False)
itemIdToDiscip = models.ForeignKey(item, on_delete=models.CASCADE, default=1)
class listOfStudForDiscipline(models.Model):
id = models.AutoField(primary_key=True)
discipListId = models.ForeignKey(discipline, on_delete=models.CASCADE)
studId = models.ForeignKey(student, on_delete=models.CASCADE)
I am using django inline
accounts/admin.py
class discipStudentInline(admin.TabularInline):
model = listOfStudForDiscipline
admin.TabularInline.verbose_name = 'Student'
extra = 0
def has_change_permission(self, request, obj=None):
return False
def get_queryset(self, request):
return self.model.objects.filter(studId__isOn=1)
class disciplineAdmin(admin.ModelAdmin):
model = discipline
inlines = [discipStudentInline]
The Inline form is displayed on the HTML page and filter (studId__isOn=1) works. But the problem is that on the HTML page below there is a field that allows you to add another student and the list of students is not filtered by the filter rule(studId__isOn=1) When I check in the DEBUG_SQL console, I can see how the query goes without the WHERE expression "FROM journal_student".
(0.000) SELECT `journal_listofstudfordiscipline`.`id`, `journal_listofstudfordiscipline`.`discipListId_id`, `journal_listofstudfordiscipline`.`studId_id` FROM `journal_listofstudfordiscipline` INNER JOIN `journal_student` ON (`journal_listofstudfordiscipline`.`studId_id` = `journal_student`.`id`) WHERE (`journal_student`.`isOn` = 1 AND journal_listofstudfordiscipline`.`discipListId_id` = 1) ORDER BY `journal_student`.`lastName` DESC; args=(True, 1)
(0.000) SELECT `journal_student`.`id`,..., `journal_student`.`descriptionStudent` FROM journal_student` ORDER BY `journal_student`.`lastName` ASC, `journal_student`.`firstName` ASC; args=()
I couldn't solve the problem using the model Manager.
I solved the problem. It turned out that after django version 1.7, the get_query_set() method was renamed to get_queryset(). And the Manager will now look like this:
class castratedListStudent(models.Manager):
use_in_migrations = False
def get_query_set(self):
return super(liveListStudent, self).get_queryset().filter(isOn=1)

How to send info in URL?

I am trying to create a product filter.
I am sending the user choice in URL
if the user select size = L then using request.GET
I am receiving:
{'size': ['L']}
But I want to receive: {'size':{'op':'in','attri':'L'}}
Is this possible?
Please help
my models are
class ProductAttribute(models.Model):
slug = models.SlugField(max_length=50, unique=True)
name = models.CharField(max_length=100)
op = models.CharField(max_length=20,default='in')
class Meta:
ordering = ('slug', )
def __str__(self):
return self.name
def get_formfield_name(self):
return slugify('attribute-%s' % self.slug, allow_unicode=True)
def has_values(self):
return self.values.exists()
class AttributeChoiceValue(models.Model):
name = models.CharField(max_length=100)
slug = models.SlugField(max_length=100)
attribute = models.ForeignKey(
ProductAttribute, related_name='values', on_delete=models.CASCADE)
class Meta:
unique_together = ('name', 'attribute')
def __str__(self):
return self.name
class Product(models.Model):
name = models.CharField(max_length=128)
attributes = HStoreField(default={})
q2 = AttributeChoiceValue.objects.filter(attribute__name='size')
My size filter(filter.py) is:
size = django_filters.ModelMultipleChoiceFilter(queryset=q2.values_list('name', flat=True).distinct(),widget=forms.CheckboxSelectMultiple)
I am currently using the following query to filter my database in views.py
result = Product.objects.all()
for key, value in request.GET:result = result.filter(**{'attributes__{}__in'.format(key): value})
I want to make it
a=request.GET
for key, value in a:
result = result.filter(**{'attributes__{}__{}'.format(key,a['op']): value})
so that if I even use Price range as filter my query filter accordingly will be
attributes__price__range
You can send info to your views via "path converters":
https://docs.djangoproject.com/en/2.0/topics/http/urls/#path-converters
Or using regular expressions:
https://docs.djangoproject.com/en/2.0/topics/http/urls/#using-regular-expressions