I'm running a django app and I've implemented MySQL. When I run the server and try to load the page I get the error "badly formed hexadecimal UUID string." This occurs in the uuid.py file in init at line 140 and from what I can tell, this occurs because the value hex is not of length 32 but I don't know how to address this issue.
This is the model that the entries in the database follow.
from django.db import models
import uuid
from django.db.models import (
UUIDField,
CharField,
TextField,
IntegerField,
DecimalField,
ImageField
)
# Create your models here.
class AnimeCatalog(models.Model):
anime_id = UUIDField(primary_key = True, default=uuid.uuid4, editable=False)
name = CharField(max_length=300)
genre = CharField(max_length=300)
typeanime = CharField(max_length = 10)
episodes = IntegerField(default=0)
rating = DecimalField(max_digits = 4, decimal_places = 2, null = True)
members = IntegerField()
anime_cover = ImageField(blank = True, null = True, upload_to = "img/animeCover", verbose_name = "Profile Photo")
Then I try to call the objects.all() method on this model to retrieve it from mysql in the views.py file which is below
from django.shortcuts import render
from django.http import HttpResponse, HttpResponseRedirect
from django.views import View
from .forms import AnimeCatalogForm
from .models import AnimeCatalog
from .WebScraping import findAnimePic
import csv
from django.core.paginator import Paginator
# Create your views here.
def home(request):
temp = []
tempID = []
pics = []
fiveNames = []
names = []
new = AnimeCatalog.objects.all()
for line in new:
temp.append(line['name'].replace(''', ''))
tempID.append(line['anime_id'])
for x in range(0,5):
pics.append(findAnimePic(tempID[x],temp[x]))
for x in range(0, len(temp), 5):
for y in range (5):
if not(x+y >= len(temp)):
fiveNames.append({'name':temp[x+y],'img':pics[y]})
names.append(fiveNames)
fiveNames = []
items = {'names': names, 'imgs': pics}
html = render(request, 'home/home.html', {'names':names})
return html
Also this is a picture of the first few entries in the mysql which i imported a csv file.
Image of mysql database with imported csv files
As is clear from that screenshot, anime_id contains integers, not UUIDs. I don't know why you set it to be a UUIDField but you should use AutoField instead and remove the default.
Related
models.py
from django.db import models
from django.utils import timezone
from django.urls import reverse
from django.contrib.auth.models import User
class Customer(models.Model):
username = models.ForeignKey(User,on_delete=models.CASCADE)
name = models.CharField(max_length=20,null=True)
def __str__(self):
return self.name
# Create your models here.
class Booking(models.Model):
customer_name = models.ForeignKey(Customer,on_delete=models.CASCADE,null=True)
username = models.ForeignKey(User,on_delete=models.CASCADE)
qty_plts = models.PositiveSmallIntegerField(default=1)
cbm = models.PositiveSmallIntegerField(default=1)
created_date = models.DateTimeField(default=timezone.now())
delivery_date = models.DateField(null=True)
delivery_time = models.TimeField(null=True)
booking_number = models.CharField(max_length=50,unique=True)
def __str__(self):
return self.booking_number
def save(self, **kwargs):
if not self.booking_number:
self.booking_number = f"{self.delivery_date:%Y%m%d}{self.delivery_time:%H%M}"
super().save(**kwargs)
def get_absolute_url(self):
return reverse('bookmyslot:detail',kwargs={'pk':self.pk})
forms.py
from django import forms
from bookmyslot.models import Booking,Customer
from bootstrap_datepicker_plus import DatePickerInput
import datetime as dt
from django.utils import timezone
HOUR_CHOICES = [(dt.time(hour=x), '{:02d}:00'.format(x)) for x in range(7, 13)]
class BookingForm(forms.ModelForm):
def __init__(self,*args,**kwargs):
user = kwargs.pop('username',None)
super(BookingForm,self).__init__(*args,**kwargs)
self.fields['qty_plts'].label = "Quantity Of Pallets"
self.fields['cbm'].label = "Shipment CBM"
self.fields['delivery_date'].label = "Delivery Date"
self.fields['delivery_time'].label = "Delivery Time"
self.fields['customer_name'].label = "Customer Name"
self.fields['customer_name'].queryset = Customer.objects.filter(username=user)
def clean(self):
cleaned_data = super(BookingForm,self).clean()
booking_number = f"{cleaned_data.get('delivery_date'):%Y%m%d}{cleaned_data.get('delivery_time'):%H%M}"
if Booking.objects.filter(booking_number=booking_number).exists():
raise forms.ValidationError("Requested slot is already booked, please choose another time")
class Meta:
model = Booking
fields = ('customer_name','qty_plts','cbm','delivery_date','delivery_time')
widgets = {'delivery_date':DatePickerInput(options={"daysOfWeekDisabled":[0,6],"minDate":timezone.now().date().strftime('%Y-%m-%d')}),
'delivery_time':forms.Select(choices=HOUR_CHOICES)}
views.py
from django.shortcuts import render
# Create your views here.
from .models import Booking,Customer
from .forms import BookingForm
from django.urls import reverse,reverse_lazy
from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import (ListView,DetailView,CreateView,UpdateView,DeleteView,TemplateView)
class BookingCreate(LoginRequiredMixin,CreateView):
login_url = '/login'
redirect_field_name = 'bookmyslot/booking_detail.html'
model = Booking
form_class = BookingForm
def get_form_kwargs(self, **kwargs):
form_kwargs = super(BookingCreate,self).get_form_kwargs(**kwargs)
form_kwargs['username'] = self.request.user
return form_kwargs
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.username = self.request.user
self.object.save()
return super().form_valid(form)
I am trying to figure out how to return a list of available time slots, using a ValidationError.
There are 6 time slots [delivery_time] to choose from on any given date -> [7,8,9,10,11,12]
The booking_number field is a unique id that is a concatenation of the delivery_date and delivery_time, which is generated each time a user successfully creates a booking.
So, let's assume there are 3 existing bookings for 2021-10-21 at 7:00,08:00 & 10:00, which are saved in the Booking model with the following booking numbers:
202110210700
202110210800
202110211000
Assuming a user tries to book over a slot that already exists e.g. 202110210700,
the validation error should return "Requested slot is already booked, please choose another from one of these available slots:
09:00
11:00
12:00
How can I achieve this?
You can use an utility function like this to return the remained time slot in the form validation like this :
app_name/utilities.py
def list_diff(l1: list, l2: list):
""" Return a list of elements that are present in l1
or in l2 but not in both l1 & l2.
IE: list_diff([1, 2, 3, 4], [2,4]) => [1, 3]
"""
return [i for i in l1 + l2 if i not in l1 or i not in l2]
def check_free_time(time_slot: list, exist_list: list):
""" Return the list of available time slot if exist,
according to a given exist slot list.
Return the remained time slot, or empty list if all are used
IE: ([7, 12], [7, 8, 9, 10, 11, 12]) => [8, 9, 10, 11]
"""
remain_slot = list_diff(time_slot, exist_list)
return remain_slot
Now import the check_free_time in your forms.py file and use it if the booking_number exist.
from datetime import datetime
from .utilities import check_free_time
if Booking.objects.filter(booking_number=booking_number).exists():
today = datetime.today()
d = today.day
m = today.month
y = today.year
# Retrieve today's bookings
today_bookings = Booking.objects.filter(delivery_date__year=y,delivery_date__month=m delivery_date__day=d)
# A list of today's bookings time slot (take only hours)
# Return something like <QuerySet [{'delivery_date__hour': 11}, ...]>
today_time_slot = today_bookings.values('delivery_date__hour')
# Convert it to list of hours values since the utility function accept list.
today_time_slot_list = [h['delivery_date__hour'] for h in list(today_time_slot)]
# The line above return something like [9, 11, ...]
all_time_slot = [7, 8, 9, 10, 11, 12]
# Now we can call the utility function `check_free_time`
available_slot = check_free_time(all_time_slot, today_time_slot_list)
if available_slot: # The are some available slot (list not empty)
# I use python3.6 f-string to format the message
# Note that the list is in a raw format ([8,11,12]), you can do better like ['8h:00', '11h:00', '12h:00']
message = f"Requested slot is already booked, please choose another time in {available slot}."
raise forms.ValidationError(message)
else: # The list is empty, all slot are taken
message = "The are not available slot for this booking today."
raise forms.ValidationError(message)
NB : I tested only in a python an Django shell, if some errors try to add in comments.
I'm creating a quiz project using Django with MongoEngine. Multiple Choice Questions and quiz are two separated apps. I want to fetch multiple choice in quiz based on m_id (unique number for each multiple choice). I'm a beginner and need a little help. How can i achieve thisMCQS Model
from django_mongoengine import Document, EmbeddedDocument, fields
class multichoice(Document):
m_id = fields.IntField(min_value=1, verbose_name='MCQ Id')
m_title = fields.StringField(primary_key=True, max_length=255, verbose_name='Title')
m_question = fields.StringField(verbose_name='Question')
m_alternatives = fields.ListField(fields.StringField(),verbose_name='Alternatives')
def __str__(self):
return self.m_title
Quiz Model
from django_mongoengine import Document, EmbeddedDocument, fields
from mcqs.models import *
class quiz(Document):
q_id = fields.IntField(min_value=1, verbose_name='Quiz ID')
q_title = fields.StringField(primary_key=True, max_length=255, verbose_name='Title')
q_s_description = fields.StringField(max_length=255, verbose_name='Description')
q_questions = fields.ListField(fields.IntField(), verbose_name='Question Numbers', blank=True)
def __str__(self):
return self.q_title
MCQ Views
def view_multichoice(request, m_id):
get_md = multichoice.objects(m_question_number = m_id)
return render(request, 'mcqs/mcq.html', {'get_md':get_md})
Quiz Views
def view_quiz(request, q_id):
get_q = quiz.objects(q_id = q_id)
return render(request, 'quiz/quiz.html', {'get_q':get_q})
Current Result
Expected Result
EDIT 1
Quiz Views
from django.shortcuts import render
from django.http import HttpResponse
from .models import *
from mcqs.models import *
def view_quiz(request, q_id):
quiz_object = quiz.objects(q_id=q_id)[0]
multichoice_objects = [multichoice.objects(m_id=id) for id in quiz_object.q_questions]
get_q = [objects[0].m_question for objects in multichoice_objects if objects]
return render(request, 'quiz/quiz.html', {'get_q':get_q})
Quiz Template
{{ get_q }}
You are returning the question documents as it is. What you should be doing is, fetch the multichoice documents corresponding to the question ids, and then get the question field from each of those documents.
Change the second line in quiz views to this:
# Get the question document corresponding to given id
# objects method returns a list. Get the first one out of it.
# Here, I've assumed there's exactly 1 quiz document per ID. Handle the edge cases
quiz_object = quiz.objects(q_id = q_id)[0]
# Get the multiple choice documents corresponding to the ids in q_questions list
# Remember that objects method returns a list. Hence this is a list of lists
multichoice_objects = [multichoice.objects(m_id=id) for id in quiz_object.q_questions]
# Get the actual questions from the multichoice documents
get_q = [objects[0].m_question for objects in multichoice_objects if objects]
Ideally, you should be making multichoice as an EmbeddedDocument and the q_questions field in quiz model as EmbeddedDocumentListField. But the drawback here will be, you can't query EmbeddedDocuments independently. So you wont be able to do multichoice.objects(m_question_number=m_id).
You can read more about EmbeddedDocuments here
I need to override variables (or pass dynamic data) to imported class.
filters.py
import django_filters
from .models import Gate, Tram, OperationArea, Bogie
from distutils.util import strtobool
from django import forms
class GateFilter(django_filters.FilterSet):
# Prepare dynamic lists with choices
tram_list = [(id, number) for id, number in Tram.objects.all().values_list('id', 'number')]
bogie_list = [(id, number) for id, number in Bogie.objects.all().values_list('id', 'number')]
area_list = [(id, area) for id, area in OperationArea.objects.all().values_list('id', 'area')]
# Generate fields
tram = django_filters.MultipleChoiceFilter(choices=tram_list, label=u'Tramwaj')
car = django_filters.MultipleChoiceFilter(choices=Gate.CAR_SYMBOLS, label=u'Człon')
bogie = django_filters.MultipleChoiceFilter(choices=bogie_list, label=u'Wózek')
bogie_type = django_filters.MultipleChoiceFilter(choices=Gate.BOGIE_TYPES, label=u'Typ wózka')
area = django_filters.MultipleChoiceFilter(choices=area_list, label=u'Obszar')
operation_no = django_filters.CharFilter(label=u'Numer operacji', widget=forms.TextInput(attrs={'size': '16px'}))
status = django_filters.MultipleChoiceFilter(choices=Gate.GATE_STATUSES, label=u'Status')
rating = django_filters.MultipleChoiceFilter(choices=Gate.GATE_GRADES, label=u'Ocena')
class Meta:
pass
views.py
from .filters import GateFilter
class GateListView(generic.ListView):
queryset = None
gate_type = None
template_name = 'qapp/gate/list.html'
context_object_name = 'gate_list'
paginate_by = 20
def get_queryset(self):
# Type is stored in database as big-letter word, so 'bjc' != 'BJC'.
if self.gate_type.upper() == 'BJW':
ordering = ['bogie', 'bogie_type']
else:
ordering = ['tram', 'car']
queryset = Gate.objects.filter(type=self.gate_type.upper()).order_by(*ordering)
self.gate_list = GateFilter(self.request.GET, queryset=queryset)
return self.gate_list.qs.distinct()
def get_context_data(self, **kwargs):
context = super(GateListView, self).get_context_data(**kwargs)
# Return Gate.type to template.
context['gate_type'] = self.gate_type
# Return object (for generating form) to template.
context['gate_list_filter'] = self.gate_list
return context
As you can see, in the filters.py, the data for variables tram_list, bogie_list and area_list are dynamic (fetched from database).
But during importing this class to views.py, this data becomes static.
I tried to override this values:
using #classmethod decorator in class GateFilter, and calling it
before setting self.gate_list object,
in views.py using GateFilter.tram_list (and the rest) notation,
No luck.
I can't use reload() function, due to import type (from .filters import GateFilter).
Currently for update lists in filters.py I need to rerun whole app.
This is unacceptable for business logic of my app.
This is the wrong approach. Rather, you should be using the filters that are aware of querysets and that evaluate them when required: ModelChoiceFilter and ModelMultipleChoiceFilter.
class GateFilter(django_filters.FilterSet):
team = django_filters.ModelMultipleChoiceFilter(queryset=Tram.objects.all())
======= Update =======
#JF brought forward a brilliant perspective for the use of model mommy in ModelForms.
With the following code, I managed to automatically generate random data for all the fields of the model, except for the ones I would like to manipulate.
tests.py:
from django.test import TestCase
from houses.forms import ManForm
from houses.models import Man
class ModelsTest(TestCase):
def test_Man(self):
man = mommy.make('Man', age=20)
data = {each_field.name: getattr(man, each_field.name) for each_field in man._meta.fields}
data.update({'age_verification': 20})
form = ManForm(data)
self.assertTrue (form.is_valid())
models.py
from django.db import models
class Man(models.Model):
name = models.CharField(max_length = 12)
age = models.PositiveSmallIntegerField()
forms.py:
from my_app.models import Man
from django import forms
from django.core.exceptions import ValidationError
class ManForm(forms.ModelForm):
age_verification = forms.IntegerField()
def clean(self):
if not self.cleaned_data['age'] == self.cleaned_data['age_verification']:
raise ValidationError("Is this a LIE?")
class Meta:
model = Man
fields = ['name', 'age', 'age_verification']
For the time being, I test it like this:
tests.py:
from django.test import TestCase
from houses.forms import ManForm
class ModelsTest(TestCase):
def test_Man(self):
data = {
'name' = 'John',
'age' = 20,
'ege_verification' = 20,
}
form = ManForm(data)
Is there a tool that provides random data for Forms?
Or ... can I use the available tools for models for this purpose?
Searching the docs of those supporting Python 3, I did not understand how this could be achieved.
The only one that clearly provides such a service is Django-Whatever which is not python3 compatible.
If you don't want to type the name of each attribute, you can do this:
from model_mommy import mommy
from django.forms import model_to_dict
class ModelsTest(TestCase):
def test_Man(self):
man = mommy.make('Man')
data = model_to_dict(man)
form = ManForm(data)
You could do something like this:
from model_mommy import mommy
class ModelsTest(TestCase):
def test_Man(self):
man = mommy.make('Man', _fill_optional=True)
data = {
'name': man.name,
'age': man.age,
'age_verification': man.age_verification,
}
form = ManForm(data)
I have 2 applications in my "aplikacja" django project:
articles
qr
From articles model I would like to get a value "title" from the first article and then put it into qr.views (it prepares for me a pdf file)
Articles models:
from django.db import models
class Article(models.Model):
title = models.CharField(max_length=150)
content = models.TextField(verbose_name="Zawartosc")
published = models.DateTimeField(verbose_name="Data Publikacji")
How to get a "title" value into qr views?
I suppose I need to import article from aplikacja.articles.models. But how to get exactly value in test_qr method?
from reportlab.pdfgen import canvas
from django.http import HttpResponse
from reportlab.graphics.shapes import Drawing
from reportlab.graphics.barcode.qr import QrCodeWidget
from reportlab.graphics import renderPDF
from django.contrib.auth.models import User
from aplikacja.articles.models import article
def test_qr(request):
# Create the HttpResponse object with the appropriate PDF headers.
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="somefilename.pdf"'
a= map(lambda x: str(x), User.objects.values_list('id', flat=True).order_by('id'))
p = canvas.Canvas(response)
p.drawString(10, 800, a[1])
qrw = QrCodeWidget(a[1])
b = qrw.getBounds()
w=b[2]-b[0]
h=b[3]-b[1]
d = Drawing(200,200,transform=[200./w,0,0,200./h,0,0])
d.add(qrw)
renderPDF.draw(d, p, 1, 1)
p.showPage()
p.save()
return response
To get the first article use the first() method:
article = article.objects.all().order_by('published').first()
title = article.title if article else None
BTW python lists are zero based so to get the first element of a list you should use a[0] instead of a[1]. But anyway I suggest you to use the same first() method to get the id of the first user:
first_user_id = str(User.objects.values_list('id', flat=True) \
.order_by('id').first())