I have n to m database (movie and cast). I need to get a list of cast associated with a movie.
#Entity(tableName = "movie")
data class MovieDbModel(
#PrimaryKey(autoGenerate = false)
val id: Int,
val poster_path: String,
val overview: String,
val title: String)
#Entity(tableName = "cast")
#TypeConverters(CastConverter::class)
data class CastDbModel(
#PrimaryKey(autoGenerate = false)
val id : Int,
val cast: Cast //Arraylist of casts
)
data class Cast(
#Embedded
var name: String,
var profile_path: String?,
var character: String
)
Crossreferenced class:
#Entity(
tableName = "movie_cast",
primaryKeys = ["movieIdMap","castIdMap"],
foreignKeys = [
ForeignKey(
entity = MovieDbModel::class,
parentColumns = ["id"],
childColumns = ["movieIdMap"],
onDelete = ForeignKey.CASCADE,
onUpdate = ForeignKey.CASCADE
),
ForeignKey(
entity = CastDbModel::class,
parentColumns = ["id"],
childColumns = ["castIdMap"],
onDelete = ForeignKey.CASCADE,
onUpdate = ForeignKey.CASCADE
)
]
)
data class MovieCastCrossRef(
var movieIdMap: Int,
#ColumnInfo(index = true)
var castIdMap: Int
)
Relation:
data class MovieWithListOfCast(
#Embedded /* The parent */
var movie: MovieDbModel,
#Relation(
entity = CastDbModel::class,
parentColumn = "id",
entityColumn = "id",
associateBy = Junction(
value = MovieCastCrossRef::class,
parentColumn = "castIdMap",
entityColumn = "movieIdMap"
)
)
var castList: List<CastDbModel>
)
The Query looks like this:
#Transaction
#Query("select * FROM `cast` WHERE id = :id")
fun getAllCastAssociatedWithMovie(id: Int): List<MovieWithListOfCast>
But I get the following warning:
The query returns some columns [cast] which are not used by MovieWithListOfCast. You can use #ColumnInfo annotation on the fields to specify the mapping. You can annotate the method with #RewriteQueriesToDropUnusedColumns to direct Room to rewrite your query to avoid fetching unused columns.
MovieWithListOfCast has some fields [poster_path, overview, title] which are not returned by the query. If they are not supposed to be read from the result, you can mark them with #Ignore annotation. You can suppress this warning by annotating the method with #SuppressWarnings(RoomWarnings.CURSOR_MISMATCH). Columns returned by the query: id, cast.
How do I query to get a list of Cast that contains name, profile_path, and character?
I believe that you have concepts reversed.
First,
the #Embedded is the parent thus the parentColumn should specify a column in the #Embedded, you have parentColumn = "castIdMap" when it should be parentColumn = "movieIdMap" along with changing to use entityColumn = "castIdMap".
This would not necessarily be apparent at first but would likely lead to confusion (all depends upon the reversed id's)
Second,
the MovieWithListOfCast will get the list of cast for a movie, therefore it needs to get the movie from the movie table not the cast table.
So MovieWithListOfClass could be:-
data class MovieWithListOfCast(
#Embedded /* The parent */
var movie: MovieDbModel,
#Relation(
entity = CastDbModel::class,
parentColumn = "id",
entityColumn = "id",
associateBy = Junction(
value = MovieCastCrossRef::class,
parentColumn = "movieIdMap",
entityColumn = "castIdMap"
)
)
var castList: List<CastDbModel>
)
Along with:-
#Transaction
#Query("select * FROM `movie` WHERE id = :id")
fun getAllCastAssociatedWithMovie(id: Int): List<MovieWithListOfCast>
You could also have (just in case that is what you are thinking):-
data class CastWithListOfMovies(
#Embedded
var castList: CastDbModel,
#Relation(
entity = MovieDbModel::class,
parentColumn = "id",
entityColumn = "id",
associateBy = Junction(
value = MovieCastCrossRef::class,
parentColumn = "castIdMap",
entityColumn = "movieIdMap"
)
)
var movieList: List<MovieDbModel>
)
Along with:-
#Transaction
#Query("select * FROM `cast` WHERE id = :id")
fun getAllMoviesAssociatedWithCast(id: Int): List<CastWithListOfMovies>
Putting both into action using your code amended as above and with a suitable #Database annotated class then using:-
class MainActivity : AppCompatActivity() {
lateinit var db: TheDatabase
lateinit var dao: AllDao
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
db = TheDatabase.getInstance(this)
dao = db.getAllDao()
val m1id = dao.insert(MovieDbModel(100,"posetr001","Western","The Good, the Bad and the Ugly"))
val m2id = dao.insert(MovieDbModel(200,"poster002","Sci-Fi","Star Wars"))
val m3id = dao.insert(MovieDbModel(300,"poster003","Soppy","Gone with the Wind"))
val c1id = dao.insert(CastDbModel(1,Cast("Actor1","acts","an actor")))
val c2id = dao.insert(CastDbModel(2,Cast("Actor2","acts","an actor")))
val c3id = dao.insert(CastDbModel(3,Cast("Actor3","acts","an actor")))
val c4id = dao.insert(CastDbModel(4,Cast("Actor4","acts","an actor")))
val c5id = dao.insert(CastDbModel(5,Cast("Actor5","acts","an actor")))
val c6id = dao.insert(CastDbModel(6,Cast("Actor6","acts","an actor")))
val c7id = dao.insert(CastDbModel(7,Cast("Actor7","acts","an actor")))
dao.insert(MovieCastCrossRef(m1id.toInt(),c1id.toInt()))
dao.insert(MovieCastCrossRef(m1id.toInt(),c3id.toInt()))
dao.insert(MovieCastCrossRef(m1id.toInt(),c5id.toInt()))
dao.insert(MovieCastCrossRef(m1id.toInt(),c7id.toInt()))
dao.insert(MovieCastCrossRef(m2id.toInt(),c2id.toInt()))
dao.insert(MovieCastCrossRef(m2id.toInt(),c4id.toInt()))
dao.insert(MovieCastCrossRef(m2id.toInt(),c6id.toInt()))
dao.insert(MovieCastCrossRef(m3id.toInt(),c1id.toInt()))
dao.insert(MovieCastCrossRef(m3id.toInt(),c2id.toInt()))
dao.insert(MovieCastCrossRef(m3id.toInt(),c3id.toInt()))
dao.insert(MovieCastCrossRef(m3id.toInt(),c4id.toInt()))
dao.insert(MovieCastCrossRef(m3id.toInt(),c5id.toInt()))
dao.insert(MovieCastCrossRef(m3id.toInt(),c6id.toInt()))
dao.insert(MovieCastCrossRef(m3id.toInt(),c7id.toInt()))
logCastWithMovie(c1id.toInt(),"C1")
logMovieWithCast(m1id.toInt(),"M1")
logCastWithMovie(c2id.toInt(),"C2")
logMovieWithCast(m2id.toInt(),"M2")
logCastWithMovie(c3id.toInt(),"C3")
logMovieWithCast(m3id.toInt(),"M3")
}
fun logMovieWithCast(movieId: Int, tagSuffix: String) {
var sb = StringBuilder()
for (cawm in dao.getAllCastAssociatedWithMovie(movieId)) {
for (c in cawm.castList) {
sb.append("\n\t Name is ${c.cast.name} Profile is ${c.cast.profile_path} Character is ${c.cast.character}")
}
Log.d("DBINFO_CAWM_$tagSuffix","Movie is ${cawm.movie.title} cast are:$sb")
}
}
fun logCastWithMovie(castId: Int, tagSuffix: String) {
var sb = StringBuilder()
for (mawc in dao.getAllMoviesAssociatedWithCast(castId)) {
for (m in mawc.movieList) {
sb.append("\n\tTitle is ${m.title} Overview is ${m.overview} Poster is ${m.poster_path}")
}
Log.d("DBINFO_MAWC_$tagSuffix","Cast is ${mawc.castList.cast.name} Movies are $sb")
}
}
}
Results in the log including:-
2022-09-03 08:15:25.084 D/DBINFO_MAWC_C1: Cast is Actor1 Movies are
Title is The Good, the Bad and the Ugly Overview is Western Poster is posetr001
Title is Gone with the Wind Overview is Soppy Poster is poster003
2022-09-03 08:15:25.095 D/DBINFO_CAWM_M1: Movie is The Good, the Bad and the Ugly cast are:
Name is Actor1 Profile is acts Character is an actor
Name is Actor3 Profile is acts Character is an actor
Name is Actor5 Profile is acts Character is an actor
Name is Actor7 Profile is acts Character is an actor
2022-09-03 08:15:25.102 D/DBINFO_MAWC_C2: Cast is Actor2 Movies are
Title is Star Wars Overview is Sci-Fi Poster is poster002
Title is Gone with the Wind Overview is Soppy Poster is poster003
2022-09-03 08:15:25.109 D/DBINFO_CAWM_M2: Movie is Star Wars cast are:
Name is Actor2 Profile is acts Character is an actor
Name is Actor4 Profile is acts Character is an actor
Name is Actor6 Profile is acts Character is an actor
2022-09-03 08:15:25.111 D/DBINFO_MAWC_C3: Cast is Actor3 Movies are
Title is The Good, the Bad and the Ugly Overview is Western Poster is posetr001
Title is Gone with the Wind Overview is Soppy Poster is poster003
2022-09-03 08:15:25.117 D/DBINFO_CAWM_M3: Movie is Gone with the Wind cast are:
Name is Actor1 Profile is acts Character is an actor
Name is Actor2 Profile is acts Character is an actor
Name is Actor3 Profile is acts Character is an actor
Name is Actor4 Profile is acts Character is an actor
Name is Actor5 Profile is acts Character is an actor
Name is Actor6 Profile is acts Character is an actor
Name is Actor7 Profile is acts Character is an actor
I have some classes
class MarketProduct(models.Model, ObjectMarket):
_state_class = 'MarketProductState'
uuid = models.UUIDField(u'Код',
default=uuid.uuid4, editable=False)
name = models.CharField(u'Название',
max_length=255, db_index=True)
class MarketItem(models.Model, ObjectMarket):
_state_class = 'MarketItemState'
STOCK, AUCTION = 1, 2
ITEM_CHOICES = (
(STOCK, u'Сток'),
(AUCTION, u'Аукцион'),
)
product = models.ForeignKey(MarketProduct)
start_at = models.DateTimeField(u'Начало продажи')
I want to get MarketItemViewSet and use
filter_backends = (filters.OrderingFilter,`)
I send request with filed orderby by angular.
If I send orderby = start_at, all are good, but I want to send
orderby = product.id, it doesn't work.
You can try specifying product__id to perform ordering based on the id of product.
orderby = product__id
Specify ordering_fields in your viewset.
ordering_fields = ('product__id', )
As you are using django-rest-framework you have to use ordering_fields as you can see from the documentation here.Hope it helps example:
class UserListView(generics.ListAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
filter_backends = (filters.OrderingFilter,)
ordering_fields = ('username', 'email')
ordering = ('created_on') # for reverse ordering = ('-created_on')
If an ordering attribute is set on the view, this will be used as the default ordering.
Typically you'd instead control this by setting order_by on the initial queryset, but using the ordering parameter on the view allows you to specify the ordering in a way that it can then be passed automatically as context to a rendered template
What's wrong with my query?
Here are my models:
class Positions(ndb.Model):
title = ndb.StringProperty(indexed=True)
summary = ndb.TextProperty()
duties = ndb.TextProperty()
dateCreated = ndb.DateTimeProperty(auto_now_add=True)
dateUpdated = ndb.DateTimeProperty(auto_now=True)
class Applicants(ndb.Model):
name = ndb.StringProperty(indexed=True)
position = ndb.KeyProperty(kind=Positions,repeated=True)
file = ndb.BlobKeyProperty()
dateCreated = ndb.DateTimeProperty(auto_now_add=True)
dateUpdated = ndb.DateTimeProperty(auto_now=True)
Here is my query:
class AdminPositionInfoHandler(BaseHandler):
def get(self,positionKeyId):
user = users.get_current_user()
if users.is_current_user_admin():
positionKey = ndb.Key('Positions',int(positionKeyId))
position = positionKey.get()
applicants = Applicants.query(position=position.key).fetch() # the query
values = {
'position': position,
'applicants': applicants,
}
self.render_html('admin-position-info.html',values)
else:
self.redirect(users.create_login_url(self.request.uri))
What seems to be wrong in using the query:
applicants = Applicants.query(position=position.key).fetch()
I got this error:
File "C:\xampp\htdocs\angelstouch\main.py", line 212, in get
applicants = Applicants.query(position=position.key).fetch()
...
TypeError: __init__() got an unexpected keyword argument 'position'
I also tried using positionKey instead of position.key:
applicants = Applicants.query(position=positionKey).fetch()
I got this from "Ancestor Queries" section of GAE site:
https://developers.google.com/appengine/docs/python/ndb/queries
You don't pass arguments to query like that - ndb uses overridden equality/inequality operators, so you can express queries more 'naturally', with '==', '<', '>' etc., so:
applicants = Applicants.query(Applications.position==position.key).fetch()
The section in the on Filtering by Property Values gives some more examples.
(ancestor is a special-case for queries - it isn't a model property)
I have a StructuredProperty that looks like this:
userDB(key=Key('userDB', 5580090230439936), name=u'Super User', orgs=[providers(name=u'Comp, Inc.', password=u'1111111', url=None, username=u'111111', value=u'comp'), providers(name=u'Systems, Inc.', password=u'2222222', url=None, username=u'222222', value=u'system')], update=None, userID=u'super#example.com')
I would like to delete every provider who's 'value' == 'system'.
class providers(EndpointsModel):
name = ndb.StringProperty()
value = ndb.StringProperty()
url = ndb.StringProperty()
username = ndb.StringProperty()
password = ndb.StringProperty()
class userDB(EndpointsModel):
userID = ndb.StringProperty(required=True, indexed=True)
name = ndb.StringProperty(required=True, indexed=True)
update = ndb.DateTimeProperty(auto_now_add=True, indexed=True)
orgs = ndb.StructuredProperty(providers, repeated=True, indexed=True)
system = ndb.StructuredProperty(system, repeated=True, indexed=True)
comp = ndb.StructuredProperty(comp, repeated=True, indexed=True)
I tried this:
def delOrgs(key, X): #Key is a userDB key and X is a list ['system']
for B in X:
for A in key[0].get().orgs:
del_provider = key[0].get().query(A.value == B).fetch(keys_only=True)
#del_provider[0].delete()
logging.info(del_provider)
but i get the following error:
TypeError: Cannot filter a non-Node argument; received False
Any help would be greatly appreciated.
Your query should look like:
userDB.query(userDB.orgs.value == 'system)
This will return all of the userDBs which have a provider with value == 'system'.
You'll then need to update the 'orgs' property of each, removing any that you don't want, and then re-put the entities:
users = query.fetch()
for user in users:
user.orgs = filter(lambda provider: provider.value != 'system', user.orgs)
ndb.put_multi(users)
Structured properties don't (or shouldn't) exist as independent entities, so you can't fetch them independently of the entity that contains them, and can't delete them directly.
main table:
class example(models.Model):
name = models.CharField('Item Name', max_length=200)
color = models.ManyToManyField(Color)
category = models.ForeignKey(Category)
image = models.ImageField('Item Image',upload_to="example/images/")
Category table:
class Category(models.Model):
catname = models.CharField('Category Name',max_length=100)
How can i query it while filtering the example table according to the category.
This didn't work out:
def list(request, cat):
c = example.object.filter(category = cat)
What should i change to make this filtering work ?
See Django's documentation on related lookups:
def list(request, cat):
c = example.objects.filter(category__catname=cat)