Django multi table on same model - django

I have huge table that needed to be sliced into some smaller table, ex:
campaign_01, campaign_02, ...
While using django queryset with different table name for same model, what I only know to set table name on a model is:
Model._meta.db_table = 'tableXXX'
However this method doesn't work in single shell/request. (only work for first time, but not for the next) -> maybe because it still on same instance?
After the second time we tried to set _meta.db_table = 'tableYYY', it will occur an error "django.db.utils.ProgrammingError: missing FROM-clause entry for table "tableXXX""
I also have tried some suggestion I read for this problem answer like:
class ListingManager(models.Manager):
def get_custom_obj(self, table_name):
self.model._meta.db_table = table_name
return self
class ObjectName(models.Model):
objects = ListingManager()
Try to create an Object manager to get new object, but it not work, it still throw same error as before (on the second time setting _meta.db_table)
The only way to make it work if we want to set multiple times for _meta.db_table is we need to exit() the shell first, then re-enter the shell mode (which means for loop is not gonna work).
I know it can be achieved with raw query 'Insert into tableXXX values ()', but any method to do it using django queryset? Thanks~

Consider creating a wrapper model.
class Model1(models.Model):
# fields...
name = ...
age = ...
class Model2(models.Model):
# fields...
height = ...
weight = ...
class ModelAll(models.Model):
model1 = models.OneToOneField(Model1)
model2 = models.OneToOneField(Model2)
But if you're only doing this for organization, just break the fields up with white space.
This will result in the following tables:
Model1
id | name | age
------------------
1 | "Joe" | 21
Model2
id | height | weight
----------------------
1 | 5.85 | 175
2 | 6.0 | 210
ModelAll
id | model1_id | model2_id
----------------------------
1 | 1 | 2
To access sub model fields:
modelall = ModelAll.objects.get(...)
modelall_name = modelall.model1.name
modelall_height = modelall.model2.height

Related

How to find ids that requires action based on 3 tables?

I'm working on my first django project which is a sport betting app.
My models are:
class Game(models.Model):
home_team = models.CharField(max_length=100)
away_team = models.CharField(max_length=100)
class GameResult(models.Model):
gameid = models.ForeignKey(Game)
result = models.IntegerField(default=None)
class GameBet(models.Model):
gameid = models.ForeignKey(Game)
bet = models.IntegerField(default=None)
userid = models.ForeignKey(User)
I'm trying to create a view that shows only pending games, which means they have no result (easy part) and no bet placed yet.
Here the problem is - in my database I have only bets that was made, like:
gameid| userid | userbet
23 | 10 | 2
23 | 11 | 1
23 | 12 | 0
and I'm looking for somethig like this:
gameid| userid | userbet
24 | 10 | 1
24 | 11 | 0
When userid #12 hasn't made his bet yet - so it is missing in the database and game should be in his pending games list.
My current logic is that I know ids of all games, I know ids of games with result and I know ids of games that I placed my bet.
How do I connect these dots and find out games that I still have to bet?
all_games = Game.objects.get()
games_with_result = GameResult.objects.filter(result__isnull=False)
games_with_players_bet = GameBet.objects.filter(userid_id=selected_player)
Or maybe I should rebuild my database? I appreciate all the answers
You might use exclude on a queryset:
all_games = Game.objects.all()
results = GameResult.objects.filter(result__isnull=False)
games_without_result = all_games.exclude(pk__in=[r.gameid.pk for r in results])
bets_from_player = GameBet.objects.filter(userid_id=selected_player)
owing_games = games_without_result.exclude(pk__in=[bet.gameid.pk for bet in bets_from_player])
The GameResult model might move as a field (result = models.IntegerField(default=None)) into Game. This should work as long as you only expect one result per game. As a benefit you can easily query for games without results.
games_without_result = Game.objects.filter(result__isnull=True)

Django: duplicates when filtering on many to many field

I've got the following models in my Django app:
class Book(models.Model):
name = models.CharField(max_length=100)
keywords = models.ManyToManyField('Keyword')
class Keyword(models.Model)
name = models.CharField(max_length=100)
I've got the following keywords saved:
science-fiction
fiction
history
science
astronomy
On my site a user can filter books by keyword, by visiting /keyword-slug/. The keyword_slug variable is passed to a function in my views, which filters Books by keyword as follows:
def get_books_by_keyword(keyword_slug):
books = Book.objects.all()
keywords = keyword_slug.split('-')
for k in keywords:
books = books.filter(keywords__name__icontains=k)
This works for the most part, however whenever I filter with a keyword that contains a string that appears more than once in the keywords table (e.g. science-fiction and fiction), then I get the same book appear more than once in the resulting QuerySet.
I know I can add distinct to only return unique books, but I'm wondering why I'm getting duplicates to begin with, and really want to understand why this works the way it does. Since I'm only calling filter() on successfully filtered QuerySets, how does the duplicate book get added to the results?
The 2 models in your example are represented with 3 tables: book, keyword and book_keyword relation table to manage M2M field.
When you use keywords__name in filter call Django is using SQL JOIN to merge all 3 tables. This allows you to filter objects in 1st table by values from another table.
The SQL will be like this:
SELECT `book`.`id`,
`book`.`name`
FROM `book`
INNER JOIN `book_keyword` ON (`book`.`id` = `book_keyword`.`book_id`)
INNER JOIN `keyword` ON (`book_keyword`.`keyword_id` = `keyword`.`id`)
WHERE (`keyword`.`name` LIKE %fiction%)
After JOIN your data looks like
| Book Table | Relation table | Keyword table |
|---------------------|------------------------------------|------------------------------|
| Book ID | Book name | relation_book_id | relation_key_id | Keyword ID | Keyword name |
|---------|-----------|------------------|-----------------|------------|-----------------|
| 1 | Book 1 | 1 | 1 | 1 | Science-fiction |
| 1 | Book 1 | 1 | 2 | 2 | Fiction |
| 2 | Book 2 | 2 | 2 | 2 | Fiction |
Then when data is loaded from DB into Python you only receive data from book table. As you can see the Book 1 is duplicated there
This is how Many-to-many relation and JOIN works
Direct quote from the Docs: https://docs.djangoproject.com/en/dev/topics/db/queries/#spanning-multi-valued-relationships
Successive filter() calls further restrict the
set of objects, but for multi-valued relations, they apply to any
object linked to the primary model, not necessarily those objects that
were selected by an earlier filter() call.
In your case, because keywords is a multi-valued relation, your chain of .filter() calls filters based only on the original model and not on the previous queryset.

Need Modeling Help For An Ordering Form

I'd like to create a Django project for my company's purchasing department. This would be my first project in Django, so sorry if this comes off as rudimentary. The workflow would look something like this:
user registers for an account > signs in > can create, edit, view, or delete a purchase order.
I'm getting tripped up on the modeling. Presumably I can create and authenticate users using django.contrib.auth. Also, since this is mainly a form saving/printing application I would use a ModelForm to generate my forms based on my models since the users will be making changes to the form data that will need to be saved. A simplified version of the purchase order form in question looks something like this:
| Vendor | Date | Lead Time | Arrival Date | Buyer_Name |
+--------+-------+-----------+--------------+------------+
| FooBar |1-1-12 | 30 | 2-1-12 | Mr. Bar |
+--------+-------+-----------+--------------+------------+
+--------+-------+-----------+--------------+------------+
| SKU | Description | Quantity | Price | Dimensions |
+--------+-------------+----------+-------+--------------+
|12345 | Soft Bar | 38 | 5.75 | 16 X 5 X 8 |
+--------+-------------+----------+-------+--------------+
|12346 | Hard Bar | 12 | 5.75 | 16 X 5 X 8 |
+--------+-------------+----------+-------+--------------+
|12347 | Medium Bar | 17 | 5.75 | 16 X 5 X 8 |
+--------+-------------+----------+-------+--------------+
As you can see, the main purchase order form has a header that identifies the Vendor being ordered from, the current date, lead time, arrival date, and the buyer's name who is filling the form out. Under that is a line-by-line order detail for three different SKUs. Ideally, each PurchaseOrder should be able to have many SKUs added to it.
What is the best way to model something like this? Do I create a User, PurchaseOrder, and SKU model? Then add a FK to the SKU Model that points to the PurchaseOrder Model's PK or is there some other, more correct, way to do something like this? Thanks in advance for any help.
[Edit]
Django had what I was looking for all along. Since this is essentially a nested form, I could make use of Formsets.
Here are two helpful links to get started:
https://docs.djangoproject.com/en/1.4/topics/forms/formsets/
https://docs.djangoproject.com/en/1.4/topics/forms/modelforms/#model-formsets
Use django's built in user model (you can look at the source to see the definition but it is similar to the code below for these other models). Other than that I would suggest a model for every object you mentioned.
Don't add a FK to the SKU Model since SKU can exist without being in a purchase order (if I understand the problem correctly).
models.py
from django.contrib.auth.models import User
class Vendor(models.Model):
name = models.CharField(max_length=200)
#other fields
class SKU(models.Model):
description = models.CharField(max_length=200)
#other fields
class PurchaseOrder(models.Model):
purchaser = models.ForiegnKey(User)
name = models.CharField(max_length=200)
skus = models.ManyToManyField(SKU) #this is the magic that allows 1 purchase order to be filled with several SKUs
#other fields

Ordering entries via comment count with django

I need to get entries from database with counts of comments. Can i do it with django's comment framework? I am also using a voting application which is not using GenericForeignKeys i get entries with scores like this:
class EntryManager(models.ModelManager):
def get_queryset(self):
return super(EntryManager,self).get_queryset(self).all().annotate(\
score=Sum("linkvote__value"))
But when there is foreignkeys i am being stuck. Do you have any ideas about that?
extra explaination: i need to fetch entries like this:
id | body | vote_score | comment_score |
1 | foo | 13 | 4 |
2 | bar | 4 | 1 |
after doing that, i can order them via comment_score. :)
Thans for all replies.
Apparently, annotating with reverse generic relations (or extra filters, in general) is still an open ticket (see also the corresponding documentation). Until this is resolved, I would suggest using raw SQL in an extra query, like this:
return super(EntryManager,self).get_queryset(self).all().annotate(\
vote_score=Sum("linkvote__value")).extra(select={
'comment_score': """SELECT COUNT(*) FROM comments_comment
WHERE comments_comment.object_pk = yourapp_entry.id
AND comments_comment.content_type = %s"""
}, select_params=(entry_type,))
Of course, you have to fill in the correct table names. Furthermore, entry_type is a "constant" that can be set outside your lookup function (see ContentTypeManager):
from django.contrib.contenttypes.models import ContentType
entry_type = ContentType.objects.get_for_model(Entry)
This is assuming you have a single model Entry that you want to calculate your scores on. Otherwise, things would get slightly more complicated: you would need a sub-query to fetch the content type id for the type of each annotated object.

Django QuerySet result with null fields in results

I have to get a QuerySet with many-to-many relations with the same number of results as if I executed the query in the database, but can't manage how to do this; I don't care if I can get the results as a QuerySet item or as a values item, but I do care to get the same number of results.
Imagine the following scenario:
class Person(models.Model):
name = models.CharField()
class Car(models.Model):
name = models.CharField()
class House(models.Model):
people = models.ManyToMany(Person)
cars = models.ManyToMany(Car)
house_1 = House.objects.create()
house_2 = House.objects.create()
john = Person.objects.create(name='John')
mary = Person.objects.create(name='Mary')
house_1.people.add(john)
house_1.people.add(mary)
mike = Person.objects.create(name='Mike')
ferrari = Car.objects.create(name='Ferrari')
house_2.people.add(mike)
house_2.cars.add(ferrari)
'''
Expected search result, regardless of the result format (model instances or values):
------------------------------------
| House ID | Car | Person |
| 1 | | John |
| 1 | | Mary |
| 2 | Ferrari | Mike |
------------------------------------
'''
How can I get a list of values, with all 3 results, spanning multiple tables, as here?
I need this so that I can create a report which can potentialy contain null fields, so the duplicated results must be listed.
Thanks!
Try to write SQL query that does that. You can't because it's wrong query to that data structure. Imagine that there will be 2 cars assigned to house 1. Should it be 1-[car-1]-John, 1-[car-2]-Merry or 1-[car-2]-John, 1-[car-1]-Merry?