Querying model data in form for cleaned DB - python

So I have forms.py which is as below:
from django import forms
from .models import SipExtension
from xmpp.models import xmpp_buddy_groups
class ExtensionForm(forms.Form):
xmpp_buddy_groups_choices = xmpp_buddy_groups.objects.values_list('group_name',flat=True)
boolean_choices=(('Yes','Yes'),('No','No'))
sip_extension = forms.IntegerField(min_value=0,max_value=100000)
sip_secret = forms.CharField(required=True,max_length=32)
commlink_push = forms.ChoiceField(choices=boolean_choices,widget=forms.CheckboxSelectMultiple,required=True)
real_name = forms.CharField(required=True,max_length=32)
xmpp = forms.ChoiceField(choices=boolean_choices,widget=forms.CheckboxSelectMultiple,required=True)
xmpp_username = forms.CharField(required = True,min_length=5)
xmpp_password = forms.CharField(max_length=32, widget=forms.PasswordInput)
xmpp_buddy_groups_names = forms.MultipleChoiceField(choices=xmpp_buddy_groups_choices,widget=forms.CheckboxSelectMultiple,required=False)
It works fine if my DB is already created by previous migrations. But I faced problem when my DB is blank. To test,I dropped all the tables and then run make migrations and got below error:
django.db.utils.ProgrammingError: relation "extensions_sipextension" does not exist
LINE 1: ...p_buddy_groups_names"."xmpp_buddy_groups_id" FROM "extension...
I am getting problems in handling this on blank database when I need to deploy on entirely new system. I could handle that by commenting the urls which are executing views which needs this form but that is a bad and temporary work around. How to fix this?

I think the issue is with xmpp_buddy_groups_choices attribute in the form. The queryset is evaluated at time of project load. So when you are using ./manage.py makemigrations, the xmpp_buddy_groups_choices trying to evaluate the queryset, but failed as there is no table in database. Try to wrap the choices in a function and pass that function in the choices parameter.
And your choices is required to be a list of tuples (with 2 elements), but the xmpp_buddy_groups_choices is a list of strings.
Sample Code:
class ExtensionForm(forms.Form):
#staticmethod
def get_group_choices():
xmpp_buddy_groups_choices = xmpp_buddy_groups.objects.values_list('group_name',flat=True)
return xmpp_buddy_groups_choices
boolean_choices=(('Yes','Yes'),('No','No'))
sip_extension = forms.IntegerField(min_value=0,max_value=100000)
sip_secret = forms.CharField(required=True,max_length=32)
commlink_push = forms.ChoiceField(choices=boolean_choices,widget=forms.CheckboxSelectMultiple,required=True)
real_name = forms.CharField(required=True,max_length=32)
xmpp = forms.ChoiceField(choices=boolean_choices,widget=forms.CheckboxSelectMultiple,required=True)
xmpp_username = forms.CharField(required = True,min_length=5)
xmpp_password = forms.CharField(max_length=32, widget=forms.PasswordInput)
xmpp_buddy_groups_names = forms.MultipleChoiceField(choices=ExtensionForm.get_group_choices,widget=forms.CheckboxSelectMultiple,required=False)

Related

django sql .raw filtering on a string not working

I am trying to filter on a foreign key but getting an error.
Current code is:
views.py
def kingmailboxcodesshow(request):
lname = "King"
lockbox_list = MailBoxCodes.objects.raw('SELECT * FROM mailboxcodes WHERE Address_id__contains %s',[lname])
return render(request,"users/mailboxcodesshow.html",{'MailBoxCodes':lockbox_list})
models.py
from django.db import models
from properties.models import Properties, Building_Name
from django.db.models import Q
# Create your models here.
class MailBoxCodes(models.Model):
id = models.AutoField(primary_key=True)
Address = models.ForeignKey(Properties, max_length=10, on_delete=models.CASCADE, default='Unknown',limit_choices_to=Q(StudentRental=True)| Q(Active=True))
MailBoxCode = models.CharField(max_length=10, null=False,default='000')
Active = models.BooleanField(default=True)
class Meta:
db_table = "mailboxcodes"
def __str__(self):
return str(self.Address)
receiving this error:
django.db.utils.ProgrammingError: (1064, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''King'' at line 1")
I am still really new to django and python, looking at the error I am thinking i need a few less ' around the King, but I am not sure how to make that happen.
I have a bunch of addresses in the Address_id and I just want to retrieve all the address with the work King in their street address.
The great thing with Django is that you don't need raw SQL queries, unless you really really know what you're doing. Please follow the official tutorial as it explains the fundamentals of Django and will guide you through this over here: Django tutorial
To help you out with this particular issue:
def kingmailboxcodesshow(request):
lname = "King"
lockbox_list = MailBoxCodes.objects.filter(address__name__contains=lname)
return render(request,"users/mailboxcodesshow.html",{'MailBoxCodes':lockbox_list})
Well there is no such thing as a __contains in SQL, that is just some Django logic that transforms it to a query, you can work with:
def kingmailboxcodesshow(request):
lname = 'King'
lockbox_list = MailBoxCodes.objects.raw(
'SELECT * FROM mailboxcodes WHERE Address_id LIKE %%%s%%', (lname,)
)
return render(
request, 'users/mailboxcodesshow.html', {'MailBoxCodes': lockbox_list}
)
That being said, using raw queries should be a last resort: the entire idea of Django's ORM is, as you actually found out with this question to make abstraction of query logic. You can run this with:
def kingmailboxcodesshow(request):
lname = 'King'
lockbox_list = MailBoxCodes.objects.filter(Address_id__contains=lname)
return render(
request, 'users/mailboxcodesshow.html', {'MailBoxCodes': lockbox_list}
)
Please share your MailBoxCodes model, and also tell what is this Address_id as you mentioned it is a foreign key in one of the comments above.
Try this:
def kingmailboxcodesshow(request):
lname = 'King'
lockbox_list = MailBoxCodes.objects.filter(Address__name__contains=lname)
return render(
request, 'users/mailboxcodesshow.html', {'MailBoxCodes': lockbox_list}
)
Or this:
MailBoxCodes.objects.filter(Address__contains=lname)
You can also use __icontains lookup for case-insensitive filtering.

Django Python With Gspread: 'choices' must be an iterable containing (actual value, human readable name) tuples

I am trying to do something that I have never seen done before with django, I am trying to make a model field(path_choices) that shows all of the unique path_names from my google sheet in a choice box so that the user can select one of them. However when I tried to make my choices CharField I am getting the error:
ERRORS:
dashboard.Robot.path_choices: (fields.E005) 'choices' must be an iterable containing (actual value, human readable name) tuples.
Right now the google sheet that I am trying to pull from with gspread only has two path-names, so if anybody has any idea on what is causing this problem or what I can do better with this, the help would be appreciated!
My Code (UPDATED CODE):
from django.db import models
class Robot(models.Model):
name = models.CharField(max_length=100)
status_choices = [('driving', 'driving'), ('waiting', 'waiting'), ('stuck', 'stuck')]
status = models.CharField(choices=status_choices, max_length=7, default='waiting')
path_choices = models.CharField(max_length=255)
My Form:
from django import forms
from django import forms
from .models import Robot
import gspread
from oauth2client.service_account import ServiceAccountCredentials
class RobotForm(forms.ModelForm):
def _generate_choices():
scope = ["REDACTED",'REDACTED',"REDACTED","REDACTED"]
creds = ServiceAccountCredentials.from_json_keyfile_name("dashboard/Files/creds.json", scope)
client = gspread.authorize(creds)
sheet = client.open("tutorial").sheet1
path_name_fetch = sheet.col_values(1)
path_names = []
temp_list = []
path_options = []
for i in path_name_fetch:
if i not in path_names:
path_names.append(i)
for path_name_options in path_names:
temp_list.append(f'{path_name_options}')
temp_list.append(f'{path_name_options}')
path_options.append(tuple(temp_list))
path_choices = forms.ChoiceField(choices=_generate_choices())
class Meta:
model = Robot
fields = {'path_choices'}
What you're trying to do may not be in line with the intended use of Choices. Whenever the possibilities of a Choice change at the Model level, new migrations must be made.
Your implementation of Choice for Robot.status is static and in line with the example in the Django documentation.
If instead you wanted to use a dynamic Choice for your path_choices that is retrieved from Google Sheets, I would recommend doing this in the ModelForm using a ChoiceField.
According to the documentation, the available choices can come from a callable, which would be your path_options wrapped in a function. path_options should then become a CharField without choices, since you manage those in the submission, rather than at the model level.
Models.py
class Robot(models.Model):
...
path_choices = models.CharField(max_length=255)
ModelForms.py
class RobotForm(ModelForm):
def _generate_choices():
# Query GSpread
choices = [('choice','choice'), ...]
return choices
path_choices = forms.ChoiceField(choices=_generate_choices())
class Meta:
model = Robot
fields = ['path_choices', ...]

Do i need to call create tables every time in peewee?

I working in a project in which i have different projects with the same database architecture,
so i used peewee Model in which:
dynamic_db = SqliteDatabase(None)
class BaseModel(Model):
class Meta:
database = dynamic_db
class KV (BaseModel):
key = TextField()
value = IntegerField()
And whenever i new project is created i will call a function
dynamic_db.init(r'{}\database.db'.format(ProjectName.upper()))
dynamic_db.connect()
dynamic_db.create_tables([KV])
dynamic_db.close()
The problem is that once this database is created, i can't access with peewee.
When i try to create a record:
KV.create(key = 'Saul', value = 123)
I get this error:
peewee.InterfaceError: Error, database must be initialized before opening a connection.
I would appreciate any help or cookbook for peewee.
I believe something is incorrect, either in your question description, or in the error you are receiving. The call you are making to .init() is what initializes the database. After that, you should have no problems using it.
Full example which works fine:
from peewee import *
db = SqliteDatabase(None)
class Base(Model):
class Meta:
database = db
class KV(Base):
key = TextField()
value = IntegerField()
db.init('foo.db') # database is now initialized
db.connect()
db.create_tables([KV]) # no problems.
db.close()
I was finally able to create a record.
I didn't mention that i was trying to create them in another file, but the procedure is the same as the one coleifer posted on the answer.
The file in which i create the peewee models is databases.py, so in the other file i do the following:
import databases
databases.db.init('foo.db')
databases.KV.create(name = 'Saul', value= 123)
Thanks!

DJANGO:How to perform AND operation for my query?

There are two models .I want to make query to extract only the app exact app related Adspaces .
models.py
class Appname(models.Model):
user=models.ForeignKey(User,related_name='appname', null=True, default=None,on_delete=models.CASCADE)
name=models.CharField(max_length=150,blank=False,null=False,help_text='Add your new App')
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse("dashapp:space",kwargs={'pk':self.pk})
class Adspace(models.Model):
user=models.ForeignKey(User,related_name='adspace', null=True, default=None,on_delete=models.CASCADE)
ad_space=models.CharField(max_length=150,blank=False,null=False)
app=models.ForeignKey('Appname', related_name='appnames',default=None, on_delete=models.CASCADE)
PID_TYPE = (
('FN','FORMAT_NATIVE'),
('FNB','FORMAT_NATIVE_BANNER'),
('FI','FORMAT_INTERSTITIAL'),
('FB','FORMAT_BANNER'),
('FMR','FORMAT_MEDIUM,RECT'),
('FRV','FORMAT_REWARDED_VIDEO'),
)
format_type=models.CharField(max_length=3,choices=PID_TYPE,default='FN',blank=False, null=False)
def __str__(self):
return self.ad_space
def get_absolute_url(self):
return reverse("dashapp:create",kwargs={'pk':self.pk})
Views.py
SHowing the one where i need to the query
class spacelist(LoginRequiredMixin,ListView):
model=Adspace
template_name='adspace_list.html'
def get_queryset(self):
query_set=super().get_queryset()
return query_set.filter(user=self.request.user)
Here I need to perform One more query so that EACH APP show their own adspaces when clicked right now every app show every show adspaces.
I have the idea what to do as if i compare app_id then it'll show the exact app related adspaces, but i dont know how to write query for the same as i already have one query present.???
You could try using a Q objects: https://docs.djangoproject.com/en/2.1/topics/db/queries/#complex-lookups-with-q-objects
From what I understand you are trying to filter both on the app_id and the request user at the same time, so you could try look something like this:
from django.db.models import Q
...
def get_queryset(self):
query_set=super().get_queryset()
return query_set.filter(Q(user=self.request.user) & Q(app_id=app_id))
...
This lets you do a single filter with both your requirements at the same time (i.e. retrieve the Adspace instances for a specific user with a specific Appname).
You chain another filter at the end like this:
class spacelist(LoginRequiredMixin,ListView):
model=Adspace
template_name='adspace_list.html'
def get_queryset(self):
query_set = super().get_queryset()
query_set = query_set.filter(user=self.request.user)
app_id = [...]
return query_set.filter(app_id=app_id)
The problem left is to find out what is the app_id coming from. How do you know what is the current app? Several options here.
Option 1: From the request
It can come from the current user: self.request.user.appname.all() but that will give you multiple apps, if the user can only have one app, you should change your model Appname.user to a OneToOneField.
Otherwise, I suggest changing your related_name='appnames' to reflect the multiplicity in the reverse relationship.
Option 2: From the URL
It can come from the URL, your space list view should extract an app_id parameter from the URL where it's defined:
url(r'^(?P<app_id>[0-9]+)/spaces/$', spacelist.as_view(), name='space_list'),
And then in the spacelist view, you would get this parameter like this:
app_id = self.kwargs['app_id']
return query_set.filter(app_id=app_id)
Hope that helps
UPDATE:
Also worth noting that QuerySets are lazy, meaning the result will get evaluated as late as possible by Django. Therefore, when you call:
query_set = query_set.filter(user=self.request.user)
The Django ORM doesn't execute any DB queries yet, and you can chain more filters after that:
query_set = query_set.filter(user=self.request.user)
query_set = query_set.filter(app_id=app_id)
Which behind the scenes is extending the query that will be executed when required. But at this point, no query is actually run. To see the query that will get executed you can print out the query attribute of the QuerySet:
print(query_set.query)
Which should log something like:
SELECT "app_adspace"."user_id" ...
FROM
"app_adspace"
WHERE
"app_adspace"."user_id" = 1234 AND "app_adspace"."app_id" = 5678

Django: Key (slug)=(*) already exists

I'm pretty new to Django and python and I'd like to learn more about how to populating my Postgres database.
Here is my current model: models.py
from django.template.defaultfilters import slugify
class Skill(models.Model):
name = models.TextField()
slug = models.TextField(unique = True)
def __unicode__(self):
return "%s" % self.name
and my views: views.py
r = r.json()
try:
Skills = r['data']['skills']
except:
pass
for skill in Skills:
skill = Skill.objects.create(name=skill['name'],slug=slugify(skill['name']))
I'm getting the error:
Exception Type: IntegrityError
DETAIL: Key (slug)=(systems-engineering) already exists.
I've been reading a similar post although still haven't been able to solve my problem. objects.create() will shows an error when the object already exists in the database, but I was getting error with the code above. Could "unique = True" be causing the error? and how do you fix this?
Follow up
My problem is simpler than I thought. I was able to run psql interactive terminal and see my data populating. I wasn't able to see it on the admin site because I missed out registering the models on admin.py
When you provide unique=True, the field will be unique throughout the table. Hence, when you try to add a data which is already in DB, it will raise an error. See this official doc for more details

Categories