Doctrine2 - Inheritance and relation - doctrine-orm

Is it possible to solve this problem in doctrine? I have one entity, called Comment and this entity have relation with another entity caller Author. The relation is made througt two columns: author_id and author_type
/**
* #ORM\Entity
* #ORM\Table(name="comments")
*/
class Comment
{
/**
* #ORM\ManyToOne(targetEntity="Entities\Authors\Guest", cascade={"persist"})
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="author_id", referencedColumnName="author_id", nullable=FALSE),
* #ORM\JoinColumn(name="author_type", referencedColumnName="author_type", nullable=FALSE)
* })
**/
protected $author;
}
This relation is because author could be system user, guest, facebook user, etc. and each user have their own author id and author type (guest, system, facebook, etc.) so the author entity look like this:
/**
* #ORM\Entity
* #ORM\Table(name="authors")
* #ORM\InheritanceType("SINGLE_TABLE")
* #ORM\DiscriminatorColumn(name="author_type", type="string")
* #ORM\DiscriminatorMap({
* "guest" = "Guest",
* "system" = "System",
* "facebook" = "Facebook",
* "twitter" = "Twitter",
* "google" = "Google",
* "github" = "Github"
* })
*/
class Guest
{
}
To separate each author type i use single table inheritance. with column author_type. Primary key for author table is author_id and author_type
When i load comment entity, it is successfully loaded with author, but problem is when i try to create new comment entity and store it to the database. The author_id stored in comment table is ok, but author_type is always "guest" even if correct author entity is added to the comment entity.
So is there possibility to solve this? Or should i use diffrent type of relation, add extra column etc.?

Related

Flask Admin a custom inline model - update relation after saving

I have a catalog and the price is a one to many relationship, so that I can track the price of a catalog item over time. The model looks like:
class CatalogItem(db.Model)
id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String(250))
price = db.relationship("Price", back_populates="catalogitem")
class Price(db.Model):
id = db.Column(db.Integer(), primary_key=True)
price = db.Column(db.Float())
timestamp = db.Column(db.DateTime(), server_default=func.now(), nullable=False)
catalogitem_id = db.Column(db.Integer(), db.ForeignKey("catalogitem.id"))
catalogitem = db.relationship("CatalogItem", back_populates="material_einheitspreis_verkauf")
And this is my View. At least I managed to only show the price.
class CatalogItemView(ModelView):
inline_models = [(Price, dict(form_columns=["id","price"]))]
There are two issues:
When I render a catalog item and set price as inline model, I can do that just fine, but the default behavior would allow me to add multiple prices. What I would actually like to do is to have just a price field. I'm looking for a way to limit the form to just one entity (and also leaving away the button "add price".
When editing a catalogitem, it shouldn't edit the price, but actually create a new relationship -> basically when I edit the price it will create a new Price entity.
For 1 I have not idea on how to achieve this. For 2 I guess I could maybe do this by adding some kind of additional form field outside of the model and then create the "magic" with some kind of listeners.
Any other ideas?

Laravel Authentication - Username and Password in different tables

getting problem with authentication in laravel as I have username and password in different tables.As Auth uses same table for username and password but my database is already setup where the the username is in table users and the password is in table webpages_membership, and I cant change the database structure because that database is used by other mobile application and website too. So how do I use Auth for login system.
#btl:
I tried the solution but now there is another error of
"Undefined index: password" in vendor\laravel\framework\src\Illuminate\Auth\GenericUser.php
following is my user model code.
Code:
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use App\WebPages_Membership;
class User extends Authenticatable
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $table = 'Users';
protected $dbPrefixOveride = '';
protected $primaryKey = 'UserId';
protected $fillable = [
'Username', 'FirstName', 'LastName','Email','MobileNumber','CreatedBy','CreatedDate','ModifiedBy','ModifiedDate','DistributorId','Telephone','IsAuthorized','AlternateMobileNumber','AlternateEmail','IsDeleted','UnauthorizationRemark'
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
/*protected $hidden = [
'password', 'remember_token',
];*/
public function webpagesMembership() {
return $this->hasOne(WebPages_Membership::class);
}
public function getPasswordAttribute() {
return $this->webpagesMembership->getAttribute('Password');
}
}
?>
I'd do something like this. Assuming a one-to-one relationship between your tables.
Define a relationship between User and WebpagesMembership models. Your User model would have the following:
public function webpagesMembership() {
return $this->hasOne(WebpagesMembership::class);
}
Add an accessor function
public function getPasswordAttribute() {
return $this->webpagesMembership->getAttribute('password');
}
That way Auth will work when it attempts to access the password attribute on your User model.
Edit:
Add password to the User model's $appends property:
protected $appends = [
'password'
];
This will act as if it were an attribute on the model now. The error you encountered was because the GenericUser's attributes were being set in the constructor and password did not exist. It then attempted to access password in:
public function getAuthPassword()
{
return $this->attributes['password'];
}
Hence, the undefined index.

Doctrine Native Query does not load related entities even if I add addMetaResult mapping

I have 2 tables:
users - id, firstName, lastName
posts - id, title, content, user_id
I'm trying to load entities with native query:
$rsm = new ResultSetMapping;
$rsm->addEntityResult('Entity\Post', 'p');
$rsm->addFieldResult('p', 'id', 'id');
$rsm->addFieldResult('p', 'title', 'title');
$rsm->addMetaResult('p', 'user_id', 'user_id');
$sql = 'select p.id, p.title, p.user_id from posts p';
$query = $em->createNativeQuery($sql, $rsm);
$posts = $query->getResult();
Doctrine loads "Post" entity, and fills "User" relation, but all attributes of "User" entity is NULL. Why it doesn't load "User" entity with proxy object? For what does "addMetaResult" exists?
Actually if you call get_class on "User", than you'll see that it is a doctrine proxy. All attributes are nulls because proxy is not loaded. Call on of "getter" methods (for example getFirstName()) on one of attribute and doctrine will load class and fill all other attributes.

I do not understand this error involving two objects with a many-to-many relation with one another

I am implementing a web interface for email lists. When a list administrator logs in, the site will visually display which lists they are an owner of and corresponding information about the lists. For this I have decided to have two tables:
1) An owner table which contains entries for information about list administrators. Each of these entries contains a 'ManyToManyField' which holds the information about which lists the owner in any given entry is an administrator for.
2) A list table which contains entries with information about each email list. Each entry contains the name of the list a 'ManyToManyField' holding information about which owners are administrators the list.
Here is the code in models.py:
from django.db import models
class ListEntry(models.Model):
name = models.CharField(max_length=64)
owners = models.ManyToManyField('OwnerEntry')
date = models.DateTimeField('date created')
class Meta:
ordering = ('name',)
class OwnerEntry(models.Model):
name = models.CharField(max_length=32)
lists = models.ManyToManyField('ListEntry')
class Meta:
ordering = ('name',)
I have already set up a simple local database to create a basic working website with. I have populated it with test entries using this code:
from list_app.models import *
from datetime import *
le1 = ListEntry(
name = "Physics 211 email list",
date = datetime.now(),
)
le1.save()
le2 = ListEntry(
name = "Physics 265 email list",
date = datetime(2014,1,1),
)
le2.save()
oe1 = OwnerEntry(
name = 'wasingej',
)
oe1.save()
oe1.lists.add(le1,le2)
le1.owners.add(oe1)
le2.owners.add(oe1)
oe2 = OwnerEntry(
name = 'doej',
)
oe2.save()
oe2.lists.add(le1)
le1.owners.add(oe2)
Here is where my error occurs: When the user has logged in via CAS, I have them redirected to this page in views.py:
def login_success(request):
u = OwnerEntry(name=request.user)
print(u.name)
print(u.lists)
return HttpResponse("login success!")
At the line 'print(u.lists)', I get the error "" needs to have a value for field "ownerentry" before this many-to-many relationship can be used.
What am I doing wrong here?
Your model structure is broken, for a start. You don't need ManyToManyFields on both sides of the relationship, only one - Django will provide the accessor for the reverse relationship.
Your issue is happening because you are not querying an existing instance from the database, you are instantiating an unsaved one. To query, you use model.objects.get():
u = OwnerEntry.objects.get(name=request.user.username)
You need to provide the actual class to the ManyToManyField constructor, not a string.
https://docs.djangoproject.com/en/dev/topics/db/examples/many_to_many/

Django: ManyToManyField creates duplicate column name

I have two types of users in my application: auth.User, which comes from django.contrib.auth (the standard Django authentication module) and mysql.User, which is in my own module. In addition, mysql.User inherits from an abstract model. The whole thing looks similar to this (some fields were omitted for brevity):
class Resource(Model):
class Meta:
abstract = True
owners = ManyToManyField('auth.User', related_name='%(class)s_owners')
class User(Resource):
name = CharField(max_length=16)
host = CharField(max_length=64)
class Database(Resource):
name = CharField(max_length=64)
As you can see, I want to make it so that multiple auth.Users may "own" a given mysql.User and a given mysql.Database, hence the ManyToManyFields. However, when I go to run ./manage.py syncdb I get the error:
_mysql_exceptions.OperationalError: (1060, "Duplicate column name 'user_id'")
Indeed, ./manage.py sql mysql shows the source of the error (again, some columns and ALTER TABLE statements omitted for brevity):
CREATE TABLE `mysql_database` (
`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
`name` varchar(64) NOT NULL,
UNIQUE (`server_id`, `name`)
);
CREATE TABLE `mysql_user` (
`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
`name` varchar(16) NOT NULL,
`host` varchar(64) NOT NULL,
UNIQUE (`server_id`, `name`, `host`)
);
CREATE TABLE `mysql_database_owners` (
`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
`database_id` integer NOT NULL,
`user_id` integer NOT NULL,
UNIQUE (`database_id`, `user_id`)
);
CREATE TABLE `mysql_user_owners` (
`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
`user_id` integer NOT NULL,
`user_id` integer NOT NULL, -- <<<<< here is the conflict >>>>>
UNIQUE (`user_id`, `user_id`)
);
Notice how the intermediate table for Database is created without a naming conflict but the table for User has a conflict. I don't see where a ManyToManyField provides a way for one to provide column names in the intermediate table, but unfortunately I think that's what I need.
Another method I tried was to explicitly create the intermediate table and use the through option of ManyToManyField, like so:
class Resource(models.Model):
class Meta:
abstract = True
owners = models.ManyToManyField('auth.User', related_name='%(class)s_owners', through='Owner')
class Owner(models.Model):
user = models.ForeignKey('auth.User', related_name='Resource_owners')
resource = models.ForeignKey(Resource)
But then I get this error:
AssertionError: ForeignKey cannot define a relation with abstract class Resource
Which is to be expected with Django.
So, short of renaming mysql.User to something like mysql.DBUser, is there any way to avoid the naming conflict created by Django?
How about creating the many to many table separately, avoiding the use of the ManyToMany field? You could use a manager or method to return a list of users for a given resource and visa versa.
class Resource(models.Model):
...
class Meta:
abstract = True
def owners(self):
return ResourceOwner.objects.filter(resource=self)
class ResourceOwners(models.Model):
resource = models.ForeignKey(Resource)
owner = models.ForeignKey(User)
class Meta:
abstract = True