How do I solve django.db.utils.IntegrityError: UNIQUE constraint failed? - python

How do I solve django.db.utils.IntegrityError: UNIQUE constraint failed?
error code is
django.db.utils.IntegrityError: UNIQUE constraint failed: Movies_comment.user_id, Movies_comment.tv_or_movie_id.
This error occurs Comment(comment=form.cleaned_data["comment"],user=request.user,stars=form.cleaned_data["stars"],tv_or_movie=tv_or_movie_object).save()
views.py
def view_tv_and_movie_detail(request, type_movie_or_tv, id):
tv_or_movie_object, _ = TVAndMovie.objects.get_or_create(tmdb_id=id, judge_tv_or_movie=type_movie_or_tv)
detail_tv_or_movie = TvAndMovieDetailhelp(request, tv_or_movie_object, 3)
mycomment_obj = detail_tv_or_movie.get_user_post_comment_for_tv_or_movie()
if request.method == "POST":
if request.POST.get("action") == "delete":
mycomment_obj.delete()
return redirect("view_tv_and_movie_detail", type=type_movie_or_tv, id=id)
else:
form = CommentCreateForm(request.POST, instance=mycomment_obj)
if form.is_valid() and request.POST.get("action") == "update":
form.save()
return redirect("view_tv_and_movie_detail", type=type_movie_or_tv, id=id)
elif form.is_valid() and request.POST.get("action") == "create":
Comment(
comment=form.cleaned_data["comment"],
user=request.user,
stars=form.cleaned_data["stars"],
tv_or_movie=tv_or_movie_object,
).save()
return redirect("view_tv_and_movie_detail", type=type_movie_or_tv, id=id)
else:
form = CommentCreateForm(instance=mycomment_obj)
data = detail_tv_or_movie.get_object_tv_or_movie_data()
recommendations = detail_tv_or_movie.get_recommendations_tmdb_data()
pages = detail_tv_or_movie.get_page_comment()
average = tv_or_movie_object.average_stars()
context = {
"data": data,
"recommendations": recommendations,
"type": "movie",
"mycomment": mycomment_obj,
"average": average,
"form": form,
"pages": pages
}
return render(request, "Movie/movie_detail.html", context)
models.py
class TVAndMovie(models.Model):
tmdb_id = models.CharField(
validators=[alphanumeric], max_length=9999
)
judge_tv_or_movie = models.CharField(
blank=False, null=False, default="movie", max_length=20
)
stars = models.FloatField(
blank=False,
null=False,
default=0,
validators=[MinValueValidator(0.0), MaxValueValidator(10.0)],
)
def get_judge_tv_or_movie(self) -> str:
return self.judge_tv_or_movie
def get_comments(self) -> object:
return Comment.objects.prefetch_related("tv_or_movie").filter(
tv_or_movie_id=self.id
)
def average_stars(self) -> float:
comments = self.get_comments()
n_comments = comments.count()
if n_comments:
self.stars = round(
sum([comment.stars for comment in comments]) / n_comments, 3
)
else:
self.stars = 0
self.save()
return self.stars
class Comment(models.Model):
comment = models.TextField(max_length=1000)
stars = models.FloatField(
blank=False,
null=False,
default=0,
validators=[MinValueValidator(0.0), MaxValueValidator(10.0)],
)
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
tv_or_movie = models.ForeignKey(TVAndMovie, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
unique_together = ("user", "tv_or_movie")
indexes = [models.Index(fields=["user", "tv_or_movie"])]
def __str__(self) -> str:
return self.comment[:20]
helper_views.py
class TvAndMovieDetailhelp:
def __init__(self, request, obj_tv_or_movie: object, page_num: int) -> None:
self.request = request
self.obj_tv_or_movie: object = obj_tv_or_movie
self.page_num: int = page_num
def get_object_tv_or_movie_data(self) -> dict:
tv_or_movie_url: str = (
"https://api.themoviedb.org/3/" +
self.obj_tv_or_movie.judge_tv_or_movie +
"/" +
str(self.obj_tv_or_movie.tmdb_id) +
"?api_key=" +
TMDB_API_KEY +
"&language=en-US"
)
return (requests.get(tv_or_movie_url)).json()
def get_recommendations_tmdb_data(self) -> dict:
recommendations_url: str = (
"https://api.themoviedb.org/3/" +
self.obj_tv_or_movie.judge_tv_or_movie +
"/" +
str(self.obj_tv_or_movie.tmdb_id) +
"/recommendations?api_key=" +
TMDB_API_KEY +
"&language=en-US"
)
return (requests.get(recommendations_url)).json()
def get_comment_for_tv_or_movie(self) -> object:
if self.request.user.id is not None:
return (
Comment.objects.filter(tv_or_movie=self.obj_tv_or_movie.id)
.exclude(user=self.request.user)
.order_by("-updated_at")
)
else:
return Comment.objects.filter(tv_or_movie=self.obj_tv_or_movie.id).order_by(
"-updated_at"
)
def get_user_post_comment_for_tv_or_movie(self) -> object:
if self.request.user.id is not None:
try:
return Comment.objects.get(
user=self.request.user, tv_or_movie=self.obj_tv_or_movie
)
except Comment.DoesNotExist:
return None
else:
return None
def get_page_comment(self):
other_comments = self.get_comment_for_tv_or_movie()
paginator = Paginator(other_comments, self.page_num)
page = self.request.GET.get("page", 1)
try:
pages = paginator.page(page)
except PageNotAnInteger:
pages = paginator.page(1)
except EmptyPage:
pages = paginator.page(1)
return pages
def send_contexts_detail(self,form) -> dict:
data_for_tvor_movie = self.get_object_tv_or_movie_data()
recommendations_data = self.get_recommendations_tmdb_data()
for_movie_or_tv = self.obj_tv_or_movie.judge_tv_or_movie
mycomment_obj = self.get_user_post_comment_for_tv_or_movie()
average = self.obj_tv_or_movie.getaverage_stars()
pages = self.get_page_comment()
context = {
"data": data_for_tvor_movie,
"recommendations": recommendations_data,
"type": for_movie_or_tv,
"mycomment": mycomment_obj,
"average": average,
"form": form,
"pages": pages, # NOTE add the comment to context
}
return context

tv_or_movie before saving i.e.
if not Comment.objects.filter(user=request.user, tv_or_movie=tv_or_movie_object).exists()
Comment(comment=form.cleaned_data["comment"], user=request.user, stars=form.cleaned_data["stars"], tv_or_movie=tv_or_movie_object).save()

Related

Django Simple History not logging user

I am using django-simple-history to log changes in my models. I have managed to save log of changes, but I always get None on field history_user.
I am following this tutorial.
This is my model:
class Reservation(models.Model):
UNCONFIRMED = 'UNCONFIRMED'
CONFIRMED = 'CONFIRMED'
CANCELED = 'CANCELED'
NO_SHOW = 'NO SHOW'
GO_SHOW = 'GO SHOW'
STATUS_CHOICES = (
(UNCONFIRMED, _('Unconfirmed')),
(CONFIRMED, _('Confirmed')),
(CANCELED, _('Canceled')),
(NO_SHOW, _('No show')),
(GO_SHOW, _('Go show')),
)
booking = models.CharField(max_length=25, verbose_name=_('Booking'))
agency = models.ForeignKey(Agency, on_delete=models.PROTECT, related_name='reservations', verbose_name=_('Agency'))
comment = models.TextField(null=True, blank=True, verbose_name=_('Comment'))
status = models.CharField(max_length=15, choices=STATUS_CHOICES, default=UNCONFIRMED, verbose_name=_('Status'))
confirmation_date = models.DateTimeField(null=True, blank=True, verbose_name=_("Confirmation Date"))
arrival_date = models.DateField(verbose_name=_('Arrival Date'))
departure_date = models.DateField(verbose_name=_('Departure Date'))
confirmation = models.CharField(max_length=15, null=True, blank=True, verbose_name=_('Confirmation Code'))
is_invoiced = models.BooleanField(default=False, verbose_name=_('Is invoiced?'))
euroamerica = models.BooleanField(default=False, verbose_name=_("Is Euroamerica sale"))
user = models.ForeignKey(User, null=True, blank=True, on_delete=models.PROTECT, related_name='reservations')
changed_by = models.ForeignKey(User, null=True, blank=True, on_delete=models.PROTECT)
timestamp = models.DateTimeField(null=True, blank=True, auto_now_add=True)
handle_fee = models.FloatField(null=True, blank=True, verbose_name=_("Handle Fee"))
log = HistoricalRecords(related_name='history')
class Meta:
verbose_name = _('Reservation')
verbose_name_plural = _('Reservations')
permissions = (
('reservation_can_edit', 'Can Edit Reservation'),
('reservation_can_view', 'Can View Reservation'),
('reservation_can_view_history_log', 'Can View Reservation History Log')
)
def __str__(self):
return "[{}]{}".format(self.booking, self.agency)
def clean(self, *args, **kwargs):
if self.id is None:
try:
Reservation.objects.get(booking=self.booking)
except:
pass
else:
raise CustomValidation(_('Booking already exists.'), 'booking', status_code=status.HTTP_400_BAD_REQUEST)
if isinstance(self.arrival_date, str):
raise CustomValidation(_('Arrival date must be a valid date.'), 'arrival_date', status_code=status.HTTP_400_BAD_REQUEST)
if isinstance(self.departure_date, str):
raise CustomValidation(_('Departure date must be a valid date.'), 'departure_date', status_code=status.HTTP_400_BAD_REQUEST)
if self.arrival_date >= self.departure_date:
raise CustomValidation(_('Departure date must be later than Arrival date.'), 'departure_date', status_code=status.HTTP_400_BAD_REQUEST)
# elif self.arrival_date <= timezone.datetime.now().date():
# if self.id == None:
# raise CustomValidation(_('Arrival date must be later than today.'), 'arrival_date', status_code=status.HTTP_400_BAD_REQUEST)
if self.status == 'CONFIRMED' and self.confirmation is None:
raise CustomValidation(_('Must provide a confirmation number.'), 'confirmation', status_code=status.HTTP_400_BAD_REQUEST)
return True
def save(self, *args, **kwargs):
from GeneralApp.models import Parameter
self.booking = self.booking.replace(' ', '')
self.booking = self.booking.upper()
self.full_clean()
if self.confirmation is not None and self.status is not self.CONFIRMED:
if self.pk is not None:
try:
previous_reservation = Reservation.objects.get(id=self.pk)
except:
pass
else:
if previous_reservation.status == self.status and previous_reservation.confirmation != self.confirmation:
self.status = self.CONFIRMED
else:
self.status = self.CONFIRMED
if self.status == self.CONFIRMED and self.confirmation_date is None:
self.confirmation_date = timezone.now()
try:
self.handle_fee = Parameter.objects.get(name="Handle Fee").value
except:
self.handle_fee = None
super(Reservation, self).save(*args, **kwargs)
#property
def _history_user(self):
return self.changed_by
#_history_user.setter
def _history_user(self, value):
self.changed_by = value
I don't know what I am missing to get the user logged.
EDIT
Here is where I save Reservation:
def save_reservation(self, reservation_data, user, pk):
try:
reservation_to_save = models.Reservation.objects.get(booking=pk)
except:
raise CustomValidation(_("There is not such reservation {}".format(pk)), 'id', status.HTTP_400_BAD_REQUEST)
reservation_to_save.booking = reservation_data['booking']
reservation_to_save.agency = models.Agency.objects.get(id=reservation_data['agency'])
reservation_to_save.comment = reservation_data.get('comment', None)
reservation_to_save.status = reservation_data.get('status', 'UNCONFIRMED')
reservation_to_save.arrival_date = reservation_data['arrival_date']
reservation_to_save.departure_date = reservation_data['departure_date']
reservation_to_save.confirmation = reservation_data.get('confirmation', None)
reservation_to_save.is_invoiced = reservation_data.get('is_invoiced', False)
reservation_to_save.euroamerica = reservation_data.get('euroamerica', False)
reservation_to_save.save()
return reservation_to_save
According to the documentation you have to add HistoryRequestMiddleware to your middleware in settings.py
Like so:
MIDDLEWARE = [
# ...
'simple_history.middleware.HistoryRequestMiddleware',
]
This at least was the solution in my case.
If you don't want to use this middleware you can set the user manually, see this.

Error when inserting into database Django

I have a new problem, it is when I insert in the database the news, it adds but without the region. How can I insert the comment with the correct region?
Here is my view :
def index_region(request,region):
try:
actuCommentaire = Actu.objects.get(region=region)
except ObjectDoesNotExist:
actuTempo = Actu(region=region)
actuCommentaire = actuTempo.commentaire
form = UpdateActu(request.POST or None, instance=actuCommentaire)
if form.is_valid():
form.save()
return redirect('index.html')
Here is my model "Actu" :
class Actu(models.Model):
commentaire = models.TextField(max_length=200, null=True)
region = models.CharField(max_length=30, null=True)
def __str__(self):
return self.region
Here is my form :
class UpdateActu(forms.ModelForm):
class Meta:
model = models.Actu
fields = ['commentaire']
widgets = {
'commentaire': forms.Textarea(attrs={'class': 'form-control', 'id': 'exampleTextarea', 'rows': '2'})
}
Here is the result when inserting into the database :
enter image description here
I found how to solve the problem.
Here is my new view :
try:
actuCommentaire = Actu.objects.get(region=region)
except ObjectDoesNotExist:
actuTempo = Actu(region=region)
actuCommentaire = actuTempo.commentaire
form = UpdateActu(request.POST or None, instance=actuCommentaire)
if form.is_valid():
if Actu.objects.filter(region=region).count() == 0:
formActu = Actu(commentaire=request.POST['commentaire'], region=region)
formActu.save()
else:
form.save()
return redirect('index.html')

Slow response in django

Currently I am inspecting a django queries(django-rest-framework) with django debug toolbar. The postgres database query time is about 100ms which is ok. But the response time took about 6 sec., which is slow.
I found that the slowest(takes about 4 sec.) function is this:
#transaction.atomic
def create(self, *args, **kwargs):
response = super(PersonView, self).create(*args, **kwargs)
data = response.data
product_data = data['packages'][0]['product']
person = Person.objects.get(pk=data['id'])
if not person.info:
product = Product.objects.get(pk=product_data['id'])
PersonItem.objects.create(person=person, product=product)
response.data = PersonSerializer(person).data
return response
Any ideas why the response is so slow or why this function takes so long ?
Edit:
This is my PersonSerializer class.
class PersonSerializer(serializers.ModelSerializer):
person_items = PersonItemSerializer(many=True, read_only=True)
address = AddressSerializer(read_only=True)
office_address = serializers.SerializerMethodField('get_office_address')
status = ChoiceWithNameField(choices=Person.STATUS_CHOICES)
source = ChoiceWithNameField(
choices=Person.SOURCE_CHOICES, required=False)
closing_person = ClosingPersonSerializer(read_only=True)
is_upfront_person = serializers.BooleanField(read_only=True)
has_discount = serializers.BooleanField(read_only=True)
payment_method = serializers.CharField(read_only=True)
user_email = serializers.CharField(
read_only=True, source='user.email')
user_display_name = serializers.CharField(
read_only=True, source='user.display_name')
billing_display_address = serializers.SerializerMethodField(
'get_billing_display_address')
real_estate_display_address = serializers.SerializerMethodField(
'get_real_estate_display_address')
net_total = serializers.DecimalField(read_only=True, source='net_total')
gross_total = serializers.DecimalField(read_only=True, source='gross_total')
tax = serializers.DecimalField(read_only=True, source='tax_total')
coupon_net_total = serializers.DecimalField(read_only=True,
source='coupon_net_total')
coupon_gross_total = serializers.DecimalField(read_only=True,
source='coupon_gross_total')
class Meta:
model = Person
policy_class = PersonPolicy
def get_billing_display_address(self, obj):
try:
address = obj.address
except Address.DoesNotExist:
pass
else:
return "{0} {1}, {2}, {3}".format(
address.house_name_number, address.address_2, address.town,
address.postcode)
def _filter_products(self, products):
user = getattr(self.context.get('request'), 'user', None)
if not user or not user.is_staff:
products = products.filter(admin_only=False)
return products
def _as_person_items(self, person, products):
persons = [PersonItem(name=p.name, description=p.description,
person=person,
price=p.total_up_front,
product=p) for p in products]
return persons
def get_packages(self, person):
products = self._filter_products(person.packages)
return PersonItemMinimalSerializer(
self._as_person_items(person, products),
many=True).data
def get_office_address(self, i):
try:
office_address = i.addresses.get(address_type=Address.ADDRESS)
except Address.DoesNotExist:
return False
return AddressSerializer(office_address, read_only=True).data
def get_real_estate_display_address(self, obj):
try:
address = obj.office_address
except Address.DoesNotExist:
pass
else:
return "{0} {1}, {2}, {3}".format(
address.house_name_number, address.address_2,
address.town, address.postcode)

How to multiply model with different app in django?

to count about multiply model with another model in foreignkey but in different app, here the penjualan app and detail_penjualan_obat model :
class detail_penjualan_obat(models.Model):
kd_penjualan_detail = models.ForeignKey(penjualan_obat)
kd_obat_detail = models.ForeignKey(obat)
jumlah_jual = models.IntegerField()
total_harga_perobat = MoneyField(max_digits=10, decimal_places=2, default_currency='IDR')
def __unicode__(self):
return self.total_harga_perobat
and the obat app model :
class obat(models.Model):
jenis_obat = {
('obat bebas','Obat Bebas'),
('obat bebas terbatas','Obat Bebas Terbatas'),
('obat keras dan psikotropika','Obat Keras dan Psikotropika')
}
kd_obat = models.CharField(primary_key = True, default = '', max_length = 10, validators=[RegexValidator(r'^\d{1,10}$')])
nama_obat = models.CharField(max_length = 15)
tipe_obat = models.CharField(max_length = 35, choices = jenis_obat)
harga_jual = MoneyField(max_digits=10, decimal_places=2, default_currency='IDR')
def __unicode__(self):
return self.kd_obat
and the view.py :
def data_penjualan_obat_detail(request):
if request.method == 'POST':
form_data = request.POST
form = penjualan_detail_form(form_data)
if form.is_valid():
input_detail_penjualan = detail_penjualan_obat(
kd_penjualan_detail = form.cleaned_data.get('kd_penjualan_detail'),
kd_obat_detail = form.cleaned_data.get('kd_obat_detail'),
jumlah_jual = request.POST['jumlah_jual'],
total_harga_perobat = form.cleaned_data.get('total_harga_perobat')
)
input_detail_penjualan.save()
return redirect('/')
else:
form = penjualan_detail_form()
return render(request, 'penjualan_detail.html',{'form':form})
here the function :
total_harga_perobat = harga_jual * jumlah_jual
and that function how to be 'place and work' in the view ?
Sorry I have bad english but I hope you will understand what about my question, and solve my problem
EDIT :
here model of penjualan_obat :
class penjualan_obat(models.Model):
kd_penjualan = models.CharField(primary_key = True, default = '', max_length = 10, validators=[RegexValidator(r'^\d{1,10}$')], unique = True)
kd_costumer_obat = models.ForeignKey(costumer)
tgl_penjualan = models.DateField(auto_now_add = True)
total_penjualan = MoneyField(max_digits=10, decimal_places=2, default_currency='IDR')
def __unicode__(self):
return self.kd_penjualan
and the form penjualan_detail_form :
class penjualan_detail_form(ModelForm):
class Meta:
model = detail_penjualan_obat
fields = ['kd_penjualan_detail','kd_obat_detail','jumlah_jual']
labels = {
'kd_penjualan_detail' : 'Kode Penjualan',
'kd_obat_detail' : 'Kode Obat',
'jumlah_penjualan' : 'Jumlah Penjualan',
}
error_messages = {
'kd_penjualan_detail':{
'required':'Anda harus memilih kode penjualan'
},
'kd_obat_detail':{
'required':'Anda harus memilih kode obat'
},
'jumlah_penjualan':{
'required':'Anda harus mengisi jumlah penjualan'
},
}
CORRECTIONS
I suggest you to change model class name with standard naming.
an example class detail_penjualan_obat(models.Model) to class DetailPenjualanObat(models.Model)
and I suggest you to not using default = '' to your unique field.
This will be difficult whenever you migrating the databases.
Why you implement to the form form.cleaned_data.get('total_harga_perobat'),
if you actually want to save it with automatically? you should handle it at your backend.
I checked at your source code, and your penjualan_detail_form
already instanced to the model of detail_penjualan_obat. perhaps like this below;
def data_penjualan_obat_detail(request):
if request.method == 'POST':
form = penjualan_detail_form(request.POST)
if form.is_valid():
initial = form.save(commit=False)
initial.total_harga_perobat = initial.kd_obat_detail.harga_jual * initial.jumlah_jual
initial.save()
form.save()
return redirect('/')
else:
form = penjualan_detail_form()
return render(request, 'penjualan_detail.html', {'form': form})
Hope it can help..
UPDATE
You also can handle it in your models.py, an example:
class DetailPenjualanObat(models.Model):
kd_penjualan_detail = models.ForeignKey(penjualan_obat)
kd_obat_detail = models.ForeignKey(obat)
jumlah_jual = models.IntegerField()
total_harga_perobat = MoneyField(max_digits=10, decimal_places=2, default_currency='IDR')
def save(self, *args, **kwargs):
self.total_harga_perobat = self.kd_obat_detail.harga_jual * self.jumlah_jual
super(DetailPenjualanObat, self).save(*args, **kwargs)
See also about pre save, like this answer

UnboundLocalError local variable <variablename> referenced before assignment

I faced the error when I tried to capture the POST data from a form. Weird, because the same algorithm works with another django app model.
The models:
class Item(models.Model):
code = models.CharField(max_length=200, unique=True)
barcode = models.CharField(max_length=300)
desc = models.CharField('Description',max_length=500)
reg_date = models.DateField('registered date')
registrar = models.CharField(max_length=100)
def __unicode__(self):
return self.code + ' : ' + self.desc
class ItemInfo(models.Model):
model = models.ForeignKey(Item)
supplier = models.ForeignKey(Supplier)
stock_on_hand = models.IntegerField()
stock_on_order = models.IntegerField()
cost = models.IntegerField()
price = models.IntegerField()
unit = models.CharField(max_length=100)
lead_time = models.IntegerField()
def __unicode__(self):
return Item.code + ' : ' + supplier
class ItemForm(ModelForm):
class Meta:
model = Item
class ItemInfoForm(ModelForm):
class Meta:
model = ItemInfo
exclude = ('model')
And the views.py function for non-working (Item) is like this:
def register(request):
csrf_context = RequestContext(request)
current_user = User
if request.user.is_authenticated():
if request.POST:
item = Item()
item_info = ItemInfo()
header_form == ItemForm(data=request.POST,instance=item)
details_form == ItemInfoForm(data=request.POST, instance=item_info)
if header_form.is_valid():
header = header_form.save()
if details_form.is_valid():
details = details_form.save(commit=False)
details.supplier = header
details.save()
return HttpResponseRedirect('/item/')
else:
return render_to_response('error/denied_data_entry.html')
else:
header_form = ItemForm()
details_form = ItemInfoForm()
return render_to_response('item/register.html',{'header_form' : header_form, 'details_form' : details_form}, csrf_context)
else:
return render_to_response('error/requires_login.html', csrf_context)
The working views.py function for another working (Supplier) model is here:
def register(request):
csrf_context = RequestContext(request)
current_user = User
if request.user.is_authenticated():
if request.POST:
supplier = Supplier()
supplier_info = SupplierInfo()
header_form = SupplierForm(data=request.POST, instance=supplier)
details_form = SupplierInfoForm(data=request.POST, instance=supplier_info)
if header_form.is_valid():
header = header_form.save()
if details_form.is_valid():
details = details_form.save(commit=False)
details.model = header
details.save()
return HttpResponseRedirect('/supplier/')
else:
return render_to_response('error/denied_data_entry.html')
else:
return render_to_response('error/denied_data_entry.html')
else:
header_form = SupplierForm()
details_form = SupplierInfoForm()
return render_to_response('supplier/register.html', {'header_form' : header_form, 'details_form' : details_form}, csrf_context)
else:
return render_to_response('error/requires_login.html', csrf_context)
The traceback page shows that the POST did pass some variable. Help me please, I cant figure it out why it works on Supplier, but not Item.
P/S: Sorry for the indentation.
The problem is here:
# ...
header_form == ItemForm(data=request.POST,instance=item)
details_form == ItemInfoForm(data=request.POST, instance=item_info)
You're not assigning, you're comparing.

Categories