Double POSTy

22 views
Skip to first unread message

Vladimír Macek

unread,
Sep 17, 2016, 5:55:34 PM9/17/16
to djan...@googlegroups.com
Zdar,

jak řešíte nepříjemné dvojité POSTy, kdy uživatel poklepe na submit?

V logu je něco takového:

2016-09-17T18:34:35+02:00 "POST /accounts/signup/ HTTP/1.1" 499 ...
2016-09-17T18:34:36+02:00 "POST /accounts/signup/ HTTP/1.1" 500 ...

Tj. na první POST Django stihne uživatele zaregistrovat, ale nginx zjistí,
že browser mezitím zavřel spojení (499) a čeká na spojení dalším. Tam ovšem
zařve postgres, že uživatel s tímto e-mailem už existuje.

Pořádné webové aplikaci by se podle mě tohle nemělo stát a druhému POSTu by
měla vrátit to samé, co BY vrátila tomu prvnímu.

Napadá mě nějaké řešení, ale abych mail neprotahoval, nejdřív bych se rád
zeptal, jestli nevíte o nějakém standardizovaném, třeba přímo v Djangu,
kterého jsem si nevšiml.

Řešíte to? Víte o dalších hazardech?

Děkuju, :-)

--
: Vladimir Macek : http://macek.sandbox.cz : +420 608 978 164
: UNIX && Dev || Training : Python, Django : PGP key 97330EBD

Tomáš Ehrlich

unread,
Sep 17, 2016, 6:04:04 PM9/17/16
to djan...@googlegroups.com

> 17. 9. 2016 v 23:55, Vladimír Macek <ma...@sandbox.cz>:
>
> Zdar,
>
> jak řešíte nepříjemné dvojité POSTy, kdy uživatel poklepe na submit?

Jestli je problém, je uživatel double clickne na submit, tak řešit přes JS? OnClick -> Disable?

> V logu je něco takového:
>
> 2016-09-17T18:34:35+02:00 "POST /accounts/signup/ HTTP/1.1" 499 ...
> 2016-09-17T18:34:36+02:00 "POST /accounts/signup/ HTTP/1.1" 500 ...
>
> Tj. na první POST Django stihne uživatele zaregistrovat, ale nginx zjistí,
> že browser mezitím zavřel spojení (499) a čeká na spojení dalším. Tam ovšem
> zařve postgres, že uživatel s tímto e-mailem už existuje.
>
> Pořádné webové aplikaci by se podle mě tohle nemělo stát a druhému POSTu by
> měla vrátit to samé, co BY vrátila tomu prvnímu.

To se mi moc nezdá. Musel bys nějak identifikovat, že oba requesty přišly od stejného uživatele.
Dokončí Django první request, když nginx vrátí 499? Nebo ho nginx “utne”?

> Napadá mě nějaké řešení, ale abych mail neprotahoval, nejdřív bych se rád
> zeptal, jestli nevíte o nějakém standardizovaném, třeba přímo v Djangu,
> kterého jsem si nevšiml.
>
> Řešíte to? Víte o dalších hazardech?

Řeším to většinou přes JS. Uživatel má krásný vizuální feedback přímo pod kurzorem,
že se něco děje (Název tlačítka se změní z “Registrovat” na “Probíhá registrace”, třeba)

Double post při refreshi se řeší redirectem, ale to není tento případ.


Tom

>
> Děkuju, :-)
>
> --
> : Vladimir Macek : http://macek.sandbox.cz : +420 608 978 164
> : UNIX && Dev || Training : Python, Django : PGP key 97330EBD
>
> --
> --
> E-mailová skupina djan...@googlegroups.com
> Správa: http://groups.google.cz/group/django-cs
> ---
> Tuto zprávu jste obdrželi, protože jste přihlášeni k odběru skupiny django-cs ve Skupinách Google.
> Chcete-li zrušit odběr skupiny a přestat dostávat e-maily ze skupiny, zašlete e-mail na adresu django-cs+...@googlegroups.com.
> Chcete-li zobrazit tuto diskusi na webu, navštivte https://groups.google.com/d/msgid/django-cs/3570829d-7333-48fa-3bad-8e3f73fe677e%40sandbox.cz.
> Další možnosti najdete na adrese https://groups.google.com/d/optout.

signature.asc

Vladimír Macek

unread,
Sep 18, 2016, 6:19:18 AM9/18/16
to djan...@googlegroups.com
On 18.9.2016 00:04, Tomáš Ehrlich wrote:
>> 17. 9. 2016 v 23:55, Vladimír Macek <ma...@sandbox.cz>:
>>
>> Zdar,
>>
>> jak řešíte nepříjemné dvojité POSTy, kdy uživatel poklepe na submit?
> Jestli je problém, je uživatel double clickne na submit, tak řešit přes JS? OnClick -> Disable?

Ano, to bude první fáze řešení a určitě to zlepší UX, jak píšeš níže. Ale
nejde na to spoléhat.


>> V logu je něco takového:
>>
>> 2016-09-17T18:34:35+02:00 "POST /accounts/signup/ HTTP/1.1" 499 ...
>> 2016-09-17T18:34:36+02:00 "POST /accounts/signup/ HTTP/1.1" 500 ...
>>
>> Tj. na první POST Django stihne uživatele zaregistrovat, ale nginx zjistí,
>> že browser mezitím zavřel spojení (499) a čeká na spojení dalším. Tam ovšem
>> zařve postgres, že uživatel s tímto e-mailem už existuje.
>>
>> Pořádné webové aplikaci by se podle mě tohle nemělo stát a druhému POSTu by
>> měla vrátit to samé, co BY vrátila tomu prvnímu.
> To se mi moc nezdá. Musel bys nějak identifikovat, že oba requesty přišly od stejného uživatele.

Ano, řešitelné. Zatím uvažuju o middleware, který po každém commitu POSTu
uloží do cache HttpResponse klíčovanou hashem request.POST dat + IP adresy
+ csrfcookie s timeoutem 2 sec. Na začátku POSTu by se do cache mrklo a
kdyžtak response hned vrátí.


> Dokončí Django první request, když nginx vrátí 499? Nebo ho nginx “utne”?

No to zatím jsem nevyřešil, proč druhý request skončí s IntegrityError a
nikoli se reg. formem s chybou "Uživatel už existuje".

Díval jsem se do logu postgresu a celý signup skrz django-allauth proběhne
v transakci. To je druhá záhada, když `ATOMIC_REQUESTS=False` a neobjevil
jsem v té cestě `transaction.atomic`. Django nějak samo začne transakci
před `SELECT` zjišťujícím, jestli už e-mail existuje a skončí jí až s
vytvořením po vytvoření všech objektů vázaných na uživatele, jak to máme v
aplikaci. Přitom normálně requesty do transakce nebalí.

Třeba někdo víte z hlavy.

Dík,

V.

Tomáš Ehrlich

unread,
Sep 18, 2016, 6:29:52 AM9/18/16
to djan...@googlegroups.com

> 18. 9. 2016 v 12:19, Vladimír Macek <ma...@sandbox.cz>:
>
> On 18.9.2016 00:04, Tomáš Ehrlich wrote:
>>> 17. 9. 2016 v 23:55, Vladimír Macek <ma...@sandbox.cz>:
>>>
>>> Zdar,
>>>
>>> jak řešíte nepříjemné dvojité POSTy, kdy uživatel poklepe na submit?
>> Jestli je problém, je uživatel double clickne na submit, tak řešit přes JS? OnClick -> Disable?
>
> Ano, to bude první fáze řešení a určitě to zlepší UX, jak píšeš níže. Ale
> nejde na to spoléhat.

Spoléhat na to nejde, ale pokud to vyřeší 99,9% případů, tak bych to tak nechal. Museli by
se sejít dvě události zároveň, aby to nefungovalo:

1) Javascript nepojede (stránka ještě není načtená nebo javascript vypnutý globálně),
2) Uživatel double clickne

>
>
>>> V logu je něco takového:
>>>
>>> 2016-09-17T18:34:35+02:00 "POST /accounts/signup/ HTTP/1.1" 499 ...
>>> 2016-09-17T18:34:36+02:00 "POST /accounts/signup/ HTTP/1.1" 500 ...
>>>
>>> Tj. na první POST Django stihne uživatele zaregistrovat, ale nginx zjistí,
>>> že browser mezitím zavřel spojení (499) a čeká na spojení dalším. Tam ovšem
>>> zařve postgres, že uživatel s tímto e-mailem už existuje.
>>>
>>> Pořádné webové aplikaci by se podle mě tohle nemělo stát a druhému POSTu by
>>> měla vrátit to samé, co BY vrátila tomu prvnímu.
>> To se mi moc nezdá. Musel bys nějak identifikovat, že oba requesty přišly od stejného uživatele.
>
> Ano, řešitelné. Zatím uvažuju o middleware, který po každém commitu POSTu
> uloží do cache HttpResponse klíčovanou hashem request.POST dat + IP adresy
> + csrfcookie s timeoutem 2 sec. Na začátku POSTu by se do cache mrklo a
> kdyžtak response hned vrátí.

To mi právě vrtá hlavou. Pokud je to takový do očí bijící problém, proč ještě není vyřešený?
Django žije víc jak 10 let, to už si někdo musel všimnou…

>
>
>> Dokončí Django první request, když nginx vrátí 499? Nebo ho nginx “utne”?
>
> No to zatím jsem nevyřešil, proč druhý request skončí s IntegrityError a
> nikoli se reg. formem s chybou "Uživatel už existuje”.

Aha! Tak to je určitě podezřelé. Pamatuju si, že nám občas registrace taky vracela
IntegrityError. Bylo to spojení s přihlašováním přes facebook a stávalo se to
náhodně a jen občas. Nenašli jsme příčinu :(

>
> Díval jsem se do logu postgresu a celý signup skrz django-allauth proběhne
> v transakci. To je druhá záhada, když `ATOMIC_REQUESTS=False` a neobjevil
> jsem v té cestě `transaction.atomic`. Django nějak samo začne transakci
> před `SELECT` zjišťujícím, jestli už e-mail existuje a skončí jí až s
> vytvořením po vytvoření všech objektů vázaných na uživatele, jak to máme v
> aplikaci. Přitom normálně requesty do transakce nebalí.

To záleží na verzi. Dřív django balilo do transakce celé requesty, pak se to změnilo,
všechny operace jsou atomické a pokud chceš transakci, musíš si ji vynutit.
Nebo použiješ middleware, který celý request obalí do transakce a vrátíš tak
původní chování Djanga. Verzi si bohužel nepamatuju.

Co se stane, když nginx vrátí 499 a 500? Je uživatel v DB? Nebo tam není vůbec?

>
> Třeba někdo víte z hlavy.
>
> Dík,
>
> V.
>
> --
> --
> E-mailová skupina djan...@googlegroups.com
> Správa: http://groups.google.cz/group/django-cs
> ---
> Tuto zprávu jste obdrželi, protože jste přihlášeni k odběru skupiny django-cs ve Skupinách Google.
> Chcete-li zrušit odběr skupiny a přestat dostávat e-maily ze skupiny, zašlete e-mail na adresu django-cs+...@googlegroups.com.
> Chcete-li zobrazit tuto diskusi na webu, navštivte https://groups.google.com/d/msgid/django-cs/6bfbd599-50ae-7540-6aef-c0e7e194902b%40sandbox.cz.
signature.asc

Vladimír Macek

unread,
Sep 18, 2016, 6:58:07 AM9/18/16
to djan...@googlegroups.com
On 18.9.2016 12:29, Tomáš Ehrlich wrote:
>>> Jestli je problém, je uživatel double clickne na submit, tak řešit přes JS? OnClick -> Disable?
>> Ano, to bude první fáze řešení a určitě to zlepší UX, jak píšeš níže. Ale
>> nejde na to spoléhat.
> Spoléhat na to nejde, ale pokud to vyřeší 99,9% případů, tak bych to tak nechal. Museli by
> se sejít dvě události zároveň, aby to nefungovalo:
>
> 1) Javascript nepojede (stránka ještě není načtená nebo javascript vypnutý globálně),
> 2) Uživatel double clickne

Jj, vidím to stejně. Přesto je podle mě dobré chránit i backend.


>>> ...
>> Ano, řešitelné. Zatím uvažuju o middleware, který po každém commitu POSTu
>> uloží do cache HttpResponse klíčovanou hashem request.POST dat + IP adresy
>> + csrfcookie s timeoutem 2 sec. Na začátku POSTu by se do cache mrklo a
>> kdyžtak response hned vrátí.
> To mi právě vrtá hlavou. Pokud je to takový do očí bijící problém, proč ještě není vyřešený?
> Django žije víc jak 10 let, to už si někdo musel všimnou…

Vidím i tohle stejně, že by v Djangu měla být pro to podpora. Proto jsem se
na začátku ptal, jestli o ní někdo neví. Django mám prolezlé hodně a hledal
jsem i před prvním postem...


>> No to zatím jsem nevyřešil, proč druhý request skončí s IntegrityError a
>> nikoli se reg. formem s chybou "Uživatel už existuje”.
> Aha! Tak to je určitě podezřelé. Pamatuju si, že nám občas registrace taky vracela
> IntegrityError. Bylo to spojení s přihlašováním přes facebook a stávalo se to
> náhodně a jen občas. Nenašli jsme příčinu :(

Aha, chtěl jsem se mrknout, jestli ta paní nešla k nám přes FB, ale ne. Je
to přímý signup.

Teď jsem to zkusil v Chrome jako ona a v pohodě jsem problém zreplikoval.

Máme Django 1.9 a uživatel po té dvojici requestů 499+500 v databázi JE
včetně navázaného objektu EmailAddress (vyrábí django-allauth).

Mám podezření, jestli to nebude souviset s transaction isolation level. Ale
tomu moc nerozumím.

Ateďbaboraď. :-)

Tome, děkuju za dosavadní.

V.

Vladimír Macek

unread,
Sep 18, 2016, 7:29:53 AM9/18/16
to djan...@googlegroups.com
Tak ještě zjištění.

Na runserveru doma problém replikuju taky.

Zestručněný log postgresu přikládám. Ilustruje, jak si dvě transakce ze
dvou různých PIDů postgresu vlezou do zelí...

V.

double-click.txt

Petr Messner

unread,
Sep 18, 2016, 7:31:11 AM9/18/16
to djan...@googlegroups.com
Ahoj,

Dne 18. září 2016 12:58 Vladimír Macek <ma...@sandbox.cz> napsal(a):

On 18.9.2016 12:29, Tomáš Ehrlich wrote:
>>> Jestli je problém, je uživatel double clickne na submit, tak řešit přes JS? OnClick -> Disable?
>> Ano, to bude první fáze řešení a určitě to zlepší UX, jak píšeš níže. Ale
>> nejde na to spoléhat.
> Spoléhat na to nejde, ale pokud to vyřeší 99,9% případů, tak bych to tak nechal. Museli by
> se sejít dvě události zároveň, aby to nefungovalo:
>
> 1) Javascript nepojede (stránka ještě není načtená nebo javascript vypnutý globálně),
> 2) Uživatel double clickne


To, že by ještě nejel Javascript, se dá vyřešit tím, že to tlačítko bude ze začátku (ve statickém HTML) neaktivní a teprve Javascript ho zprovozní.
 
Jj, vidím to stejně. Přesto je podle mě dobré chránit i backend.


Backend je třeba chránit před útoky - zkoušení náhodných id, operací, které by frontend sám od sebe nevyvolal, ale backend je podporuje... Chránit backend před tím, co se dá ošetřit ve frontendu, ake zároveň v případě neošetření frontendem jde jen o kosmetický a ne o bezpečnostní problém, je podle mě zbytečné.

Jinak tohle má ještě jiné řešení, které bude pro tento případ asi moc hardcore, ale zmiňuju ho aspoň pro úplnost - klient (frontend, tj. javascript) si pro každou operaci vygeneruje nějaké operation_id (UUID v1 nebo v4 nebo nějakou obdobu vhodnou pro JS), které identifikuje ten konkrétní pokus o registraci uživatele, nebo o změnu stavu nějaké entity apod. Backend pak pozná, jestli jde o duplicitní požadavek, umí se s tím vypořádat a vrátí sémanticky relevantní odpověď. Např. "uživatel úspěšně zaregistrován", i když už ve skutečnosti byl zaregistrovaný právě tím předchozím požadavkem se stejným operation_id. Vlastně jde o rozšíření té myšlenky s response keší. Cílem je, aby i volání, která mění stav, byla idempotentní. Využití to má ale spíš v microservices architektuře, kde je potom větší prostor a tolerance pro dočasné chyby nebo nedostupnosti (např. se něco restartuje, databázový cluster se vzpamatovává z výpadku mastera atd.).

PM

Petr Messner

unread,
Sep 18, 2016, 7:32:53 AM9/18/16
to djan...@googlegroups.com
Jakou máš nastavenou izolaci transakcí?

PM

Dne 18. září 2016 13:29 Vladimír Macek <ma...@sandbox.cz> napsal(a):

V.

--
--
E-mailová skupina djan...@googlegroups.com
Správa: http://groups.google.cz/group/django-cs
---
Tuto zprávu jste obdrželi, protože jste přihlášeni k odběru skupiny django-cs ve Skupinách Google.
Chcete-li zrušit odběr skupiny a přestat dostávat e-maily ze skupiny, zašlete e-mail na adresu django-cs+unsubscribe@googlegroups.com.
Chcete-li zobrazit tuto diskusi na webu, navštivte https://groups.google.com/d/msgid/django-cs/cadf2717-ea07-218d-6ffc-a7683391963c%40sandbox.cz.

Vladimír Macek

unread,
Sep 18, 2016, 7:48:05 AM9/18/16
to djan...@googlegroups.com
No default, ale teď jsem doma řekl Djangu, že chci serializable a vybíhá na
mě stejný IntegrityError při double POST pro signup uživatele...

Dík,

V.


On 18.9.2016 13:32, Petr Messner wrote:
> Jakou máš nastavenou izolaci transakcí?
>
> PM
>
> Dne 18. září 2016 13:29 Vladimír Macek <ma...@sandbox.cz
> <mailto:ma...@sandbox.cz>> napsal(a):

Vladimír Macek

unread,
Sep 18, 2016, 7:53:22 AM9/18/16
to djan...@googlegroups.com
On 18.9.2016 13:30, Petr Messner wrote:
> Ahoj,
>
> Dne 18. září 2016 12:58 Vladimír Macek <ma...@sandbox.cz
> <mailto:ma...@sandbox.cz>> napsal(a):
>
> On 18.9.2016 12:29, Tomáš Ehrlich wrote:
> >>> Jestli je problém, je uživatel double clickne na submit, tak
> řešit přes JS? OnClick -> Disable?
> >> Ano, to bude první fáze řešení a určitě to zlepší UX, jak píšeš
> níže. Ale
> >> nejde na to spoléhat.
> > Spoléhat na to nejde, ale pokud to vyřeší 99,9% případů, tak bych
> to tak nechal. Museli by
> > se sejít dvě události zároveň, aby to nefungovalo:
> >
> > 1) Javascript nepojede (stránka ještě není načtená nebo javascript
> vypnutý globálně),
> > 2) Uživatel double clickne
>
>
> To, že by ještě nejel Javascript, se dá vyřešit tím, že to tlačítko bude
> ze začátku (ve statickém HTML) neaktivní a teprve Javascript ho zprovozní.

My považujeme JS za nepovinný.


>
>
> Jj, vidím to stejně. Přesto je podle mě dobré chránit i backend.
>
>
> Backend je třeba chránit před útoky - zkoušení náhodných id, operací,
> které by frontend sám od sebe nevyvolal, ale backend je podporuje...
> Chránit backend před tím, co se dá ošetřit ve frontendu, ake zároveň v
> případě neošetření frontendem jde jen o kosmetický a ne o bezpečnostní
> problém, je podle mě zbytečné.
>
> Jinak tohle má ještě jiné řešení, které bude pro tento případ asi moc
> hardcore, ale zmiňuju ho aspoň pro úplnost - klient (frontend, tj.
> javascript) si pro každou operaci vygeneruje nějaké operation_id (UUID v1
> nebo v4 nebo nějakou obdobu vhodnou pro JS), které identifikuje ten
> konkrétní pokus o registraci uživatele, nebo o změnu stavu nějaké entity
> apod. Backend pak pozná, jestli jde o duplicitní požadavek, umí se s tím
> vypořádat a vrátí sémanticky relevantní odpověď. Např. "uživatel úspěšně
> zaregistrován", i když už ve skutečnosti byl zaregistrovaný právě tím
> předchozím požadavkem se stejným operation_id. Vlastně jde o rozšíření té
> myšlenky s response keší. Cílem je, aby i volání, která mění stav, byla
> idempotentní. Využití to má ale spíš v microservices architektuře, kde je
> potom větší prostor a tolerance pro dočasné chyby nebo nedostupnosti
> (např. se něco restartuje, databázový cluster se vzpamatovává z výpadku
> mastera atd.).
>

Ano, je to rozšíření té myšlenky s response keší. Každopádně děkuju.

Mám rád jednoduché věci a zde uvažuju o řešení Kladivo: Kombinaci disable
submitnu při prvním kliknutí pomocí JS a globálního locku na všech POSTech
pomocí middleware. Lock by byl klíčovaný csrftokenem, pokud by existoval, a
uměl by vytikat, aby netrval příp. deadlock.

Tomu zlomku non-JS uživatelů by tedy pak vyběhla chyba validace, že user už
existuje. Řekl bych přijatelná collateral damage.

V.

Tomáš Ehrlich

unread,
Sep 18, 2016, 8:29:51 AM9/18/16
to djan...@googlegroups.com
Vrtá mi to hlavou. Pokud by byl opravdu problém opakovaná registrace, tak vyskočí ValidationError a ne IntegrityError...


Chápu to dobře, že AllAuth poskytuje registraci přes oauth i přímo?

Zkusil jsem se mrknout a pár issue tam je:

Jsou tam případy přihlášení jak přes oauth, tak normálně email:heslo. Je tam ale spousta dalších
okolností, jestli třeba používáš custom user model, atp, viz:


Tom


18. 9. 2016 v 13:29, Vladimír Macek <ma...@sandbox.cz>:

--
--
E-mailová skupina djan...@googlegroups.com
Správa: http://groups.google.cz/group/django-cs
---
Tuto zprávu jste obdrželi, protože jste přihlášeni k odběru skupiny django-cs ve Skupinách Google.
Chcete-li zrušit odběr skupiny a přestat dostávat e-maily ze skupiny, zašlete e-mail na adresu django-cs+...@googlegroups.com.

Další možnosti najdete na adrese https://groups.google.com/d/optout.
<double-click.txt>

signature.asc

Vladimír Macek

unread,
Sep 19, 2016, 4:32:29 AM9/19/16
to djan...@googlegroups.com
Dík za interes. :-)

Taky to nevím. Tuším, že jde o tu kolizi transakcí s nedostatečnou izolací.
Nicméně i při nejvyšším stupni postgresu "serializable" ten IntegrityError
vyskočí. Tam by měla být myslím chyba jiná, ale je možné, že se postgres
spokojí s "nějakou chybou".

Samozřejmě je pro mě primární konzistence db.

Nevím toho dost a nemám už možnost tomu věnovat víc času. Už takhle ho bylo
dost. :-/

Nenapadá-li někoho nic dalšího, udělám zmíněné kladivo.

Děkuju,

V.


On 18.9.2016 14:29, Tomáš Ehrlich wrote:
> Vrtá mi to hlavou. Pokud by byl opravdu problém opakovaná registrace, tak
> vyskočí ValidationError a ne IntegrityError...
>
>
> Chápu to dobře, že AllAuth poskytuje registraci přes oauth i přímo?
>
> Zkusil jsem se mrknout a pár issue tam je:
> https://github.com/pennersr/django-allauth/issues?utf8=%E2%9C%93&q=IntegrityError
>
> Jsou tam případy přihlášení jak přes oauth, tak normálně email:heslo. Je
> tam ale spousta dalších
> okolností, jestli třeba používáš custom user model, atp, viz:
> http://stackoverflow.com/questions/24536774/django-allauth-custom-user-generates-integrityerror-at-accounts-signup-custo/24622274#24622274
>
>
> Tom
>
>
>> 18. 9. 2016 v 13:29, Vladimír Macek <ma...@sandbox.cz
>> <mailto:ma...@sandbox.cz>>:
>>
>> Tak ještě zjištění.
>>
>> Na runserveru doma problém replikuju taky.
>>
>> Zestručněný log postgresu přikládám. Ilustruje, jak si dvě transakce ze
>> dvou různých PIDů postgresu vlezou do zelí...
>>
>> V.
>>
>> --
>> --
>> E-mailová skupina djan...@googlegroups.com
>> <mailto:djan...@googlegroups.com>
>> Správa: http://groups.google.cz/group/django-cs
>> ---
>> Tuto zprávu jste obdrželi, protože jste přihlášeni k odběru skupiny
>> django-cs ve Skupinách Google.
>> Chcete-li zrušit odběr skupiny a přestat dostávat e-maily ze skupiny,
>> zašlete e-mail na adresu django-cs+...@googlegroups.com
>> <mailto:django-cs+...@googlegroups.com>.
>> Chcete-li zobrazit tuto diskusi na webu, navštivte
>> https://groups.google.com/d/msgid/django-cs/cadf2717-ea07-218d-6ffc-a7683391963c%40sandbox.cz.
>> Další možnosti najdete na adrese https://groups.google.com/d/optout.
>> <double-click.txt>
>
> --
> --
> E-mailová skupina djan...@googlegroups.com
> Správa: http://groups.google.cz/group/django-cs
> ---
> Tuto zprávu jste obdrželi, protože jste přihlášeni k odběru skupiny
> „django-cs“ ve Skupinách Google.
> Chcete-li zrušit odběr skupiny a přestat dostávat e-maily ze skupiny,
> zašlete e-mail na adresu django-cs+...@googlegroups.com
> <mailto:django-cs+...@googlegroups.com>.
> Chcete-li tuto diskusi zobrazit na webu, navštivte
> https://groups.google.com/d/msgid/django-cs/438E5223-C713-472E-917A-B66DBE8FE436%40gmail.com
> <https://groups.google.com/d/msgid/django-cs/438E5223-C713-472E-917A-B66DBE8FE436%40gmail.com?utm_medium=email&utm_source=footer>.
> Další možnosti najdete na https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages