Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[django] users populaten vanuit een script

Pagina: 1
Acties:

  • Boudewijn
  • Registratie: Februari 2004
  • Niet online

Boudewijn

omdat het kan

Topicstarter
Hoihoi


Aangeizen ik nog steeds bezig ben met me de quirks van Django eigen te maken loop ik weer tegen een probleem op.
Case:

ik heb een django webapp gebouwd om users op een Jabber-server te managen. Prima, hierbij gebruik ik de bekende tango with django tutorial (http://www.tangowithdjang...setting-up-authentication) die ik modificeer.

Je ziet dat men daar een UserProfile klasse aanmaakt, die inherit van User. Dit omdat er dan een paar extra fields bij kunnen zonder dingen met de User klasse te tweaken.

Ik wil datzelfde ook doen:

Python:
1
2
3
4
5
6
class JabberAdmin(models.Model):
    # This line is required. Links UserProfile to a User model instance.
    user = models.OneToOneField(User)

    name = models.CharField(max_length=128, unique=True, primary_key=True)
    group = models.ForeignKey(JabberAdminGroup)

Goed, so far so good... maar ik wil mijn jabberadmins populaten vanuit een scriptje. Waarom? Omdat diverse objecten in de database een "created_by" foreign key hebben naar een JabberAdmin.

Dat betekent dus dat ik JabberAdmin objecten moet instantieren die overerven van de User objecten.

Mijn oude code:

code:
1
2
3
4
5
    admin_boudewijn = add_JabberAdmin(name="boudewijn", group=admingroup_team1)

def add_JabberAdmin(name,group):
    obj = JabberAdmin.objects.get_or_create(name=name,group=group)[0]
    return obj


Nou prima, dat werkte gewoon goed.
Nu ik echter de link heb gelegd met de Django User klasse:

code:
1
2
3
4
5
6
7
8
9
10
11
Traceback (most recent call last):
  File "/home/john/workspace/jabberadmin_project/jabberadmin_project/populate.py", line 108, in <module>
    populate()
  File "/home/john/workspace/jabberadmin_project/jabberadmin_project/populate.py", line 12, in populate
    admin_boudewijn = add_JabberAdmin(name="boudewijn", group=admingroup_team)
  File "/home/john/workspace/jabberadmin_project/jabberadmin_project/populate.py", line 84, in add_JabberAdmin
    obj = JabberAdmin.objects.get_or_create(name=name,group=group)[0]
*KNIP*
  File "/usr/lib/python2.7/dist-packages/django/db/backends/sqlite3/base.py", line 450, in execute
    return Database.Cursor.execute(self, query, params)
django.db.utils.IntegrityError: NOT NULL constraint failed: jabberadmin_jabberadmin.user_id

Okay prima, ik moet een user_id opgeven dus... maar hoezo dat? Als in: waarom zou ik dat willen... het veld is namelijk in de database auto incrementing:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
mysql> describe auth_user;
+--------------+--------------+------+-----+---------+----------------+
| Field        | Type         | Null | Key | Default | Extra          |
+--------------+--------------+------+-----+---------+----------------+
| id           | int(11)      | NO   | PRI | NULL    | auto_increment |
| password     | varchar(128) | NO   |     | NULL    |                |
| last_login   | datetime     | NO   |     | NULL    |                |
| is_superuser | tinyint(1)   | NO   |     | NULL    |                |
| username     | varchar(30)  | NO   | UNI | NULL    |                |
| first_name   | varchar(30)  | NO   |     | NULL    |                |
| last_name    | varchar(30)  | NO   |     | NULL    |                |
| email        | varchar(75)  | NO   |     | NULL    |                |
| is_staff     | tinyint(1)   | NO   |     | NULL    |                |
| is_active    | tinyint(1)   | NO   |     | NULL    |                |
| date_joined  | datetime     | NO   |     | NULL    |                |
+--------------+--------------+------+-----+---------+----------------+
11 rows in set (0.00 sec)


Waarom moet dit?
En kan ik hier omheen komen? Ik kan best wat user_id's opgeven (zou even moeten kijken hoe de constructor van mijn JabberAdmin er dan uit komt te zien) maar eigenlijk wil ik dat gewoon niet (dat moet de DB maar lekker uitzoeken...)

  • Xudonax
  • Registratie: November 2010
  • Laatst online: 21-11 20:40
Omdat je user een OneToOneField is, oftewel een database referentie ;)
Dus je moet niet zozeer een user ID opgeven, maar een User object zodat Django weet wat er in het user veld moet komen te staan. Als je wilt kun je me op Skype toevoegen (stuur een DM), ik heb aardig wat Django ervaring en wil best helpen met kleine dingen waar je tegenaan loopt ^_^

Ow, en de constructor van je JabberAdmin model accepteert gewoon named parameters, de namen zijn de velden in je model :) Je kunt dus gewoon zoiets doen:
code:
1
2
3
user = User(...)
group = Group.objects.get(...)
jAdmin = JabberAdmin(name="Boudewijn", group, user)


En nog een laatste opmerking, functie calls zijn relatief duur in Python, dus je add_JabberAdmin functie kun je net zo goed inline schrijven ;)

[ Voor 36% gewijzigd door Xudonax op 11-08-2014 19:58 ]


  • Boudewijn
  • Registratie: Februari 2004
  • Niet online

Boudewijn

omdat het kan

Topicstarter
Xudonax schreef op maandag 11 augustus 2014 @ 19:56:
Omdat je user een OneToOneField is, oftewel een database referentie ;)
Dus je moet niet zozeer een user ID opgeven, maar een User object zodat Django weet wat er in het user veld moet komen te staan. Als je wilt kun je me op Skype toevoegen (stuur een DM), ik heb aardig wat Django ervaring en wil best helpen met kleine dingen waar je tegenaan loopt ^_^
Ghehe dank voor het aanbod, je hebt een DM.

Heteen me op het verkeerde been zette mbt dat user_id was deze error:
code:
1
django.db.utils.IntegrityError: jabberadmin_jabberadmin.user_id may not be NULL


[q]
Ow, en de constructor van je JabberAdmin model accepteert gewoon named parameters, de namen zijn de velden in je model :) Je kunt dus gewoon zoiets doen:
code:
1
2
3
user = User(...)
group = Group.objects.get(...)
jAdmin = JabberAdmin(name="Boudewijn", group, user)

Uhh dat doe ik toch gewoon? :) Behalve dat user-veld.
En nog een laatste opmerking, functie calls zijn relatief duur in Python, dus je add_JabberAdmin functie kun je net zo goed inline schrijven ;)
Goed punt maar geen issue, want:

Ik heb meerdere admins/users en wil niet 3x dezelfde code schrijven (ik insert zo'n 50 objecten in de DB) en die code wordt zelden uitgevoerd. Alleen als ik mijn DB verklooid heb; dat gebeurt niet al te vaak. Dan is even wachten oid prima ;). Deze code zal dus niet snel in een productie omgeving draaien, maar dank voor de tip.

  • Boudewijn
  • Registratie: Februari 2004
  • Niet online

Boudewijn

omdat het kan

Topicstarter
Ondanks je goede tip werkt het nog steeds niet. Uit je tip begrijp ik dat ik een gewone user instantieer en die aan de constructor van JabberAdmin meegeef, mijn huidige code doet dat:


Python:
1
2
3
4
5
6
7
    user_boudewijn = User(username="boudewijn", password= "123", email="boudewijn@blah.nl")
    admin_boudewijn = add_JabberAdmin(user=user_boudewijn,name="boudewijn", group=admingroup_lalalalalala)


def add_JabberAdmin(user,name,group):
    obj = JabberAdmin.objects.get_or_create(user=user,name=name,group=group)[0]
    return obj

Dit faalt alsnog met deze error:

code:
1
django.db.utils.IntegrityError: jabberadmin_jabberadmin.user_id may not be NULL

Mis ik hier wat je bedoelt?

Die parameters voor de constructor van User heb ik ui trouwens uit de comments van User gevist.

[ Voor 6% gewijzigd door Boudewijn op 12-08-2014 00:24 ]


  • Xudonax
  • Registratie: November 2010
  • Laatst online: 21-11 20:40
Ik kan op mijn telefoon niet bij m'n DMs komen, dus die houd je tegoed. Het probleem is dat de User niet gesaved word. Dan heeft 'ie inderdaad nog geen ID, dus ergens klopt de foutmelding wel. Duidelijk is echter anders :P

  • Merethil
  • Registratie: December 2008
  • Laatst online: 09:03
Volgens mij probeer je het veld "user_id" je database in te schieten als null omdat je 'm niet vult en zover ik in je code kan zien er geen primary-key, noch een auto-incremental van hebt gemaakt.

Enige reden waarom je "username" op primary-key=true hebt staan?
Volgens mij moet je dus even kijken naar je eigen database-opbouw: hij verschilt alleen op 't punt van je "id"-kolom t.o.v. die van Tango with Django.

Edit: Zo te zien heb je nog wel een probleem: Al je databasevelden zijn non-nullable, maar de default value in de DB is wel NULL. Als je dus een waarde niet meegeeft aan de database in je query (wat je dus waarschijnlijk onder andere voor user_id niet doet) wordt geprobeerd in de database daar NULL in te zetten. Als dat niet kan krijg je een constraint probleem, want hij mag niet NULL zijn, maar hij probeert 't wel omdat hij geen andere waarde heeft.
Een beter idee is om alle velden die niet per sé nodig zijn nullable te maken terwijl je je primary key non-null zonder default maakt, dan gebruikt hij vanzelf de auto-incremental als je hem in je query niet meegeeft.

[ Voor 44% gewijzigd door Merethil op 12-08-2014 07:27 ]


  • Boudewijn
  • Registratie: Februari 2004
  • Niet online

Boudewijn

omdat het kan

Topicstarter
Xudonax schreef op dinsdag 12 augustus 2014 @ 06:29:
Ik kan op mijn telefoon niet bij m'n DMs komen, dus die houd je tegoed. Het probleem is dat de User niet gesaved word. Dan heeft 'ie inderdaad nog geen ID, dus ergens klopt de foutmelding wel. Duidelijk is echter anders :P
Makes sense. Gaan we dat zo eens proberen.


code:
1
2
3
4
5
6
7
mysql> describe auth_user;
+--------------+--------------+------+-----+---------+----------------+
| Field        | Type         | Null | Key | Default | Extra          |
+--------------+--------------+------+-----+---------+----------------+
| id           | int(11)      | NO   | PRI | NULL    | auto_increment |

11 rows in set (0.00 sec)
Mwa, volgens mij redelijk auto_increment'end.

Maar idd dit werkt nu:

Python:
1
2
3
4
5
6
7
user_boudewijn = User.objects.create_superuser(username="boudewijn", password= "123", email="boudewijn@blah.nl")
user_boudewijn.save()
admin_boudewijn = add_JabberAdmin(user=user_boudewijn,name="boudewijnAdmin", group=lalalallalal)

def add_JabberAdmin(user,name,group):
    obj = JabberAdmin.objects.get_or_create(user=user,name=name,group=group)[0]
    return obj



Dank heren!
Pagina: 1