I've inherited an app created with Django. There is a problem with it: in admin interface, the page lists not all entities (videos), but some (16 of 25). I have no idea, what is this.
Then I run python manage.py shell, and there Video.objects.all(), there are all 25 objects (counted them using len and by iterating them with for loop).
I have found no managers or whatever (maybe I just don't know where to look for them).
On the bottom of admin page: 25 videos, while there are only 16 rows.
Then I add to VideoModelAdmin class list_per_page = 10, paginator show three pages, but only first two of them has any Videos, third shows no rows.
Here are some code.
# admin.py
class VideoModelAdmin(admin.ModelAdmin):
list_display = ['title', 'short_desc', 'author', 'redactor_choise', 'views_num', 'rating', 'is_published']
list_filter = ['is_published', 'redactor_choise']
list_per_page = 10
actions = ['make_published', 'update_comments_count']
exclude = ('file_lq', 'file_hq', )#'thumb',)
def make_published(self, request, queryset):
queryset.update(is_published=1)
make_published.short_description = "Опубликовать выделенные"
def save_model(self, request, obj, form, change):
instance = form.save(commit=False)
instance.author = request.user
instance.save()
return instance
def update_comments_count(self, request, queryset):
for video in queryset:
video.update_comments_count()
update_comments_count.short_description = "Пересчитать комментарии!"
# later there
admin.site.register(Video, VideoModelAdmin)
# models.py
class Video(models.Model):
def make_upload_path(instance, filename):
return 'video/thumbs/' + generate_random_name(filename)
category = models.ManyToManyField(Category, limit_choices_to = {'is_published': 1})
title = models.CharField(max_length=128)
short_desc = models.CharField(max_length=255)
long_desc = tinymce_models.HTMLField(blank=True)
file_lq = models.FileField(upload_to='video/lq/', null=True, blank=True)
file_hq = models.FileField(upload_to='video/hq/', null=True, blank=True)
thumb = models.FileField(upload_to=make_upload_path, blank=True, null=True)
#thumb = fields.ThumbnailField(upload_to=make_upload_path, sizes=settings.VIDEO_THUMB_SIZE, blank=True, null=True)
author = models.ForeignKey(User, editable=False)
redactor_choise = models.BooleanField(default=False)
views_num = models.SmallIntegerField(default=0, editable=False)
comments_num = models.SmallIntegerField(default=0, editable=False)
rating = models.SmallIntegerField(default=0, editable=False)
voters = fields.PickledObjectField(blank=True, editable=False)
created = models.DateTimeField(auto_now_add=True)
is_published = models.BooleanField(default=False)
def get_absolute_url(self):
return "/video/%d" % self.id
def views_num_plus(self):
cursor = connection.cursor()
cursor.execute('update soctv_video set views_num=views_num+1 where id=%d', [self.id])
cursor.close()
def update_comments_count(self):
from threadedcomments.models import ThreadedComment as Comment
self.comments_num = Comment.objects.filter(video=self).count()
self.save()
#cursor = connection.cursor()
#cursor.execute('update soctv_video set comments_num = (select count(*) from soctv_comment where video_id = %s) where id = %s', [self.id, self.id])
#cursor.close()
def update_categories_counts(self):
cursor = connection.cursor()
cursor.execute('update soctv_category set num_items = (select count(*) from soctv_video_category where category_id = soctv_category.id)')
cursor.close()
def is_user_voted(self, uid):
try:
if self.voters[uid]:
return self.voters[uid]
except Exception:
return False
def increment_view_count(self, token):
import md5
token = md5.new(token).hexdigest()
if VideoView.objects.filter(uniquetoken=token).count() == 0:
VideoView(uniquetoken = token, video = self).save()
def view_count(self):
return self.views_num + VideoView.objects.filter(video=self).count()
def __unicode__(self):
return unicode(self.title)
The problem can be that some FK in some of your videos points to something that does not exist.
I had the same problem and this was the reason.
Django will silently fail if the value is not there in the foreign key column.
Add both null and blank attribute to the column
null=True, blank=True
Make sure that you are logged in to the correct account aswell.
In my case, My account did not have permissions to modify <Model>
Related
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.'})
room_category = models.ForeignKey(Cat, on_delete=models.CASCADE)
number = models.IntegerField(unique=True)
people = models.IntegerField()
picture = models.ImageField(upload_to = 'room/', null=True, blank=True)
actual_price = models.IntegerField()
offer_price = models.IntegerField()
def __str__(self):
return '%d : %s with People : %d' % (self.number, self.room_category, self.people)
I want to set a condition in offer_price table that offer_price < actual_price. It should show an error while entering data in the admin panel itself.
You can add validation in the .clean(…) method [Django-doc], and add a database constraint with Django's constraint framework:
from django.core.exceptions import ValidationError
from django.db.models import F, Q
class YourModel(models.Model):
# …
actual_price = models.IntegerField()
offer_price = models.IntegerField()
def clean(self, *args, **kwargs):
if self.actual_price <= self.offer_price:
raise ValidationError('offer price should be lower than the actual price')
return super().clean(*args, **kwargs)
class Meta:
constraints = [
models.CheckConstraints(
check=Q(offer_price__lt=F('actual_price')),
name='lower_than_actual_price'
)
]
I'm working on a timesheet based system currently. I am getting a Foreign Key constraint failure when I am trying to assign the foreign key of one model to the other one.
Here are the two models
class Timesheet(models.Model):
id = models.CharField(primary_key=True, max_length=50, blank=True, unique=True, default=uuid.uuid4)
First_Name = models.CharField(max_length=32)
Last_Name = models.CharField(max_length=32)
Date_Created = models.DateField(auto_now_add=True)
Creator = models.ForeignKey(User, on_delete=models.DO_NOTHING)
Approved = models.BooleanField(default=False)
Company_Relationship = (
('Supplier', 'Supplier'),
('Contractor', 'Contractor'),
('Employee', 'Employee')
)
Worker_Type = models.CharField(max_length=32, choices=Company_Relationship)
Total_Days_Worked = models.DecimalField(decimal_places=2, max_digits=3)
class Meta:
ordering = ['-id']
#unique_together = ['Creator', 'Work_Week']
def get_absolute_url(self):
return reverse('timesheet-detail', kwargs={'pk': self.pk})
class InternalSheet(models.Model):
id = models.CharField(primary_key=True, max_length=50, blank=True, unique=True, default=uuid.uuid4)
Timesheet_id = models.ForeignKey(Timesheet, on_delete=models.DO_NOTHING)
Working_For = (
('7', 'Seven'),
('i', 'intelligent'),
('S', 'Sata'),
)
iPSL = (
('R16.1', 'Release 16.1'),
('R16', 'Release 16')
)
Company_name = models.CharField(max_length=5, choices=Working_For)
Company_name_change = models.CharField(max_length=5, choices=Working_For)
Internal_Company_Role = models.CharField(max_length=10, choices=iPSL)
DaysWorked = models.DecimalField(decimal_places=2, max_digits=3)
Managers = (
('GW', 'Greg Wood'),
('JC', 'Jamie Carson')
)
ManagerName = models.CharField(max_length=8, choices=Managers)
Approved = models.BooleanField(default=False)
def get_absolute_url(self):
return reverse('sheet-detail', kwargs={'pk': self.pk})
My issue is that I am getting a foreign key failure using this post request.
class TimesheetCreateView(LoginRequiredMixin, CreateView):
"""
Creates view and send the POST request of the submission to the backend.
"""
def get(self, request, *args, **kwargs):
internal_form_loop = create_internal_form_for_context()
context = {'form': CreateTimesheetForm(), 'UserGroup': User()}
context.update(internal_form_loop)
print("new", context)
return render(request, 'create.html', context)
def post(self, request, *args, **kwargs):
form = CreateTimesheetForm(request.POST)
internal_form_1 = CreateInternalSheetForm(request.POST)
if form.is_valid():
print("forms valid")
external_timesheet = form.save(commit=False)
print("self", self.request.user)
print("id", Timesheet.id)
external_timesheet.Creator = self.request.user
external_timesheet.save()
else:
print("Error Here")
if internal_form_1.is_valid():
print("Internal form valid")
internal = internal_form_1.save(commit=False)
internal.Timesheet_id_id = Timesheet.id
internal.id = uuid.uuid4()
internal.save()
return HttpResponseRedirect(reverse_lazy('timesheet-detail', args=[Timesheet.id]))
return render(request, 'create.html', {'form': form, 'UserGroup': User()})
It is failing on the line internal.save(). If I print the line internal.Timesheet_id_id I get a value like this, <django.db.models.query_utils.DeferredAttribute object at 0x000001580FDB75E0>. I'm guessing this is the issue? I need the actual Foreign key and not the location of that object. How do I do this. Thanks.
Figured out the issue, I had to replace the lines
internal.Timesheet_id_id = Timesheet.id
internal.id = uuid.uuid4()
internal.save()
with
internal.Timesheet_id_id = Timesheet.objects.get(id=external_timesheet.id)
internal.save()
I'd like to find a simple and robust way to create a child object. I think it is a simple problem, probably solved using Django RelationshipManager or Related objects reference.
I've gotten it to work in the past (by paying someone on fiver to help me solve this), but I feel that there is a much simpler method that escapes me.
This worked on my views.py
class MainVisitForm(SingleObjectMixin, FormView):
template_name = "clincher/visit_form.html"
form_class = VisitForm
model = Main
def post(self, request, *args, **kwargs):
if not request.user.is_authenticated:
return HttpResponseForbidden()
self.object = self.get_object()
form=self.get_form()
form.fk_visit_user = self.request.user
form.fk_visit_main = Main.objects.get(id=self.kwargs['pk'])
#added this to save form as we are mixxing the two forms and Models
# as the approch of singleObjectMixin is we should get object from DB as per request url as a primary key
#and we have defined model as a Main but taking the form view of VistForm as the probem occures
# as i think
if form.is_valid():
instance = Main()
instance.firstname = form.cleaned_data['firstname']
instance.middelname = form.cleaned_data['middlename']
instance.lastname = form.cleaned_data['lastname']
instance.date_of_birth = form.cleaned_data['date_of_birth']
instance.sex = form.cleaned_data['sex']
instance.address = form.cleaned_data['address']
instance.save()
return super().post(request, *args, **kwargs)
def get_success_url(self):
return reverse('clincher:main_detail', kwargs={'pk': self.object.pk})
Basically, while the user is in the details page of the "main" object, I would like them to be able to create a child object (visit object). Ultimately 1 patient will have many visits (1:m relationship). Each time a patient visits the doc, 1 new visit will be added, that is related to that person. Later, I will show a list of visits for that patient (but not the subject of this question).
Models.py
class Main(models.Model):
firstname = models.CharField(max_length = 256, verbose_name=('First Name'))
middlename = models.CharField(max_length=256, verbose_name=('Middle Name'))
lastname = models.CharField(max_length=256, verbose_name=('Last Name'))
date_of_birth = models.DateField()
age = models.CharField(max_length=4)
sex_list = (
(str(1), 'Female'),
(str(2), 'Male'),
(str(3), 'Other'),
(str(4), 'Unknown'),)
sex = models.CharField(max_length = 24, choices=sex_list, verbose_name='Sex')
address = models.TextField(max_length = 256)
#property
def full_name(self):
#"Returns the person's full name."
return '%s %s' % (self.firstname, self.lastname)
#Redirects after form is submitted using primary key
def get_absolute_url(self):
return reverse('clincher:main_detail', kwargs={'pk': self.pk})
def __str__(self):
return self.firstname + ' ' + self.lastname +' - ' + str(self.date_of_birth)
class Visit(models.Model):
fk_visit_main = models.ForeignKey(Main, on_delete=models.CASCADE, verbose_name=('Patient Name'))
visit_date = models.DateField(auto_now = True, editable=True)
fk_visit_user = models.ForeignKey(User, on_delete=models.PROTECT, verbose_name=('Practitioner'), max_length=500)
visit_label = models.CharField(max_length=256, blank=True, null=True)
visit_type = models.CharField(
max_length=256,
default=1, verbose_name='Type of Visit')
visit_progress_notes = models.TextField(max_length=10000,
blank=True, verbose_name='Progress Notes')
outcomes = models.BooleanField(default=False)
def __str__(self):
return '%s %s' % (self.visit_date, self.visit_label)
def get_absolute_url(self):
return reverse('clincher:main_detail', kwargs={'pk': self.pk})
forms.py
class VisitForm(forms.Form):
visit_types_list = (
(str(1), 'Consultation'),
(str(2), 'Procedure'),
(str(3), 'Administrative'),)
visit_type = forms.ChoiceField(choices=visit_types_list)
visit_label = forms.CharField(label='Visit Label', max_length=100)
progress_note = forms.CharField(widget=forms.Textarea)
def form_valid(self, form):
form.instance.fk_visit_user = self.request.user
form.instance.fk_visit_main = Main.objects.get(id=self.kwargs['pk'])
return super().form_valid(form)
Thus, I should end up with a child record/object that has the primary key of the parent object.
The above code works, but I am sure that there is a simple Django-ey way of doing things much simpler, and in a robust manner. I think my solution should be found in the Django RelationshipManager, but I cannot find a solution that works. I paid a guy on Fiver, and I think he didn'y get this as simple as possible.
Check django InlineFormset: https://docs.djangoproject.com/en/2.2/topics/forms/modelforms/#inline-formsets
If you want to have to abillity to add an remove the formset dynamically checkout (Jquery based) :
https://github.com/elo80ka/django-dynamic-formset
If you are using class based view you will have to add the inlineformset in get_context_data() and inside form_valid() check if the formset.is_valid() and then save it to the database.
EDIT: Here is the code based on your comment
forms.py
class VisitForm(forms.ModelForm);
class Meta:
model = Visit
fields = [
'visit_type',
'visit_label',
'visit_progress_notes'
]
views.py
class CreateVisitView(CreateView):
model = Visit
form_class = VisitForm
template_name = "clincher/visit_form.html"
#one of the first function called in class based view, best place to manage conditional access
def dispatch(self, request, *args, **kwargs):
if not request.user.is_authenticated:
return HttpResponseForbidden()
return super(CreateVisitView,self).dispatch(request, *args, **kwargs)
def form_valid(self, form):
visit = form.save(commit=False)
visit.fk_visit_user = self.request.username
visit.fk_visit_main = get_object_or_404(Main, pk=self.kwargs.get('pk'))
visit.save()
return super(CreateVisitView,self).form_valid(form)
models.py
class Main(models.Model):
SEX_LIST_CHOICE = (
(str(1), 'Female'),
(str(2), 'Male'),
(str(3), 'Other'),
(str(4), 'Unknown'),
)
firstname = models.CharField(max_length = 256, verbose_name=('First Name'))
middlename = models.CharField(max_length=256, verbose_name=('Middle Name'))
lastname = models.CharField(max_length=256, verbose_name=('Last Name'))
date_of_birth = models.DateField()
age = models.PositiveSmallIntegerField()
sex = models.CharField(max_length = 24, choices=SEX_LIST_CHOICE, verbose_name='Sex')
address = models.TextField(max_length = 256)
#property
def full_name(self):
#"Returns the person's full name."
return '%s %s' % (self.firstname, self.lastname)
#Redirects after form is submitted using primary key
def get_absolute_url(self):
return reverse('clincher:main_detail', kwargs={'pk': self.pk})
def __str__(self):
return self.firstname + ' ' + self.lastname +' - ' + str(self.date_of_birth)
class Visit(models.Model):
VISIT_TYPE_CHOICE = (
(str(1), 'Consultation'),
(str(2), 'Procedure'),
(str(3), 'Administrative'),)
fk_visit_main = models.ForeignKey(Main, on_delete=models.CASCADE, verbose_name=('Patient Name'))
visit_date = models.DateField(auto_now = True, editable=True)
fk_visit_user = models.ForeignKey(User, on_delete=models.PROTECT, verbose_name=('Practitioner'), max_length=500)
visit_label = models.CharField(max_length=256, blank=True, null=True)
#you are storing the type of visit as an
visit_type = models.CharField(
max_length=256,
default=1,
verbose_name='Type of Visit',
choices=VISIT_TYPE_CHOICE
)
visit_progress_notes = models.TextField(max_length=10000,
blank=True, verbose_name='Progress Notes')
outcomes = models.BooleanField(default=False)
def __str__(self):
return '%s %s' % (self.visit_date, self.visit_label)
def get_absolute_url(self):
return reverse('clincher:main_detail', kwargs={'pk': self.pk})
So a number of things here that you could clear up.
instance.middelname = form.cleaned_data['middlename'] Will never work as middlename is incorrect on the instance side.
You can use Main.objects.create(firstname=form.validated_data['firstname'], lastname= .... etc) to create your Model instances
You should probably have the relation from a User to your models be via Main, not Visit. This will allow you to add records for a Visit easier, for example, staff member logging visits instead of customer.
You should lookup CreateView to assist you with the boilerplate of creating an instance.
Rename the Main model. What is it actually? Looks like a Profile to me, but calling it Main isn't very descriptive.
Age should be an integer field. Nobody is 'dave' years old.
I'm trying to make a model in Django that has a custom id attribute. I want it to always equal the sum of 10000 and the current id number of that instance. How exactly do I write that? And do I have to do anything in the view?
Edit: I better put the code I'm using just in case.
models.py
class Schedules(models.Model):
course_name = models.CharField(max_length=128, choices=COURSE_NAME_CHOICES, default='a-plus')
location = models.CharField(max_length=128, choices=LOCATION_CHOICES, default='south_plainfield')
room = models.CharField(max_length=128, choices=ROOM_CHOICES, default='A')
start_date = models.DateField(auto_now=False, auto_now_add=False, default=datetime.date.today)
start_time = models.CharField(max_length=128, choices=START_TIME_CHOICES, default='eight-thirty am')
end_time = models.CharField(max_length=128, choices=END_TIME_CHOICES, default='eight-thirty am')
instructor = models.CharField(max_length=128, choices=INSTRUCTOR_CHOICES, default='adewale')
total_hours = models.CharField(max_length=128, choices=TOTAL_HOURS_CHOICES, default='six')
hours_per_class = models.CharField(max_length=128, choices=HOURS_PER_CLASS_CHOICES, default='four_and_half')
frequency = models.CharField(max_length=128)
status = models.CharField(max_length=128, choices=STATUS_CHOICES)
interval = models.CharField(max_length=128, choices=INTERVAL_CHOICES, default='1 day')
initiated_by = models.CharField(max_length=128, null=True)
schedule_id = models.IntegerField(default=0)
views.py
def start_One_Schedule(request):
form = ScheduleForm()
if request.method == 'POST':
form = ScheduleForm(request.POST)
if form.is_valid():
obj = form.save(commit=False)
obj.initiated_by = request.user.username
obj.save()
return render(request, 'schedule/schedule.html', {})
else:
print(form.errors)
return render(request, 'schedule/start_one_schedule.html', {'form': form})
Create a property on the model that adds 10000 to the id field. You don't need to create the actual field.
class Example(models.Model):
#property
def custom_id(self):
return self.id + 10000
You can write custom id field in you model like this
class ABC(models.Model):
custom_id = models.IntegerField(default=0)
def save(self, flag=True, *args, **kwargs):
# Save your object. After this line, value of custom_id will be 0 which is default value
super(ABC, self).save(flag=True, *args, **kwargs)
# Here value of custom_id will be updated according to your id value
if flag:
self.custom_id = self.id + 10000
self.save(flag=False, *args, **kwargs)
flag is required as otherwise it will start recursion which will run infinitely.