how to make connection between two classes in python3 - python

hi i have two classes Book and Library with a text file (my_text.txt including these data
danial feldroy - two scoops of django
james brown - python3 with examples
in the Book class
class Book():
def __init__(self,author,title):
self.title = title
self.author = author
def __str__(self):
return f"Author: {self.author}, Title: {self.title}"
Library takes one input variable, name, which is a string that represents the name of the library
class Library:
def __init__(self, name):
self.name = name
books = {}
# add_book takes a Book instance, and checks to see if the Book is not in self.books. If it's not
# then a new key value pair is added to the dictionary. If it is in books, then the data stored
# in the key 'available' is updated for that book.
def add_book(self, book_inst):
if (book_inst.author, book_inst.title) not in self.books:
self.books[(book_inst.author, book_inst.title)] = {"checked_out": 0, "available": 1}
else:
self.books[(book_inst.author, book_inst.title)]["available"] +=1
# can_check_out will take a Book instance as input. Checks to see if the book is in the dictionary
# of books. If it is, then it checks to see if the value of available is 1 or more. If it is, then it
# returns True. If it does not, then it returns False. If the book cannot be found, then a string is returned
# to the user to inform them of this occurrence.
def can_check_out(self, book_inst):
book = (book_inst.author, book_inst.title)
if book in self.books:
if self.books[book]["available"] >= 1:
return True
else:
return False
else:
return "The book you are looking for has not been added to this library yet."
f = open('my_text.txt').readlines()
book_list = []
for book in f:
instance = tuple((x.strip() for x in book.split('-')))
book_list.append(instance) # the variable instance should be assigned an instance of the Book class.
There is an instance of the Library class called books; i have to add all of the Book instances to books variable
books = Library("Hatcher Graduate Library")
#i have to write the code here
i need to add data to the Book
i have to access to Book through books like this
print(books.can_check_out(Book('Statistics for all', 'jim james')))
i much appreciate your helps ..

You may want to look into class inheritance, it is basically a connector between two classes, where one derives from the other.

Related

In Python, can I create or inherit an object out of another object without losing or overriding previously existing attributes from the older object?

Say I have a base class called Publication:
class Publication():
def __init__(self, title='Default', price='Default')
self.title = title
self.price = price
def gettitle(self):
self.title = input("Please type in a title: ")
def getprice(self):
self.price = input("Please type in a price: ")
And a subclass called Book that inherits from Publication:
class Book(Publication):
def __init__(self, title, author, pages, current_page, price):
super().__init__(title, price)
self.author = author
self.pages = pages
self.current_page = current_page
def turnpage(self.current_page):
self.current_page += 1
Let's say early on in the course of my program, I create an object from the Publication class:
item = Publication()
But later on I have to assign my title and my price:
item.gettitle()
item.getprice()
I input "Lord of the Rings" and 10.99 respectively so now
item.title = "Lord of the Rings"
and
item.price = 10.99
Now, let's say I have some logic in my program that, depending on the price or if the title matches a string in a list, then we know specifically it is a book (as opposed to something like a magazine or a newspaper) so now I'd like it to be
item = Book()
When I originally created my object from the Publication class, I didn't know it was a Book. But now that I know, is there a way for me to keep the attributes/methods bound to the originally created object while "extending"/"inheriting" the object (not sure if those are the right words) with the newly available attributes from the Book class?
item = Book(title=item.gettitle(), price=item.getprice())
Or you can add a method in Publication that will give you the array which contains all characteristics of class, and in the __init__ function get all needed parameters by array. Another way is to pass item as an argument so __init__ will get all attributes from created object

Check if object has relation with other in ManyToMany field and aggregate field

I have a couple models as follows:
class Student(models.Model):
name = models.CharField()
classes = models.ManyToManyField(Class, related_name="students")
class Class(models.Model):
nombre = models.CharField
What I need is a way such that, when querying students in certain class, instead of just returnig the students enrolled in that class, it returns a QuerySet of all the students, each one with an aggregated field indicating if such student is enrolled in that class, e.g.:
[{'name':'student A', 'enrolled_in_physics':True}, {'name':'student B', 'enrolled_in_physics':False}]
I think it can be achieved through F() expressions along with ExpressionWrapper, but have no idea of how implement them; additionaly, the documentation and the examples are not very noob-friendly. Any help is appreciated, thanks!.
EDIT: Ok, I think using the word "list" is not the correct one, I need a normal QuerySet, such that let me do something like this:
student_a = query[0]
student_a.name
>>>'A'
student_a.enrolled_in_physics
>>>True
UPDATED
You could try defining a method within the student class:
class Student(models.Model):
name = models.CharField()
classes = models.ManyToManyField(Class, related_name="students")
def enrolled_in_class(self,class_name):
if len(Class.objects.filter(nombre=class_name,students__in=self)) > 0:
return True
else:
return False
students = Student.objects.all()
student_a = students[0]
student_a.name
student_a.enrolled_in_class('physics')
Original Answer:
Edit: Sorry misread question, I'll try and get an answer together for what you actually wanted: A list of all students, and binary true false if they are enrolled in a specific class.
Alright, I'm reading this as a:
I need a query that returns a list of dictionaries, indicating the student, and enrollment in a class.
#Assume: class_name = 'physics'
def get_class_list(class_name):
filtered_class = Class.object.get(nombre=class_name)
student_names = Students.objects.filter(classes__contains=filtered_class).values_list('name',flat=True)
class_list = []
for name in student_names:
class_list = {}
class_list['name'] = name
enrolled_class_string = 'enrolled_in_' + class_name
class_list[enrolled_class_string] = True
return class_list
This will give you a list of dictionaries with the keys named 'name', and 'class__name'

How to search within a class from a menu or add to a class from menu-python

I am creating a phone book with python and was stumped on how to search through the class for a specific contact or how to search for a specific entry in the class.
This is what I have so far:
class person:
def __init__(self, first_name, last_name, phone_number):
person.first = first_name
person_last = last_name
person_number = phone_number
class friend:
def __init__(self, email, birth_date):
email = johnny.seagraves8219
birth_date = 8/13/1993
super(friend, self)._init_
ans = True
while ans:
print("""
1. Add a contact
2. Look up contact by name
Press enter to quit
""")
ans = input("What would you like to do?")
if ans == "1":
elif ans == "2":
look_up = input("Who would you like to look up?")
The class will not have entries that you can search through as far as I know. The class is basically just a constructor which is used to create an instance of a, in this case, person in the phone book. You could use an array to hold the instances and then search the array.
for i in arrayName:
if(arrayName[i].first == look_up):
# do something
To create an instance simply call the constructor:
firstPerson = person("Mike", "Ryans", "1800838699")
arrayName.append(firstPerson)
My knowledge of python is fairly limited but this is what I think should work.
Good luck!
To begin with, Flexicon is correct: your person/friend class is just a single entity that holds only a single persons information. To be able to search for people, you'll either need to make an array (list) of person objects, a map (dictionary) mapping a name or nickname to the object (so {'Timmie': <my_timidger_object>}, or you can wrap one of these approaches in a AddressBook class that contains additional methods that one of those basic data structures cannot do for you.
Some other important problems: your friend class does not extend the person, the constructor for a class has two underscores, like __init__; as well, you should add default values for email and birth_date in the person class, or trying to access these later will cause an error; your attribute need self before them or they will not be treated as attribute for the object
Here is Object Orientated (using a list to hold the people) way to do it, though it might be overkill for something this simple:
class person:
def __init__(self, first_name, last_name, phone_number):
self.person.first = first_name
self.person_last = last_name
self.person_number = phone_number
self.email = None #Notice the placeholders?
self.birth_date #Not having this information should not be exceptional
class friend(person): #Here, friend extends person
def __init__(self, email, birth_date):
self.email = email
self.birth_date = birth_date
super(friend, self).__init__()
class AddressBook:
def __init__(self, people = None):
if people:
self.entries = list(people)
else:
self.entries = []
#This is merely an example method, a better way would be to use some relational method like SQL to put in a query to find specific information about the person, but that is beyond the scope of this answer
def find_num(self, first_name, last_name):
for person in self.entries:
if (person.last_name, person.first_name) == (last_name, first_name):
return person
return None

django - how to sort objects alphabetically by first letter of name field

I have a model which has the fields word and definition. model of dictionary.
in db, i have for example these objects:
word definition
-------------------------
Banana Fruit
Apple also Fruit
Coffee drink
I want to make a query which gives me, sorting by the first letter of word, this:
Apple - also Fruit
Banana - Fruit
Coffee -drink
this is my model:
class Wiki(models.Model):
word = models.TextField()
definition = models.TextField()
I want to make it in views, not in template. how is this possible in django?
Given the model...
class Wiki(models.Model):
word = models.TextField()
definition = models.TextField()
...the code...
my_words = Wiki.objects.order_by('word')
...should return the records in the correct order.
However, you won't be able to create an index on the word field if the type is TextField, so sorting by word will take a long time if there are a lot of rows in your table.
I'd suggest changing it to...
class Wiki(models.Model):
word = models.CharField(max_length=255, unique=True)
definition = models.TextField()
...which will not only create an index on the word column, but also ensure you can't define the same word twice.
Since you tagged your question Django, I will answer how to do it using Django entities.
First, define your entity like:
class FruitWords(models.Model):
word = models.StringField()
definition = models.StringField()
def __str__(self):
return "%s - %s" % (self.word, self.definition)
To get the list:
for fruit in FruitWords.all_objects.order_by("word"):
print str(fruit)
If you are using class based ListView
class WikiListView(ListView):
model = Wiki
template_name = # Path to your html code. Example: 'appName/htmlFileName.html
def get_context_data(self, *args, **kwargs):
wiki_list = Wiki.objects.order_by('word')
context = super(WikiListView, self).get_context_data(*args, **kwargs)
context["wiki_list"] = wiki_list
return context
if you are using a simple view
def WikiView(request):
wiki_list = Wiki.objects.order_by('word')
return render(request, """HTML File""", {'wiki_list': wiki_list})
for example, I have an Article object that have a title field.
articles = list(sorted(articles, key=lambda obj:obj.title))
the issue you may run into is that you must require to return a QuerySet in class method occasions like get_queryset, the solution is stopping using a class based view and switch to a function view.

How would you inherit from and override the django model classes to create a listOfStringsField?

I want to create a new type of field for django models that is basically a ListOfStrings. So in your model code you would have the following:
models.py:
from django.db import models
class ListOfStringsField(???):
???
class myDjangoModelClass():
myName = models.CharField(max_length=64)
myFriends = ListOfStringsField() #
other.py:
myclass = myDjangoModelClass()
myclass.myName = "bob"
myclass.myFriends = ["me", "myself", "and I"]
myclass.save()
id = myclass.id
loadedmyclass = myDjangoModelClass.objects.filter(id__exact=id)
myFriendsList = loadedclass.myFriends
# myFriendsList is a list and should equal ["me", "myself", "and I"]
How would you go about writing this field type, with the following stipulations?
We don't want to do create a field which just crams all the strings together and separates them with a token in one field like this. It is a good solution in some cases, but we want to keep the string data normalized so tools other than django can query the data.
The field should automatically create any secondary tables needed to store the string data.
The secondary table should ideally have only one copy of each unique string. This is optional, but would be nice to have.
Looking in the Django code it looks like I would want to do something similar to what ForeignKey is doing, but the documentation is sparse.
This leads to the following questions:
Can this be done?
Has it been done (and if so where)?
Is there any documentation on Django about how to extend and override their model classes, specifically their relationship classes? I have not seen a lot of documentation on that aspect of their code, but there is this.
This is comes from this question.
There's some very good documentation on creating custom fields here.
However, I think you're overthinking this. It sounds like you actually just want a standard foreign key, but with the additional ability to retrieve all the elements as a single list. So the easiest thing would be to just use a ForeignKey, and define a get_myfield_as_list method on the model:
class Friends(model.Model):
name = models.CharField(max_length=100)
my_items = models.ForeignKey(MyModel)
class MyModel(models.Model):
...
def get_my_friends_as_list(self):
return ', '.join(self.friends_set.values_list('name', flat=True))
Now calling get_my_friends_as_list() on an instance of MyModel will return you a list of strings, as required.
What you have described sounds to me really similar to the tags.
So, why not using django tagging?
It works like a charm, you can install it independently from your application and its API is quite easy to use.
I also think you're going about this the wrong way. Trying to make a Django field create an ancillary database table is almost certainly the wrong approach. It would be very difficult to do, and would likely confuse third party developers if you are trying to make your solution generally useful.
If you're trying to store a denormalized blob of data in a single column, I'd take an approach similar to the one you linked to, serializing the Python data structure and storing it in a TextField. If you want tools other than Django to be able to operate on the data then you can serialize to JSON (or some other format that has wide language support):
from django.db import models
from django.utils import simplejson
class JSONDataField(models.TextField):
__metaclass__ = models.SubfieldBase
def to_python(self, value):
if value is None:
return None
if not isinstance(value, basestring):
return value
return simplejson.loads(value)
def get_db_prep_save(self, value):
if value is None:
return None
return simplejson.dumps(value)
If you just want a django Manager-like descriptor that lets you operate on a list of strings associated with a model then you can manually create a join table and use a descriptor to manage the relationship. It's not exactly what you need, but this code should get you started.
Thanks for all those that answered. Even if I didn't use your answer directly the examples and links got me going in the right direction.
I am not sure if this is production ready, but it appears to be working in all my tests so far.
class ListValueDescriptor(object):
def __init__(self, lvd_parent, lvd_model_name, lvd_value_type, lvd_unique, **kwargs):
"""
This descriptor object acts like a django field, but it will accept
a list of values, instead a single value.
For example:
# define our model
class Person(models.Model):
name = models.CharField(max_length=120)
friends = ListValueDescriptor("Person", "Friend", "CharField", True, max_length=120)
# Later in the code we can do this
p = Person("John")
p.save() # we have to have an id
p.friends = ["Jerry", "Jimmy", "Jamail"]
...
p = Person.objects.get(name="John")
friends = p.friends
# and now friends is a list.
lvd_parent - The name of our parent class
lvd_model_name - The name of our new model
lvd_value_type - The value type of the value in our new model
This has to be the name of one of the valid django
model field types such as 'CharField', 'FloatField',
or a valid custom field name.
lvd_unique - Set this to true if you want the values in the list to
be unique in the table they are stored in. For
example if you are storing a list of strings and
the strings are always "foo", "bar", and "baz", your
data table would only have those three strings listed in
it in the database.
kwargs - These are passed to the value field.
"""
self.related_set_name = lvd_model_name.lower() + "_set"
self.model_name = lvd_model_name
self.parent = lvd_parent
self.unique = lvd_unique
# only set this to true if they have not already set it.
# this helps speed up the searchs when unique is true.
kwargs['db_index'] = kwargs.get('db_index', True)
filter = ["lvd_parent", "lvd_model_name", "lvd_value_type", "lvd_unique"]
evalStr = """class %s (models.Model):\n""" % (self.model_name)
evalStr += """ value = models.%s(""" % (lvd_value_type)
evalStr += self._params_from_kwargs(filter, **kwargs)
evalStr += ")\n"
if self.unique:
evalStr += """ parent = models.ManyToManyField('%s')\n""" % (self.parent)
else:
evalStr += """ parent = models.ForeignKey('%s')\n""" % (self.parent)
evalStr += "\n"
evalStr += """self.innerClass = %s\n""" % (self.model_name)
print evalStr
exec (evalStr) # build the inner class
def __get__(self, instance, owner):
value_set = instance.__getattribute__(self.related_set_name)
l = []
for x in value_set.all():
l.append(x.value)
return l
def __set__(self, instance, values):
value_set = instance.__getattribute__(self.related_set_name)
for x in values:
value_set.add(self._get_or_create_value(x))
def __delete__(self, instance):
pass # I should probably try and do something here.
def _get_or_create_value(self, x):
if self.unique:
# Try and find an existing value
try:
return self.innerClass.objects.get(value=x)
except django.core.exceptions.ObjectDoesNotExist:
pass
v = self.innerClass(value=x)
v.save() # we have to save to create the id.
return v
def _params_from_kwargs(self, filter, **kwargs):
"""Given a dictionary of arguments, build a string which
represents it as a parameter list, and filter out any
keywords in filter."""
params = ""
for key in kwargs:
if key not in filter:
value = kwargs[key]
params += "%s=%s, " % (key, value.__repr__())
return params[:-2] # chop off the last ', '
class Person(models.Model):
name = models.CharField(max_length=120)
friends = ListValueDescriptor("Person", "Friend", "CharField", True, max_length=120)
Ultimately I think this would still be better if it were pushed deeper into the django code and worked more like the ManyToManyField or the ForeignKey.
I think what you want is a custom model field.

Categories

Resources